现在我们来快速搭建一个开箱即用的小程序、H5开发框架 (vue3 ts)
一、我们先来快速预览一下我们的框架结构
二、使用以下命令快速创建项目
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下创建utils 、config文件,(注意:我们把上述的 api 文件移入utils)
1、首先在我们创建的 config 文件下面创建 app.ts 文件,为方便复制代码如下:
export const APP_NAME = '开箱及用小程序、H5'export const IMAGE_URL = 'xxxxx' // 静态资源的地址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、接下来创建 requestClass.ts 文件,代码如下
const config = Symbol('config')const isCompleteURL = Symbol('isCompleteURL')const requestBefore = Symbol('requestBefore')const requestAfter = Symbol('requestAfter')class requestClass { // 默认配置 [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] } // 修改默认配置的一个方法,可以修改请求地址,请求方式等等.. setConfig(func: Fn) { this[config] = func(this[config]) }}export default requestClass
3、下面创建 request.ts,代码如下
import requestClass from './requestClass'import { HEADER, HEADERPARAMS, TOKENNAME, HTTP_REQUEST_URL } from '@/config/app'import qs from 'qs'const Request = new requestClass()// 请求拦截器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})// 响应拦截器Request.interceptors.response((response: any) => { const token = uni.getStorageSync('userDate').token // if (response.data.code === 403) { // uni.showToast({ // title: token ? '请重新登录' : '请先登录', // icon: 'none', // duration: 2000, // }) // uni.removeStorageSync('token') // uni.removeStorageSync('userInfo') // } return response})// 设置默认配置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、最后我们创建我们的 api.ts, 代码如下
import request from '@/utils/request'const options = { header: { 'content-type': 'application/x-www-form-urlencoded'}, token: uni.getStorageSync('userDate').token}/** * @method 测试接口 */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下创建store文件(在store 下创建 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 下创建app文件夹(在 app 文件夹创建以下文件夹)
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 ( 小程序默认顶部状态栏高度处理,全局变量配置等)
import { createSSRApp } from 'vue'import App from './App.vue'import { store } from './store'export function createApp() { const app = createSSRApp(App) //获取顶部状态栏高度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 //获取导航高度 app.config.globalProperties.$navHeight = e.statusBarHeight * (750 / e.windowWidth) 91 app.config.globalProperties.$SystemInfo = e }, }) app.use(store) return { app, }}
2、小程序分包(pages.json) 例如(根据需要删减,但保持结构不变)
{ "pages": [ //pages数组中第一项表示应用启动页,参考: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": "首页", "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、接口调用
//例如在页面引入 三 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调用
注意:vue3调用状态管理和Vue2不同(三步走)
//引入 useStoreimport { useStore } from 'vuex'//调用const store = useStore()//通过 store 调用 actions 我们的用户登录方法store.dispatch(AppActionTypes.ACTION_LOGIN, xxx)
最后我们看一下vue3 setup() 方法,我们可能看到两种不同的写法
//个人推荐组件封装使用这种<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' //调用 const store = useStore() //通过 store 调用 actions 我们的用户登录方法 store.dispatch(AppActionTypes.ACTION_LOGIN, xxx)</script>
接下来我们就可以快速开始我们的开发了
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。