跳至主要內容

客户端开发(二)| uni-app 项目起步

Kevin 吴嘉文大约 5 分钟知识笔记webfront

相关信息

感谢黑马程序员提供的完善资料。该文章基于黑马程序员教材做了少量改动。

项目架构

项目架构图

项目架构图
项目架构图

拉取项目模板代码

项目模板包含:目录结构,项目素材,代码风格。

模板地址

git clone https://gitee.com/Megasu/uniapp-shop-vue3-ts.git

注意事项

  • 在 manifest.json 中添加微信小程序的 appid

页面构建:引入 uni-ui 组件库

操作步骤

安装 [uni-ui 组件库](https://uniapp.dcloud.net.cn/component/uniui/quickstart.html#npm 安装)

npm i @dcloudio/uni-ui
npm install --save-dev sass

相关信息

uni-ui 类似 element-ui 等 vue 模块库。

配置自动导入组件

// pages.json
{
  // 组件自动导入,可以在 vue 文件中,自动导入组件库
  "easycom": {
    "autoscan": true,
    "custom": {
      // uni-ui 规则如下配置  
      "^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue" 
    }
  },
  "pages": [
    // …省略
  ]
}

安装类型声明文件

npm i -D @uni-helper/uni-ui-types

配置类型声明文件

// tsconfig.json
{
  "compilerOptions": {
    "types": [
      "@dcloudio/types",
      "@uni-helper/uni-app-types", // [!code ++]
      "@uni-helper/uni-ui-types" // [!code ++]
    ]
  }
}

使用 uni-ui 的 component

  • 比如要使用 Uni-Ui 官方提供的 card 模块的话,直接在 vue 文件中添加即可。
<uni-card title="基础卡片" extra="额外信息">
    <text>这是一个基础卡片示例,此示例展示了一个标题加标题额外信息的标准卡片。</text>
</uni-card>

状态管理:小程序端 Pinia 持久化

提示

项目中 Pinia 用法平时完全一致,主要解决持久化插件 兼容性 问题。插件默认使用 localStorage 实现持久化,小程序端不兼容,需要替换持久化 API。

当然 Uni-app 也支持使用 vuex 来进行状态管理。但是看网上对 Pinia 以及 VUEX 的评论,感觉 Pinia 更好一点?

但目前看来 VUEX 对 TypeScript 的支持没有 pinia 那么好。

持久化存储插件

持久化存储插件: pinia-plugin-persistedstateopen in new window

安装:npm install pinia@2.0.27 pinia-plugin-persistedstate (要求 vue>3.3.4); pinia 官网文档open in new window

网页端持久化 API

// 网页端 API
localStorage.setItem()
localStorage.getItem()

多端持久化 API

// 兼容多端 API
uni.setStorageSync()
uni.getStorageSync()

参考代码

// stores/modules/member.ts
export const useMemberStore = defineStore(
  'member',
  () => {
    // 常规的 pinia 配置
  },
  {
    // 配置持久化
    persist: {
      // 调整为兼容多端的 API
      storage: {
        setItem(key, value) {
          uni.setStorageSync(key, value) // [!code warning]
        },
        getItem(key) {
          return uni.getStorageSync(key) // [!code warning]
        },
      },
    },
  },
)






 
 
 
 
 
 
 
 
 
 
 
 
 
 

持久化储存,用户之间不会受到影响。

数据交互:uni.request 请求封装

添加请求和上传文件拦截器

相关信息

在各种页面的 vue 文件中,我们可能需要发送不同的 request。配置拦截器之后,所有 vue 中发送的请求,都会先经过拦截器,而后发送出 request。

拦截器可以用于对 URL 进行格式化,添加 header,timeout 配置等操作。当然我们可以同时拦截 request 和 uploadFile

uniapp 拦截器 : uni.addInterceptoropen in new window

接口说明 :接口文档open in new window

实现步骤

  1. 基础地址
  2. 超时时间
  3. 请求头标识
  4. 添加 token

参考代码

在 vue 文件中填写请求:

import '@/utils/http'
const get_data = ()=> {
  const res = uni.request({
      'method': 'GET',
      'url': '/'
        }
  )
}

填写拦截器

// src/utils/http.ts
const httpInterceptor = {
  // 拦截前触发
  invoke(options: UniApp.RequestOptions) {
    // 1. 非 http 开头需拼接地址
    if (!options.url.startsWith('http')) {
      options.url = baseURL + options.url
    }
    // 2. 请求超时
    options.timeout = 10000
    // 3. 添加小程序端请求头标识
    options.header = {
      ...options.header,
      'source-client': 'miniapp',
    }
    // 4. 添加 token 请求头标识
    const memberStore = useMemberStore()
    const token = memberStore.profile?.token
    if (token) {
      options.header.Authorization = token
    }
  },
}

// 拦截 request 请求
uni.addInterceptor('request', httpInterceptor)
// 拦截 uploadFile 文件上传
uni.addInterceptor('uploadFile', httpInterceptor)

封装 Promise 请求函数

实现步骤

image-20230904110203015
image-20230904110203015

参考代码

import {http} from '@/utils/http'
const get_data = async ()=> {
  const res = await http({
      'method': 'GET',
      'url': '/'
        }
  )
  console.log(res)
}
配置接收器代码
// src/utils/http.ts
/**
 * 请求函数
 * @param  UniApp.RequestOptions
 * @returns Promise
 *  1. 返回 Promise 对象
 *  2. 获取数据成功
 *    2.1 提取核心数据 res.data
 *    2.2 添加类型,支持泛型
 *  3. 获取数据失败
 *    3.1 401 错误  -> 清理用户信息,跳转到登录页
 *    3.2 其他错误 -> 根据后端错误信息轻提示
 *    3.3 网络错误 -> 提示用户换网络
 */
type Data<T> = {
  code: string
  msg: string
  result: T
}
// 2.2 添加类型,支持泛型
export const http = <T>(options: UniApp.RequestOptions) => {
  // 1. 返回 Promise 对象,给 promise 指定类型。
  return new Promise<Data<T>>((resolve, reject) => {
    uni.request({
      ...options,
      // 响应成功 - 只要服务器链接了,不论返回的是什么 code 都算相应成功
      success(res) {
        // 状态码 2xx, axios 就是这样设计的
        if (res.statusCode >= 200 && res.statusCode < 300) {
          // 2.1 提取核心数据 res.data,采用类型断言,指定 res.data 的类型
          // resolve 标记成功并返回结果
          resolve(res.data as Data<T>)
        } else if (res.statusCode === 401) {
          // 401 错误  -> 清理用户信息,跳转到登录页
          const memberStore = useMemberStore()
          memberStore.clearProfile()
          // 实现页面跳转(不能跳转到 tabBar 页面)
          uni.navigateTo({ url: '/pages/login/login' })
          // return reject 返回错误
          reject(res)
        } else {
          // 其他错误 -> 根据后端错误信息轻提示
          uni.showToast({
            icon: 'none',
            title: (res.data as Data<T>).msg || '请求错误',
          })
          reject(res)
        }
      },
      // 响应失败
      fail(err) {
        uni.showToast({
          icon: 'none',
          title: '网络错误,换个网络试试',
        })
        reject(err)
      },
    })
  })
}

【拓展】代码规范

为什么需要代码规范

如果没有统一代码风格,团队协作不便于查看代码提交时所做的修改。

diff
diff

统一代码风格

  • 安装 eslint + prettier
npm i -D eslint prettier eslint-plugin-vue @vue/eslint-config-prettier @vue/eslint-config-typescript @rushstack/eslint-patch @vue/tsconfig
  • 新建 .eslintrc.cjs 文件,添加以下 eslint 配置
/* eslint-env node */
require('@rushstack/eslint-patch/modern-module-resolution')

module.exports = {
  root: true,
  extends: [
    'plugin:vue/vue3-essential',
    'eslint:recommended',
    '@vue/eslint-config-typescript',
    '@vue/eslint-config-prettier',
  ],
  // 小程序全局变量
  globals: {
    uni: true,
    wx: true,
    WechatMiniprogram: true,
    getCurrentPages: true,
    UniApp: true,
    UniHelper: true,
  },
  parserOptions: {
    ecmaVersion: 'latest',
  },
  rules: {
    'prettier/prettier': [
      'warn',
      {
        singleQuote: true,
        semi: false,
        printWidth: 100,
        trailingComma: 'all',
        endOfLine: 'auto',
      },
    ],
    'vue/multi-word-component-names': ['off'],
    'vue/no-setup-props-destructure': ['off'],
    'vue/no-deprecated-html-element-is': ['off'],
    '@typescript-eslint/no-unused-vars': ['off'],
  },
}
  • 配置 package.json
{
  "script": {
    // ... 省略 ...
    "lint": "eslint . --ext .vue,.js,.ts --fix --ignore-path .gitignore"
  }
}
  • 运行
pnpm lint 
# 或 npm run lint

到此,你已完成 eslint + prettier 的配置。

Git 工作流规范

  • 安装并初始化 husky
# 或 npx husky-init && npm install
pnpm dlx husky-init
  • 安装 lint-staged
# 或 npm install lint-staged -D
pnpm i lint-staged -D
  • 配置 package.json
{
  "script": {
    // ... 省略 ...
  },
  "lint-staged": {
    "*.{vue,ts,js}": ["eslint --fix"]
  }
}
  • 修改 .husky/pre-commit 文件
pnpm lint-staged
  • 之后采用 git commit 时候,代码会自动进行格式规范修改
上次编辑于:
贡献者: kevinng77