一、uni-ui组件库
二、小程序端Pinia持久化
说明:Pinia用法与Vue3项目完全一致,uni-app项目仅需解决持久化插件兼容性问题。
1.持久化存储插件
安装持久化存储插件:pinia-plugin-persistedstate
pnpm i pinia-plugin-persistedstate
注意:插件默认使用localStorage实现持久化,小程序端不兼容,需要替换持久化API。
2.基本用法
src/stores/modules/member.ts
import type { LoginResult } from '@/types/member'
import { defineStore } from 'pinia'
import { ref } from 'vue'
// 定义 Store
export const useMemberStore = defineStore(
'member',
() => {
// 会员信息
const profile = ref<LoginResult>()
// 保存会员信息,登录时使用
const setProfile = (val: LoginResult) => {
profile.value = val
}
// 清理会员信息,退出时使用
const clearProfile = () => {
profile.value = undefined
}
// 记得 return
return {
profile,
setProfile,
clearProfile,
}
},
// TODO: 持久化
{
// 网页端配置
// persist: true,
// 小程序端配置
persist:{
storage:{
getItem(key) {
return uni.getStorageSync(key)
},
setItem(key,value){
uni.setStorageSync(key,value)
}
}
}
},
)
stores/index.ts
import { createPinia } from 'pinia'
import persist from 'pinia-plugin-persistedstate'
// 创建 pinia 实例
const pinia = createPinia()
// 使用持久化存储插件
pinia.use(persist)
// 默认导出,给 main.ts 使用
export default pinia
// 模块统一导出
export * from './modules/member'
src/main.ts
import { createSSRApp } from 'vue'
import pinia from './stores'
import App from './App.vue'
export function createApp() {
const app = createSSRApp(App)
app.use(pinia)
return {
app,
}
}
2.多端兼容
网页端持久化API
// 网页端API
localStorage.setItem()
localStorage.getItem()
多端持久化API
// 兼容多端API
uni.setStorageSync()
uni.getStorageSync()
三、uni.request请求封装
1.请求和上传文件拦截器
uniapp拦截器:uni.addInterceptor
接口说明:接口文档
实现需求如下:
- 拼接基础地址
- 设置超时时间
- 添加请求头标识
- 添加token
// 添加拦截器:
// 拦截 request 请求
// 拦截 uploadFile 文件上传
import { useMemberStore } from "@/stores"
// TODO:
// 1.非 http 开头需拼接地址
// 2.请求超时
// 3.添加小程序端请求头标识
// 4.添加 token 请求头标识
const baseURL =
'https://pcapi-xiaotuxian-front-devtest.itheima.net'
// 添加拦截器
const httpInterceptor = {
// 拦截器触发
invoke(options:UniApp.RequestOptions){
// 1. 非 http 开头需拼接地址
if (!options.url.startsWith('http')) {
options.url = baseURL + options.url
}
// 2.请求超时,默认60s
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
}
}
}
uni.addInterceptor('request',httpInterceptor)
uni.addInterceptor('uploadFile',httpInterceptor)
2.封装Promise请求函数
/**
* 请求函数
* @param UniApp.RequestOptions
* @returns Promise
* 1. 返回 Promise 对象,用于处理返回值类型
* 2. 请求成功
* 2.1 提取核心数据 res.data
* 2.2 添加类型,支持泛型
* 3. 请求失败
* 3.1 网络错误 -> 提示用户换网络
* 3.2 401错误 -> 清理用户信息,跳转到登录页
* 3.3 其他错误 -> 根据后端错误信息轻提示
*/
interface Data<T> {
code: string
msg: string
result: T
}
export const http = <T>(options:UniApp.RequestOptions) =>{
// 1. 返回 Promise 对象
return new Promise<Data<T>>((resolve,reject)=>{
uni.request({
...options,
// 响应成功
success(res){
// 状态码 2XXX axios 就是这样设计的
if (res.statusCode >= 200 && res.statusCode < 300) {
// 2.1 提取核心数据 res.data
resolve(res.data as Data<T>)
} else if (res.statusCode === 401) {
// 401错误 -> 清理用户信息,跳转到登录页
const memberStore = useMemberStore()
memberStore.clearProfile()
uni.navigateTo({url:'/pages/login/login'})
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)
}
})
})
}