一个上手即用的通用公众号/小程序/h5/app框架

源码地址:https://github.com/dr34-m/uniapp-demo

框架后期或有更新,请以源码中README.md文档为准

本通用框架基于uniappuView UI 2.0.31,封装了日常开发中最常用的接口请求、数据中心、环境配置等操作,上手即用。

1. 运维

1.1 构建

1
2
3
4
5
6
7
8
# H5 生产
npm run build

# H5 dev
npm run build:dev

# 微信小程序
npm run build:mp-weixin

其他平台构建,例如快应用、支付宝小程序等详见uniapp官方文档

1.2 H5修改前缀

修改/src/manifest.json,例如修改前缀为/h5如下

1
2
3
4
5
6
"h5" : {
"title" : "标题",
"router" : {
"base" : "/h5/"
}
}

更多配置详见uniapp官方文档

1.3 配置文件

配置文件在/src/config/index.js

2. 开发

2.1 启动

1
2
3
4
5
# 安装依赖
npm install

# 运行
npm run serve

其他平台运行,例如快应用、支付宝小程序等详见uniapp官方文档

2.2 说明

2.2.1 配置

通用配置请放在/src/config/index.js中,例如后端地址。

2.2.2 数据中心

数据中心统一管理需要在全局使用的数据,可以临时存储(h5刷新页面、小程序/app退出等操作数据就会丢失)或者持久化存储。

在这里定义和存储的数据是全局动态响应的,这让您无需繁琐地写监听方法。

配置文件在/src/store/index.js,建议命名为vuex_开头,以便与页面数据区分避免冲突。

2.2.2.1 定义
2.2.2.1.1 临时存储

直接在/src/store/index.js中定义,如下边的vuex_tmp

1
2
3
4
5
6
7
8
9
const store = new Vuex.Store({
state: {
vuex_token: lifeData.vuex_token ? lifeData.vuex_token : null,
vuex_tmp: null
},

...

})
2.2.2.1.2 持久化存储

/src/store/index.js中定义,并写入saveStateKeys中,如下边的vuex_token,定义的时候格式为vuex_token: lifeData.vuex_token ? lifeData.vuex_token : null

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 需要永久存储,且下次APP启动需要取出的,在state中的变量名
let saveStateKeys = ['vuex_token'];

...

const store = new Vuex.Store({
state: {
vuex_token: lifeData.vuex_token ? lifeData.vuex_token : null,
vuex_tmp: null
},

...

})
2.2.2.2 使用
2.2.2.2.1 取值
  • 页面<template>中取值{{ vuex_token }}
  • js代码(包括App.vue页面)<script>中取值this.vuex_token
  • 拦截器等通用组件中(须获取上下文vm)取值vm.vuex_token
2.2.2.2.2 设值

可以设定值的类型为基本数据类型可以进行序列化的对象/列表等

1
2
3
4
5
6
7
8
// 字符串
this.$u.vuex('vuex_token', "xxxxx");
// 对象
this.$u.vuex('vuex_token', {
id: 1,
key: 'token',
value: 'xxxxx'
});

2.2.3 接口

接口基于luch-requestuView对其简单封装,本示例使用的是uView封装后的,对最常用的场景做了说明,更详细的文档见uView的http请求

2.2.3.1 统一拦截器

接口拦截器在/src/utils/request.js中,可以根据需要自行修改;

对于请求:

  • 凡是不以/login开头,且当前已有token的(数据中心vuex_token字段值非null),将自动在请求头header.token存入已有的token值;

对于响应:

  • 响应值response.statusCode200的,将拦截,弹框提示并抛出异常,可在接口catch中捕获;
  • 响应数据存在response.data.code字段的,判断code值:
    • 值为401将拦截并抛出异常,可在接口catch中捕获,建议在拦截器中统一处理;
    • 值非200且非401将拦截,弹框提示并抛出异常,可在接口catch中捕获;
    • 值为200的,将返回response.data,可在接口then中获取;
  • 响应数据不存在response.data.code字段的,将返回response.data,可在接口then中获取。
2.2.3.2 api集中管理

提示:get请求第一个参数是配置,post请求第一个参数是请求值,第二个才是配置

/src/api/目录下新建api.js文件,内容如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
const http = uni.$u.http

// get请求
export const getMenu1 = () => http.get(`/ebapi/public_api/index`)

// get请求
export const getMenu2 = (id) => http.get(`/ebapi/public_api/index/${id}`)

// get请求
export const getMenu3 = (params) => http.get('/ebapi/public_api/index', {params})

// get请求(带header等配置)
export const getMenu4 = (params) => http.get('/ebapi/public_api/index', {
params,
header: {
token: '1111'
}
})

// post请求
export const postMenu = (data) => http.post('/ebapi/public_api/index', data)

// post请求(带header等)
export const postMenu = (data) => http.post('/ebapi/public_api/index', data, {
header: {
token: '1111'
},
responseType: 'arraybuffer'
})

// 更多请求使用
uni.$u.http.get(url[, config])
uni.$u.http.post(url[, data[, config]])
uni.$u.http.delete(url[, data[, config]])
uni.$u.http.put(url[, data[, config]])
uni.$u.http.middleware(config)
uni.$u.http.request(config)
uni.$u.http.upload(url[, config])
uni.$u.http.head(url[, data[, config]])
uni.$u.http.connect(url[, data[, config]])
uni.$u.http.options(url[, data[, config]])
uni.$u.http.trace(url[, data[, config]])
2.2.3.3 api使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import {
getMenu2,
getMenu3
} from '@/api/api.js';

getMenu2(1).then(res => {
// 经过拦截器的处理,进入到这里的请求都是成功请求,无需考虑请求失败的情况
console.log('res',res)
}).catch(err=>{
// 多数情况下,不需要写catch,因为拦截器已经进行了弹窗提示等操作
// 但当页面需要对错误进行处理时(例如关闭加载动画,取消按钮loading等),就需要在catch中操作
console.log('err',err)
})

getMenu3({
id: 1
}).then(
...
).catch(
...
)

postMenu({
id: 1
}).then(
...
).catch(
...
)

2.2.4 全局过滤器

2.2.4.1 定义

全局过滤器定义在/src/utils/filters.js中,可参照其增加自己的过滤规则,常用定义方式如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 0-男,1-女
const sexFilter = (value) => {
let sexList = ['男', '女'];
return sexList[value] ? sexList[value] : "--";
}

// xx-小学及以下,cz-初中,gz-高中及以上
const educationFilter = (value) => {
switch (value) {
case 'xx':
return '小学及以下';
case 'cz':
return '初中';
case 'gz':
return '高中及以上';
default:
return '--';
}
}

export default {
sexFilter,
educationFilter
}
2.2.4.2 使用

因为已经在main.js中定义如下

1
2
import filters from '@/utils/filters';
Object.keys(filters).forEach(k => Vue.filter(k, filters[k]));

所以页面中无需引入,如下直接使用

1
<view>过滤器-性别:{{ sex | sexFilter }}</view>

效果:当sex0,页面输出;当sex1,页面输出

参考 uViewuniapp


一个上手即用的通用公众号/小程序/h5/app框架
https://blog.ctftools.com/2022/06/newpost-43/
作者
Dr3@m
发布于
2022年6月10日
许可协议