uni-app development applet: project structure and experience sharing
2022
In 2019, in order to quickly complete the product and launch it, the company chose the WeChat applet as the carrier; because it still plans to develop it later; although the company has an agreement, ifApp
aios
setAndroid
of code can be packaged for multiple terminals, the cost can be solved to a certain extent; the front-end technology stack Alsovue
, in the inspection selectionuni-app
. Later, many small program projects were developeduni-app
, accumulated some experience and packaged more business components. Here I will share theuni-app
overall structure of the project, common method packaging and precautions. The full-text code will be placedgithub
, like it first and then read it, earning millions a year!
create project
uni-app
There are two ways to create a project:
- 1. Created by the HBuilderX visualization tool
- 2. Created by vue-cli command
⚠️It should be noted that the creation method of the project must be selected according to the project requirements; if it is only a single development
小程序
orApp
development environment, it can beHBuilderX
created with a visual tool. If multi-terminal development, and the same set of code may be packaged to generate multiple small programs, it is recommended to use itvue-cli
to create, otherwise it will be more painful to automate the build and compile according to the specified conditions later. Regarding conditional compilation, there will be detailed instructions later in the article.
vue-cli
It is relatively simple to install and run using :
1. Install vue-cli globally
npm install -g @vue/cli
2. Create uni-app
vue create -p dcloudio/uni-preset-vue 项目名称
3. Enter the project folder
cd 项目名称
4. To run the project, if it is based on the WeChat applet, you can package.json
change the command in it to:
"scripts": {
"serve": "npm run dev:mp-weixin"
}
then execute
npm run serve
cli
Create a project without css
precompilation by default, you need to install it manually, here is an sass
example:
npm i sass --save-dev
npm i sass-loader --save-dev
overall project structure
通过HBuilderX
或者vue-cli
创建的项目,目录结构有稍许不同,但基本没什么差异,这里就按vue-cli
创建的项目为例,整体架构配置如下:
├──dist 编译后的文件路径
├──package.json 配置项
├──src 核心内容
├──api 项目接口
├──components 全局公共组件
├──config 项目配置文件
├──pages 主包
├──static 全局静态资源
├──store vuex
├──mixins 全局混入
├──utils 公共方法
├──App.vue 应用配置,配置App全局样式以及监听
├──main.js Vue初始化入口文件
├──manifest.json 配置应用名称、appid等打包信息
├──pages.json 配置页面路由、导航条、选项卡等页面类信息
└──uni.scss 全局样式
封装方法
工欲善其事,必先利其器。在开发之前,我们可以把一些全局通用的方法进行封装,以及把uni-app
提供的api
进行二次封装,方便使用。全局的公共方法我们都会放到/src/utils
文件夹下。
封装常用方法
下面这些方法都放在/src/utils/utils.js
中,文章末尾会提供github
链接方便查看。如果项目较大,建议把方法根据功能定义不同的js
文件。
小程序Toast
提示
/**
* 提示方法
* @param {String} title 提示文字
* @param {String} icon icon图片
* @param {Number} duration 提示时间
*/
export function toast(title, icon = 'none', duration = 1500) {
if(title) {
uni.showToast({
title,
icon,
duration
})
}
}
缓存操作(设置/获取/删除/清空)
/**
* 缓存操作
* @param {String} val
*/
export function setStorageSync(key, data) {
uni.setStorageSync(key, data)
}
export function getStorageSync(key) {
return uni.getStorageSync(key)
}
export function removeStorageSync(key) {
return uni.removeStorageSync(key)
}
export function clearStorageSync() {
return uni.clearStorageSync()
}
页面跳转
/**
* 页面跳转
* @param {'navigateTo' | 'redirectTo' | 'reLaunch' | 'switchTab' | 'navigateBack' | number } url 转跳路径
* @param {String} params 跳转时携带的参数
* @param {String} type 转跳方式
**/
export function useRouter(url, params = {}, type = 'navigateTo') {
try {
if (Object.keys(params).length) url = `${url}?data=${encodeURIComponent(JSON.stringify(params))}`
if (type === 'navigateBack') {
uni[type]({ delta: url })
} else {
uni[type]({ url })
}
} catch (error) {
console.error(error)
}
}
图片预览
/**
* 预览图片
* @param {Array} urls 图片链接
*/
export function previewImage(urls, itemList = ['发送给朋友', '保存图片', '收藏']) {
uni.previewImage({
urls,
longPressActions: {
itemList,
fail: function (error) {
console.error(error,'===previewImage')
}
}
})
}
图片下载
/**
* 保存图片到本地
* @param {String} filePath 图片临时路径
**/
export function saveImage(filePath) {
if (!filePath) return false
uni.saveImageToPhotosAlbum({
filePath,
success: (res) => {
toast('图片保存成功', 'success')
},
fail: (err) => {
if (err.errMsg === 'saveImageToPhotosAlbum:fail:auth denied' || err.errMsg === 'saveImageToPhotosAlbum:fail auth deny') {
uni.showModal({
title: '提示',
content: '需要您授权保存相册',
showCancel: false,
success: (modalSuccess) => {
uni.openSetting({
success(settingdata) {
if (settingdata.authSetting['scope.writePhotosAlbum']) {
uni.showModal({
title: '提示',
content: '获取权限成功,再次点击图片即可保存',
showCancel: false
})
} else {
uni.showModal({
title: '提示',
content: '获取权限失败,将无法保存到相册哦~',
showCancel: false
})
}
},
fail(failData) {
console.log('failData', failData)
}
})
}
})
}
}
})
}
更多函数就不在文章中展示了,已经放到/src/utils/utils,js
里面,具体可以到github查看。
请求封装
为了减少在页面中的请求代码,所以我们要对uni-app
提供的请求方式进行二次封装,在/src/utils
文件夹下建立request.js
,具体代码如下:
import {toast, clearStorageSync, getStorageSync, useRouter} from './utils'
import {BASE_URL} from '@/config/index'
const baseRequest = async (url, method, data, loading = true) =>{
header.token = getStorageSync('token') || ''
return new Promise((reslove, reject) => {
loading && uni.showLoading({title: 'loading'})
uni.request({
url: BASE_URL + url,
method: method || 'GET',
header: header,
timeout: 10000,
data: data || {},
success: (successData) => {
const res = successData.data
uni.hideLoading()
if(successData.statusCode == 200){
if(res.resultCode == 'PA-G998'){
clearStorageSync()
useRouter('/pages/login/index', 'reLaunch')
}else{
reslove(res.data)
}
}else{
toast('网络连接失败,请稍后重试')
reject(res)
}
},
fail: (msg) => {
uni.hideLoading()
toast('网络连接失败,请稍后重试')
reject(msg)
}
})
})
}
const request = {};
['options', 'get', 'post', 'put', 'head', 'delete', 'trace', 'connect'].forEach((method) => {
request[method] = (api, data, loading) => baseRequest(api, method, data, loading)
})
export default request
请求封装好以后,我们在/src/api
文件夹下按业务模块建立对应的api
文件,拿获取用户信息接口举例子:
在/src/api
文件夹下建立user.js
,然后引入request.js
import request from '@/utils/request'
//个人信息
export const info = data => request.post('/v1/api/info', data)
在页面中直接使用:
import {info} from '@/api/user.js'
export default {
methods: {
async getUserinfo() {
let info = await info()
console.log('用户信息==', info)
}
}
}
版本切换
很多场景下,需要根据不同的环境去切换不同的请求域名、APPID
等字段,这时候就需要通过环境变量来进行区分。下面案例我们就分为三个环境:开发环境(dev
)、测试环境(test
)、生产环境(prod
)。
建立env
文件
在项目根目录建立下面三个文件并写入内容(常量名要以VUE开头命名):
.env.dev
(开发环境)
VUE_APP_MODE=build
VUE_APP_ID=wxbb53ae105735a06b
VUE_APP_BASE=https://www.baidu.dev.com
.env.test
(test environment)
VUE_APP_MODE=build
VUE_APP_ID=wxbb53ae105735a06c
VUE_APP_BASE=https://www.baidu.test.com
.env.prod
(Production Environment)
VUE_APP_MODE=wxbb53ae105735a06d
VUE_APP_ID=prod
VUE_APP_BASE=https://www.baidu.prod.com
modify package.json
file
"scripts": {
"dev:mp-weixin": "cross-env UNI_PLATFORM=mp-weixin vue-cli-service uni-build --watch --mode dev",
"build:mp-weixin": "cross-env UNI_PLATFORM=mp-weixin vue-cli-service uni-build --watch --mode prod"
},
then execute
npm run dev:mp-weixin
Below/src/pages/index/index.vue
, print:
onLoad() {
console.log(process.env.VUE_APP_MODE, '====VUE_APP_BASE')
console.log(process.env.VUE_APP_BASE, '====VUE_APP_BASE')
},
At this point the output is
dev ====VUE_APP_BASE
https://www.baidu.dev.com ====VUE_APP_BASE
Dynamically modify appid
If the same set of code needs to be packaged to generate multiple small programs, it needs to be dynamically modified appid
; at the beginning of the article, it was said that the appid /src/manifest.json
is configured in the file, but json
the file cannot directly write variables. At this time, you can refer to the official solution: create vue.config.js
a file , the specific operation is as follows.
Create a file in the root directory vue.config.js
and write the following content:
// 读取 manifest.json ,修改后重新写入
const fs = require('fs')
const manifestPath = './src/manifest.json'
let Manifest = fs.readFileSync(manifestPath, { encoding: 'utf-8' })
function replaceManifest(path, value) {
const arr = path.split('.')
const len = arr.length
const lastItem = arr[len - 1]
let i = 0
let ManifestArr = Manifest.split(/\n/)
for (let index = 0; index < ManifestArr.length; index++) {
const item = ManifestArr[index]
if (new RegExp(`"${arr[i]}"`).test(item)) ++i
if (i === len) {
const hasComma = /,/.test(item)
ManifestArr[index] = item.replace(
new RegExp(`"${lastItem}"[\\s\\S]*:[\\s\\S]*`),
`"${lastItem}": ${value}${hasComma ? ',' : ''}`
)
break
}
}
Manifest = ManifestArr.join('\n')
}
// 读取环境变量内容
replaceManifest('mp-weixin.appid', `"${process.env.VUE_APP_ID}"`)
fs.writeFileSync(manifestPath, Manifest, {
flag: 'w'
})
end
This is uni-app
the end of the initial work of the project, and I will have the opportunity to write a complete set of uni
e-commerce applet projects later, remember to pay attention. The code has been submitted to github , if it is helpful to you, remember to click star
!