現(xiàn)在我們來快速搭建一個(gè)開箱即用的小程序、H5開發(fā)框架 (vue3 ts)
一、我們先來快速預(yù)覽一下我們的框架結(jié)構(gòu)
二、使用以下命令快速創(chuàng)建項(xiàng)目
npx degit dcloudio/uni-preset-vue#vite-ts my-vue3-project //或者直接下載https://gitee.com/dcloud/uni-preset-vue/repository/archive/vite-ts.zip
三、首先處理全局配置和axiso封裝
在src下創(chuàng)建utils 、config文件,(注意:我們把上述的 api 文件移入utils)
1、首先在我們創(chuàng)建的 config 文件下面創(chuàng)建 app.ts 文件,為方便復(fù)制代碼如下:
export const APP_NAME = '開箱及用小程序、H5'export const IMAGE_URL = 'xxxxx' // 靜態(tài)資源的地址export const HTTP_Request_URL = 'xxxxx'export const header = { 'content-type': 'application/json',}export const HEADERPARAMS = { 'content-type': 'application/x-www-form-urlencoded',}export const TOKENNAME = 'Authorization'
2、接下來創(chuàng)建 requestClass.ts 文件,代碼如下
const config = Symbol('config')const isCompleteURL = Symbol('isCompleteURL')const requestBefore = Symbol('requestBefore')const requestAfter = Symbol('requestAfter')class requestClass { // 默認(rèn)配置 [config]: { baseURL?: string } & UniApp.RequestOptions = { baseURL: '', url: '', HEADER: { 'content-type': 'application/x-www-form-urlencoded', }, method: 'GET', timeout: 3000, dataType: 'json', responseType: 'text' } // 攔截器 interceptors = { request: (func: Fn) => { if (func) { requestClass[requestBefore] = func } else { requestClass[requestBefore] = (request) => request } }, response: (func: Fn) => { if (func) { requestClass[requestAfter] = func } else { requestClass[requestAfter] = (response) => response } }, } static [requestBefore](config: UniApp.RequestOptions) { Return config } static [requestAfter](response: any) { return response } static [isCompleteURL](url: string) { return /(http|https)://([w.] /?)S*/.test(url) } request(options: UniApp.RequestOptions & { baseURL?: string }) { options.baseURL = options.baseURL || this[config].baseURL options.dataType = options.dataType || this[config].dataType options.url = requestClass[isCompleteURL](options.url) ? options.url : (options.baseURL options.url) options.data = options.data options.header = { ...options.header, ...this[config].header } options.method = options.method || this[config].method options = { ...options, ...requestClass[requestBefore](options) } return new Promise((resolve, reject) => { options.success = function (res) { resolve(requestClass[requestAfter](res)) } options.fail = function (err) { reject(requestClass[requestAfter](err)) } uni.request(options) let obj: any = {} obj[request.url] = uni.request(options) abortRequest() { for (const key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { const element = obj[key]; element.abort() } } } }) } get(url: string, data: any = {}, options: Recordable = {}) { return this.request({ ...options, url, data, method: 'GET' }) } post(url: string, data: any = {}, options: Recordable = {}) { return this.request({ ...options, url, data, method: 'POST' }) } put(url: string, data: any = {}, options: Recordable = {}) { return this.request({ ...options, url, data, method: 'PUT' }) } delete(url: string, data: any = {}, options: Recordable = {}) { return this.request({ ...options, url, data, method: 'DELETE' }) } getConfig() { return this[config] } // 修改默認(rèn)配置的一個(gè)方法,可以修改請(qǐng)求地址,請(qǐng)求方式等等.. setConfig(func: Fn) { this[config] = func(this[config]) }}export default requestClass
3、下面創(chuàng)建 request.ts,代碼如下
import requestClass from './requestClass'import { HEADER, HEADERPARAMS, TOKENNAME, HTTP_REQUEST_URL } from '@/config/app'import qs from 'qs'const Request = new requestClass()// 請(qǐng)求攔截器Request.interceptors.request((request: any) => { if (request.header.contentType) { request.header['content-type'] = request.header.contentType delete request.header.contentType } if (request.method === 'GET') { request.data = qs.stringify(request.data) request.url = request.url '?' request.data } return request})// 響應(yīng)攔截器Request.interceptors.response((response: any) => { const token = uni.getStorageSync('userDate').token // if (response.data.code === 403) { // uni.showToast({ // title: token ? '請(qǐng)重新登錄' : '請(qǐng)先登錄', // icon: 'none', // duration: 2000, // }) // uni.removeStorageSync('token') // uni.removeStorageSync('userInfo') // } return response})// 設(shè)置默認(rèn)配置Request.setConfig((config: any) => { config.baseURL = HTTP_REQUEST_URL if (uni.getStorageSync('userDate').token) { config.header['Authorization'] = 'Bearer ' uni.getStorageSync('token') config.header['token'] = uni.getStorageSync('userDate').token } return config})export default Request
4、最后我們創(chuàng)建我們的 api.ts, 代碼如下
import request from '@/utils/request'const options = { header: { 'content-type': 'application/x-www-form-urlencoded'}, token: uni.getStorageSync('userDate').token}/** * @method 測(cè)試接口 */export function testGet(data :any) { return request.get('/api/kecheng/getchargekechenginfo', data)}export function testPost(data :any) { return request.post('/api/kecheng/getlistsuddenstudy', data, options)}export function testPut(data :any) { return request.post('/testPut', data)}export function testDelete(data :any) { return request.delete('/testDelete', data)}
四、處理我們的vuex,在src下創(chuàng)建store文件(在store 下創(chuàng)建 index.ts 、gettres.ts 和modules文件夾)
1、index.ts,代碼如下
import { InjectionKey} from 'vue'import { createStore } from 'vuex'import { store as app, Appstate, AppStore } from '@/store/modules/app'import getters from './getters'export const key: InjectionKey<Store> = Symbol()export interface RootState { app: AppState}export type Store = AppStore<Pick<RootState, 'app'>>export const store = createStore<RootState>({ modules: { app }, getters})export function useStore(): Store { return store as Store}
2、gettres.ts,代碼如下
import { RootState } from '@/store'export default { token: (state: RootState) => state.app.token,}
3、在modules 下創(chuàng)建app文件夾(在 app 文件夾創(chuàng)建以下文件夾)
1、index.ts,代碼如下:
import { Store as VuexStore, CommitOptions, DispatchOptions, Module } from 'vuex'import { RootState } from '@/store'import { state } from './state'import { actions, Actions } from './actions'import { mutations, Mutations } from './mutations'import type { AppState } from './state'export { AppState }export type AppStore<S = AppState> = Omit<VuexStore<S>, 'getters' | 'commit' | 'dispatch'> & { commit<K extends keyof Mutations, P extends Parameters<Mutations[K]>[1]>( key: K, payload: P, options?: CommitOptions ): ReturnType<Mutations[K]>} & { dispatch<K extends keyof Actions>( key: K, payload: Parameters<Actions[K]>[1], options?: DispatchOptions ): ReturnType<Actions[K]>}export const store: Module<AppState, RootState> = { state, actions, mutations,}
2、state.ts,代碼如下:
import {reactive} from 'vue'export interface AppState { token: string, userData: object}export const state: AppState = reactive({ token: '', userData:[]})
3、mutations.ts,代碼如下:
import { MutationTree } from 'vuex'import { AppState } from './state'import { AppMutationTypes } from './mutation-types'export type Mutations<S = AppState> = { // [AppMutationTypes.SET_TOKEN](state: S, token: string): void}export const mutations: MutationTree<AppState> & Mutations = { [AppMutationTypes.SET_USER_MSG](state: AppState, userData: object) { state.userData = userData }}
4、mutation-types.ts,代碼如下:
export enum AppMutationTypes { SET_USER_MSG = 'SET_USER_MSG', //SET_TOKEN = 'SET_TOKEN',}
5、actions.ts,代碼如下:
import { ActionTree, ActionContext } from 'vuex'import { RootState } from '@/store'import { AppState } from './state'import { Mutations } from './mutations'import { AppActionTypes } from './action-types'import { AppMutationTypes } from './mutation-types'type AugmentedActionContext = { commit<K extends keyof Mutations>(key: K, payload: Parameters<Mutations[K]>[1]): ReturnType<Mutations[K]>} & Omit<ActionContext<AppState, RootState>, 'commit'>export interface Actions { // [AppActionTypes.ACTION_RESET_TOKEN]({ commit }: AugmentedActionContext): void}export const actions: ActionTree<AppState, RootState> & Actions = { [AppActionTypes.ACTION_LOGIN]({ commit }: AugmentedActionContext, userData: object) { commit(AppMutationTypes.SET_USER_MSG, userData) }, // [AppActionTypes.ACTION_RESET_TOKEN]({ commit }: AugmentedActionContext) { // commit(AppMutationTypes.SET_TOKEN, '') // }}
6、action-types.ts,代碼如下:
export enum AppActionTypes { ACTION_LOGIN = 'ACTION_LOGIN', ACTION_RESET_TOKEN = 'ACTION_RESET_TOKEN',}
五、其他配置
1、main.ts ( 小程序默認(rèn)頂部狀態(tài)欄高度處理,全局變量配置等)
import { createSSRApp } from 'vue'import App from './App.vue'import { store } from './store'export function createApp() { const app = createSSRApp(App) //獲取頂部狀態(tài)欄高度uni.getSystemInfo({ success: function (e: any) { // #ifndef MP app.config.globalProperties.$StatusBar = e.statusBarHeight if (e.platform == 'android') { app.config.globalProperties.$CustomBar = e.statusBarHeight 50 } else { app.config.globalProperties.$CustomBar = e.statusBarHeight 45 } // #endif // #ifdef MP-WEIXIN app.config.globalProperties.$StatusBar = e.statusBarHeight const custom = wx.getMenuButtonBoundingClientRect() app.config.globalProperties.$Custom = custom app.config.globalProperties.$CustomBar = custom.bottom custom.top - e.statusBarHeight // #endif //窗口高度 app.config.globalProperties.$windowHeight = e.windowHeight //獲取導(dǎo)航高度 app.config.globalProperties.$navHeight = e.statusBarHeight * (750 / e.windowWidth) 91 app.config.globalProperties.$SystemInfo = e }, }) app.use(store) return { app, }}
2、小程序分包(pages.json) 例如(根據(jù)需要?jiǎng)h減,但保持結(jié)構(gòu)不變)
{ "pages": [ //pages數(shù)組中第一項(xiàng)表示應(yīng)用啟動(dòng)頁(yè),參考:https://uniapp.dcloud.io/collocation/pages { "path": "pages/template/index", "style": { "navigationBarTitleText": "開箱及用小程序、H5", "navigationStyle": "custom" } }, { "path": "pages/template/settled", "style": { "navigationBarTitleText": "開箱及用小程序、H5", "navigationBarTextStyle": "black", "navigationBarBackgroundColor": "#fff", "backgroundColor": "#f7f7f7" } }, { "path": "pages/template/user", "style": { "navigationBarTitleText": "開箱及用小程序、H5", "navigationBarTextStyle": "black", "navigationBarBackgroundColor": "#fff", "backgroundColor": "#f7f7f7" } } ], //分包 "subPackages": [ { "root":"pages/teachers", "pages":[{ "path":"teacherdetail", "style": { "navigationBarTitleText": "開箱及用小程序、H5", "navigationBarTextStyle": "black", "navigationBarBackgroundColor": "#fff", "backgroundColor": "#f7f7f7" } }] },{ "root":"pages/user", "pages":[{ "path":"collection", "style": { "navigationBarTitleText": "開箱及用小程序、H5", "navigationBarTextStyle": "black", "navigationBarBackgroundColor": "#fff", "backgroundColor": "#f7f7f7" } },{ "path":"appointment", "style": { "navigationBarTitleText": "開箱及用小程序、H5", "navigationBarTextStyle": "black", "navigationBarBackgroundColor": "#fff", "backgroundColor": "#f7f7f7" } }] }], "tabBar": { "color": "#7a7e83", "selectedColor": "#1296db", "backgroundColor": "#ffffff", "list": [{ "pagePath": "pages/template/index", "text": "首頁(yè)", "iconPath": "static/img/index.png", "selectedIconPath": "static/img/index_ed.png" }, { "pagePath": "pages/template/settled", "text": "你的", "iconPath": "static/img/learn.png", "selectedIconPath": "static/img/learn_ed.png" }, { "pagePath": "pages/template/user", "text": "我的", "iconPath": "static/img/user.png", "selectedIconPath": "static/img/user_ed.png" }] }, "globalStyle": { "navigationBarTextStyle": "black", "navigationBarTitleText": "uni-app", "navigationBarBackgroundColor": "#F8F8F8", "backgroundColor": "#F8F8F8" }}
2、注意封裝接口的引入和vuex的使用,例如
1、接口調(diào)用
//例如在頁(yè)面引入 三 4 下面的 testPost方法import { testPost} from '@/utils/index'//使用const data = { 'token':'23232321121', 'workType':1}testPost(data).then((res:any):void => { console.log(state.workTypeList )}).catch((err) => {})
2、vuex調(diào)用
注意:vue3調(diào)用狀態(tài)管理和Vue2不同(三步走)
//引入 useStoreimport { useStore } from 'vuex'//調(diào)用const store = useStore()//通過 store 調(diào)用 actions 我們的用戶登錄方法store.dispatch(AppActionTypes.ACTION_LOGIN, xxx)
最后我們看一下vue3 setup() 方法,我們可能看到兩種不同的寫法
//個(gè)人推薦組件封裝使用這種<script lang="ts"> import {defineComponent} from 'vue' export default defineComponent({ name: "xxx", setup(props, context){ } })</script>
<script setup lang="ts"> //引入 useStore import { useStore } from 'vuex' //調(diào)用 const store = useStore() //通過 store 調(diào)用 actions 我們的用戶登錄方法 store.dispatch(AppActionTypes.ACTION_LOGIN, xxx)</script>
接下來我們就可以快速開始我們的開發(fā)了
版權(quán)聲明:本文內(nèi)容由互聯(lián)網(wǎng)用戶自發(fā)貢獻(xiàn),該文觀點(diǎn)僅代表作者本人。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如發(fā)現(xiàn)本站有涉嫌抄襲侵權(quán)/違法違規(guī)的內(nèi)容, 請(qǐng)發(fā)送郵件至 舉報(bào),一經(jīng)查實(shí),本站將立刻刪除。