uni-app development applet: project structure and experience sharing

uni-app development applet: project structure and experience sharing

2022In 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, if Appa iosset Androidof code can be packaged for multiple terminals, the cost can be solved to a certain extent; the front-end technology stack Also vue, in the inspection selection uni-app. Later, many small program projects were developed uni-app, accumulated some experience and packaged more business components. Here I will share the uni-appoverall structure of the project, common method packaging and precautions. The full-text code will be placed github, like it first and then read it, earning millions a year!

create project

uni-appThere are two ways to create a project:

⚠️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 小程序or Appdevelopment environment, it can be HBuilderXcreated 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 it vue-clito 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-cliIt 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.jsonchange the command in it to:

"scripts": {
    "serve": "npm run dev:mp-weixin"
}

then execute

npm run serve

cliCreate a project without cssprecompilation by default, you need to install it manually, here is an sassexample:

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.jsonfile

"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.jsonis configured in the file, but jsonthe file cannot directly write variables. At this time, you can refer to the official solution: create vue.config.jsa file , the specific operation is as follows.

Create a file in the root directory vue.config.jsand 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-appthe end of the initial work of the project, and I will have the opportunity to write a complete set of unie-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!

Guess you like

Origin juejin.im/post/7259589417736847416