UniApp 小程序开发技巧

1,431 阅读2分钟

这里是最近基于 vue2.x 的 uniapp 小程序开发过程中的一些技巧汇总,希望可以给到刚刚入门uniapp开发的同学一些帮助。

1. 使用 easycom 简化自定义模块导入

easycom 介绍

传统vue组件,需要安装、引用、注册,三个步骤后才能使用组件。easycom 将其精简为一步。 只要组件安装在项目的 components 目录下,并符合 components/ 组件名称/组件名称.vue目录结构。就可以不用引用、注册,直接在页面中使用。不管 components 目录下安装了多少组件,easycom 打包后会自动剔除没有使用的组件,对组件库的使用尤为友好。官方介绍

项目中用到的全局公共组件可以使用 easycom 的方式自动引用,而且可以按需打包,十分方便,提升开发效率

自定义的包为 tj-ui,相关的组件放到 tj-ui/components

目录结构

├── uni_modules
    ├── tj-ui
    │   └── components
    │       ├── tj-description
    │       ├── tj-description-item
    │       └── tj-section

组件以正常的组件写法相同,没有什么不一样,但要注意多端的兼容

配置

在根目录下 /pages.json 中配置导入的模块路径规则

{
    ...
    "easycom": {
        "autoscan": true,
        "custom": {
          "^tj-(.*)": "@/uni_modules/tj-ui/components/tj-$1/tj-$1.vue",
        }
    }
}

使用

  • 需要重新运行项目或重启Hbuilder
  • 注意组件标签的名称要与 tj-ui/components 下的名称一致
<tj-section>
  <tj-description>
    <tj-description-item title="检查时间" :rightText="examDate" border />
    <tj-description-item title="订单金额" :rightText="orderPrice" border />
    <tj-description-item title="收据金额" :rightText="selfMoney" />
  </tj-description>
</tj-section>

2. request 请求封装

接口请求主要解决以下几个问题

  • 更简洁的接口定义
  • 支持配置为全局和本地处理异常
  • 支持配置为全局和本地处理loading
  • 支持配置post请求体的数据类型为 默认的请求体类或JSON
  • 登录失效后自动跳转到授权登录页面,登录后回跳回来

接口定义

import registApi from './request'

const apiConfig = {
    login: 'post /login',
    deleteOrder: (orderId) => `delete /order/${orderId}`
}

const api = registApi(apiConfig, '/api')

export defalut api;

应用场景

import api from '@/api'

// - 默认值:没有loading、全局处理异常、请求体为 json
api.login({ data }) 

// - 全局处理异常
// 如果出现异常返回 永不结束的promise
// 1. 防止抛出 `Uncaught (in promise)` 异常
// 2. 使用时结合 async await 不需要 try...catch 来捕获异常
api.login({ data, catchError: false })

// - 全局显示loading
api.login({ data, loading: true })

// - 本地处理loading和异常
api.login({
    data, 
    // 本地处理loading
    loading: isLoading => {
        this.isLoading = isLoading;
    },
    catchError: false
}).catch(err => {
    // 处理异常
})

// - 使用表单提交,content-type 设置为 application/x-www-form-urlencoded
api.login({ data, dataType: 'default' })

异常的分类和处理

从接口返回的数据大致可以区分两种异常:业务异常 和 网络异常

  • 网络异常:超时、服务器5xx、无网络
  • 业务异常:请求体格式错误、正常的是业务异常提示如: 用户名密码不正确等

网络异常始终全局提示,此时应该中断后续业务逻辑 业务异常分两种,一种只是提醒没有后续逻辑,一种是提醒,点击后有后续逻辑,前一种可以全局处理,后一种需要具体业务具体处理,要本地处理,catchError要设置为 false

3. 项目目录结构设计

.
├── api             // 接口定义
├── components      // 自定义的公共组件
├── docs            // 项目文档
├── env.js          // 环境配置
├── mixins          // 公共Mixin
├── node_modules
├── pages           // 页面分包 - 主包
├── pages_exam      // 页面分包 - 子包
├── pages_hospital  // 页面分包 - 子包 
├── plugins         // 挂载在Vue原型上的插件
├── service         // 公共的业务逻辑
├── static          // 静态资源
├── store           // Vuex数据层
├── uni_modules     // easycom 模块
├── utils           // 工具层

4. 路由拦截封装

要封装的功能点:

  • 提供一致的路由跳转方法,内置部分固定逻辑
  • 提供登录状态校验
  • 提供跳转参数封装

小程序提供的几种页面跳转方式:

uni.navigateTo 保留当前页面,跳转到应用内的某个页面,使用uni.navigateBack可以返回到原页面
uni.redirectTo 关闭当前页面,跳转到应用内的某个页面
uni.reLaunch 关闭所有页面,打开到应用内的某个页面
uni.switchTab 跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面
uni.navigateBack 关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages() 获取当前的页面栈,决定需要返回几层。

统一使用 this.$$routerTo(path, params, { auth: false, redirect: false }) 来跳转页面,后面两个参数可选

path 可以是小程序页面路径,也可以是外部地址

1. 登录认证

例: this.$$routerTo('/pages/order/order', {}, { auth: true }),方法内部会检查用户状态

这里的实现方式是多样的,不同的业务有不同的实现,这里我的实现是,用户登录后,在storage中存储一个标识,标识为true则已登录,为false则未登录,未登录用户需要跳转到授权登录页面或账号密码登录页面,跳转的时候需要带上回跳地址

if(auth === true && uni.getStorageSync('isLogin') === false){
    routerTo('/pages/authorized/authorized', { nextUrl: encodeURIComponent(buildPath(path, paramas)) })
}

2. tabar页面

tabbar 页面的特殊情况:不能带参数,只能使用 uni.switchTab 切换

tabbar页面可根据路径来判断是否是tabbar页面 如果需要带参数到tabbar页面,可以在跳转之前缓存数据,到tabbar页面后,从 onShow 中读取缓存数据,并清空缓存

  // Tabar页面
  if(pagePath.startsWith('/pages/tabbar')){
    // 如果是tabar,则使用 switchTab, 并缓存tabbar跳转参数到本地
    if(paramas) saveTabbarData(paramas);
    uni.switchTab({ url: pagePath })
    return;
  }

3. 外部地址

外部地址的跳转:以 http 开头的地址应该跳转到 webivew 页面打开

  if(path.startsWith('http')){
    const webviewPath = '/pages/webview/webview?url='+encodeURIComponent(path) + '&' + obj2Params(paramas);
    uni.navigateTo({ url: webviewPath})
    return;
  }

4. 重定向

例: this.$$routerTo('/pages/home/home', {}, { redirect: true })

如果是重写向则使用 uni.redirectTo 否则使用 uni.navigateTo 跳转

5. 全局挂载工具方法

将工具方法全局挂载到 Vue 原型上,方便业务调用

this.$$apis.login();
this.$$routerTo()
import apis from '@/api/index.js'
import { routerTo } from '@/utils/router.js'

const plugins = {
  install: Vue => {
    Vue.prototype.$$apis = apis;
    Vue.prototype.$$routerTo = routerTo;
  }
}

export default plugins;
import Vue from 'vue'
imoprt plugins from '@/plugins'

Vue.use(plugins);