【前端/uniapp】项目配置、请求函数封装
黑马程序员前端项目uniapp小兔鲜儿微信小程序项目视频教程,基于Vue3+Ts+Pinia+uni-app的最新组合技术栈开发的电商业务全流程_哔哩哔哩_bilibili
参考
有代码,还有app、h5页面、小程序的演示
小兔鲜儿-vue3+ts-uniapp-一套代码多端部署: 小兔鲜儿-vue3+ts-uniapp 项目已上线,小程序搜索《小兔鲜儿》即可体验。🎉🎉🎉 <br/> 配套项目接口文档,配套笔记。
接口文档
创建uni-app项目
官方文档:
npx degit dcloudio/uni-preset-vue#vite-ts my-vue3-project
could not fetch
本质是拉取模板,网络不好就会拉取失败
(拉取失败了,但因为过去创建过,所以使用了缓存)
使用vscode开发uni-app项目
uni-create-view 快速创建 uni-app 页面
安装后进行设置
配置好后,直接创建uniapp页面
前一个是页面,后一个是页面路由pages路径名称
能否自动注册页面路由
uni-helper 代码提示
工具包,包含多个插件
uniapp小程序扩展 鼠标悬停查文档
完善ts类型校验
uni-helper的配置(使用pnpm)
官网
安装依赖
pnpm i -D @uni-helper/uni-app-types
设置 .npmrc避免幽灵依赖
npm 和 pnpm 共同使用同一个 .npmrc 是文件
win下,.npmrc文件的位置为:%USERPROFILE%/.npmrc
找到文件,然后添加或修改成true
shamefully-hoist=true
查看配置
pnpm config get shamefully-hoist
微信小程序配置
插件github仓库:
微信开放文档:
安装依赖
pnpm i -D miniprogram-api-typings
配置tsconfig.json
// tsconfig.json
{
"extends": "@vue/tsconfig/tsconfig.json",
"compilerOptions": {
"sourceMap": true,
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
},
"lib": ["esnext", "dom"],
// 类型声明文件
"types": [
"@dcloudio/types", // uni-app API 类型
"miniprogram-api-typings", // 原生微信小程序类型
"@uni-helper/uni-app-types" // uni-app 组件类型
]
},
// vue 编译器类型,校验标签类型
"vueCompilerOptions": {
// 原配置 experimentalRuntimeMode 已废弃,请升级 Vue - Official 插件至最新版本
"plugins": ["@uni-helper/uni-app-types/volar-plugin"]
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"]
}
tsconfig报错
方法一:加上"ignoreDeprecations":"5.0"后重启
在 TypeScript 5.0 及以上版本中,importsNotUsedAsValues 和 preserveValueImports 选项已被弃用,并将在 TypeScript 5.5 中停止支持。取而代之的是使用 verbatimModuleSyntax 选项
如果希望继续使用旧版本的配置,可以在 tsconfig.json 中添加 ignoreDeprecations 选项,使编译器忽略弃用警告
"ignoreDeprecations":"5.0"
方法二:更新@vue/tsconfig
使用命令查看vue/tsconfig版本
我的版本是0.1.3
pnpm list @vue/tsconfig
升级
pnpm update @vue/tsconfig
允许pages.json和manifest.json允许注释
在uniapp项目中,允许pages.json和manifest.json允许注释
但是vscode默认严格json
只有这两个json文件允许注释
值jsonc,表示允许注释
项目配置(运行到小程序)
微信小程序appid
安装依赖,运行
安装依赖
pnpm i
pnpm dev:mp-weixin
mp表示mini program,微信小程序
导入mp-weixin
自动生成dis目录
编译完成的结果在dis目录下
打开微信小程序,导入mp-weixin
分离窗口
分离窗口,方便查看
安装uni-ui(可以不装)
官网:
pnpm i @dcloudio/uni-ui
配置vite.config.ts
官网提供的是对Vue-cli项目的vue.config.js的配置
import { defineConfig } from "vite";
import uni from "@dcloudio/vite-plugin-uni";
export default defineConfig({
plugins: [uni()],
});
安装sass
官网提供的是对 Vue CLI 项目的说明
Vite 项目中无需手动安装 sass-loader(Vite 内置了对 SASS/SCSS 的支持,底层已处理 loader),只需安装 sass 本体即可
pnpm i sass -D
安装uni-ui组件库
pnpm i @dcloudio/uni-ui
配置easycom完成组件自动导入
开启自动扫描,在components文件夹是否有符合uniapp标准的组件,有就自动导入
但我们通过pnpm包管理器的方式下载,组件在node_modules里
所以这个配置走的是第二个custom正则的规则
^表示开头,用()包裹.*,表示提取出这个组件的名字,()表示提取,提取的内容会把后面的$1替换
("^Xtx(.*)": "@/components/Xtx$1.vue"这一行是之后的项目要用的,官方文档里没有)
// 组件自动引入规则
"easycom": {
// 是否开启自动扫描
"autoscan": true,
// 以正则方式自定义组件匹配规则
"custom": {
// uni-ui 规则如下配置
"^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue"
}
},
运行微信小程序
设置->项目设置->取消勾选过滤无依赖文件
第一次运行时报错了,取消勾选就成功运行了
然后我再次勾选上,之后也成功运行了
不明所以
为uni-ui提供ts类型声明
官网:
uni-ui开发时使用js,没有升级到ts
官方提供的组件库,并没有对应的类型声明文件
有人为uni-ui提供了配套的类型声明文件
安装文件
pnpm i -D @uni-helper/uni-app-types@latest @uni-helper/uni-ui-types@latest
配置tsconfig.json
//tsconfig.json
"@uni-helper/uni-ui-types"
小程序端pinia持久化
官方文档:
配置 | Pinia Plugin Persistedstate
Pinia 用法与 Vue3 项目完全一致,uni-app 项目仅需解决持久化插件兼容性问题
插件默认使用 localStorage 实现持久化,小程序端不兼容,需要替换持久化 API
安装pinia
pnpm install pinia
安装持久化存储插件
pnpm i pinia-plugin-persistedstate
配置
// src/main.ts
import { createSSRApp } from "vue";
import App from "./App.vue";
// 导入pinia实例
import pinia from '@/stores';
export function createApp() {
// 创建vue实例
const app = createSSRApp(App);
// 挂载pinia实例
app.use(pinia);
return {
app,
};
}
// src/stores
import persist from 'pinia-plugin-persistedstate';
import {createPinia} from 'pinia';
// 创建 Pinia 实例
const pinia = createPinia();
// 添加持久化插件
pinia.use(persist);
// 默认导出,给main.ts使用
export default pinia;
// 模块统一导出
export * from './modules/member';
参考
路由
因此,UniApp 提供了自己的路由系统,与标准 vue-router 不兼容
请求工具的封装
拦截器
文档:
uni.addInterceptor(STRING, OBJECT) | uni-app官网
设置请求基地址:
如果首选服务器挂了,换成备用服务器,有基地址设置,只需要改一边就可以了
在项目中用到路径也更简洁
设置超时时间:
默认的超时时间是60s,太长了
添加请求头标识:
项目服务端除了服务于小程序端,也会服务于pc端和app端
后端需要通过标记识别出数据请求的来源,后端就能知道来源哪个端
还有根据不同的端,返回不同的数据
添加token:
用户登录后拿到token,部分接口必须在登录之后,携带token才能访问
请求函数
封装请求函数,借鉴axios(axios返回值是Promise对象,配合async,await,能更方便地获取到请求成功的数据)
uniapp的拦截器没有axios拦截器完善,uniapp的响应拦截器对类型支持并不友好
所以前面的拦截器只完成了请求前的拦截,没有实现响应拦截器,要通过自己封装的请求函数去实现axios响应拦截器做过的业务(响应分为成功、失败)
成功:
在uni.request发完请求之后,后端返回的数据会包裹在res.data里,为了方便使用,直接把数据提取出来
uni.request函数不支持添加类型,在自己封装的函数里添加泛型,通过泛型确定使用时的具体类型
获取数据失败
success()只有服务器有响应,都会走到这里面
如果服务器挂了,或者网络出错,才会走到fail()响应失败
如果没有token,但调用了一个需要携带token才能访问的接口,会走到success()响应成功里面。因为服务器有响应,响应的结果只不过是token失败
对于我们也页面中使用,业务理解会有差异
所以借鉴axios
完整代码
ts版(utils/http.ts)
// 请求基地址
const baseURL = 'http://localhost:8080'
// 拦截器配置
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 请求头标识
// 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)
/**
* 请求函数
* @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 对象,resolve标记成功,reject标记失败
return new Promise<Data<T>>((resolve, reject) => {
uni.request({
...options,
// 2. 响应成功
success(res) {
// 状态码 2xx,参考 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)
},
})
})
}
js版
// 请求基地址
const baseURL = 'http://localhost:8080'
// 拦截器配置
const httpInterceptor = {
// 拦截前触发
invoke(options) {
// 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 请求头标识
// 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)
/**
* 请求函数
* @param UniApp.RequestOptions
* @returns Promise
* 1. 返回 Promise 对象,用于处理返回值类型
* 2. 获取数据成功
* 2.1 提取核心数据 res.data
* 2.2 添加类型,支持泛型
* 3. 获取数据失败
* 3.1 401错误 -> 清理用户信息,跳转到登录页
* 3.2 其他错误 -> 根据后端错误信息轻提示
* 3.3 网络错误 -> 提示用户换网络
*/
// 2.2 添加类型,支持泛型
export const http = (options) => {
// 1. 返回 Promise 对象,resolve标记成功,reject标记失败
return new Promise((resolve, reject) => {
uni.request({
...options,
// 2. 响应成功
success(res) {
// 状态码 2xx,参考 axios 的设计
if (res.statusCode >= 200 && res.statusCode < 300) {
// 2.1 提取核心数据 res.data
resolve(res.data)
} 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.msg || '请求错误',
})
reject(res)
}
},
// 响应失败
fail(err) {
uni.showToast({
icon: 'none',
title: '网络错误,换个网络试试',
})
reject(err)
},
})
})
}
统一代码风格、git工作流规范
更多推荐
所有评论(0)