现在我们来快速搭建一个开箱即用的小程序、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>
接下来我们就可以快速开始我们的开发了
本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 sumchina520@foxmail.com 举报,一经查实,本站将立刻删除。
如若转载,请注明出处:https://www.sumedu.com/faq/164007.html
如若转载,请注明出处:https://www.sumedu.com/faq/164007.html