目录
[安装 uni-ui 组件库](#安装 uni-ui 组件库)
[解决 标签 错误](#解决 标签 错误)
[安装 uview-plus 组件库](#安装 uview-plus 组件库)
[Pinia 配置](#Pinia 配置)
[pinia 依赖安装](#pinia 依赖安装)
[pinia 持久化配置](#pinia 持久化配置)
创建uni-app项目
npx degit dcloudio/uni-preset-vue#vite-ts new-project-name
new-project-name:这里更改一下为自己的项目名称

基础架构
安装 uni-ui 组件库
官网:uni-app官网
通过官网说明文档相对应的搭建
pnpm i @dcloudio/uni-ui
安装sass依赖
javascript
pnpm i [email protected] -D
pnpm i [email protected] -D
easycom配置组件自动导入
javascript
// pages.json
{
// uniapp 配置文件
"easycom": {
"autoscan": true,
// 以正则方式自定义组件匹配规则
"custom": {
// uni-ui 规则如下配置
"^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue",
// 以serive开头的组件,在 components 文件夹中查找引入(需要重启服务器)
//"^serive(.*)": "@/components/serive/serive$1.vue"
}
},
// 其他内容
pages:[
// ...
]
}
配置view等标签高亮声明
javascript
pnpm i -D miniprogram-api-typings @uni-helper/uni-app-types
安装成功后复制对应的依赖包名放置在 tsconfig.json中的type字段
同时加上 vueCompilerOptions 配置
javascript
"vueCompilerOptions": {
"experimentalRuntimeMode": "runtime-uni-app"
},


配置uni-ui组件类型声明
组件声明类型依赖官网(注意:如果缓慢需要魔法):@uni-helper/uni-ui-types - npm
javascript
pnpm i -D @uni-helper/uni-ui-types
安装成功后复制对应的依赖包名放置在 tsconfig.json中的type字段
解决 标签 错误
关于tsconfig.json中提示报错
选项"importsNotUsedAsValues"已删除。请从配置中删除它。请改用"verbatimModuleSyntax"

主要是我们使用的tsconfig版本太低了
步骤1:
更新@vue/tsconfig版本,在package.json文件中找到@vue/tsconfig,把版本号改为0.7.0

"@vue/tsconfig": "^0.7.0",
随后运行pnpm 更新依赖
pnpm install
最后更改 tsconfig 地址
"extends": "@vue/tsconfig/tsconfig.dom.json",

这样就不报错了
关于非原生标签错误(看运气)
当我们发现正常标签报错

更改我们的 tsconfig.json,参考一下我下面的配置
javascript
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"compilerOptions": {
"sourceMap": true,
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
},
"lib": ["esnext", "dom"],
// 类型声明文件
"types": [
"@uni-helper/uni-ui-types", // uni-ui 组件类型
"@dcloudio/types", // uni-app API 类型
"miniprogram-api-typings", // 原生微信小程序类型
"@uni-helper/uni-app-types" // uni-app 组件类型
]
},
// vue 编译器类型,校验标签类型
"vueCompilerOptions": {
//新增加的配置 experimentalRuntimeMode 已废弃,现调整为 nativeTags,请升级 Volar 插件至最新版本
"nativeTags": ["block", "component", "template", "slot"],
// experimentalRuntimeMode 已废弃,请升级 Vue - Official 插件至最新版本
"plugins": ["@uni-helper/uni-app-types/volar-plugin"]
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"]
}
如果还是爆红,多次尝试重启 Vue - Official 插件,以及重启vscode,我就是这样不明不白的改好了。

安装 uview-plus 组件库
执行命令安装 uview 依赖
TypeScript
pnpm install uview-plus
挂载使用
TypeScript
import uviewPlus from 'uview-plus'
app.use(uviewPlus);
由于uview-plus 不是原生组件,所以我们要自定义声明类型,这样就不会爆红波浪线了

uview-plus.d.ts
TypeScript
// src/types/uview-plus.d.ts
declare module 'uview-plus' {
import { Plugin } from 'vue';
const install: Plugin;
export default install;
}
全局样式配置
TypeScript
/* src\uni.scss */
@import 'uview-plus/theme.scss';
TypeScript
// src\App.vue
<style lang="scss">
/* 注意要写在第一行,同时给style标签加入lang="scss"属性 */
@import "uview-plus/index.scss";
</style>
自动导入
TypeScript
// pages.json
{
"easycom": {
"autoscan": true,
// 注意一定要放在custom里,否则无效,https://ask.dcloud.net.cn/question/131175
"custom": {
"^u--(.*)": "@/uni_modules/uview-plus/components/u-$1/u-$1.vue",
"^up-(.*)": "@/uni_modules/uview-plus/components/u-$1/u-$1.vue",
"^u-([^-].*)": "@/uni_modules/uview-plus/components/u-$1/u-$1.vue"
}
},
// 此为本身已有的内容
"pages": [
// ......
]
}
Pinia 配置
Pinia官网(注意:如果缓慢需要魔法):Pinia | The intuitive store for Vue.js
pinia 依赖安装
执行命令安装 Pinia 依赖
pnpm install pinia
分包创建目录

index.ts配置pinia
TypeScript
import { createPinia } from "pinia";
const pinia = createPinia(); // 创建 Pinia 实例
// 默认导出,给 main.ts 使用
export default pinia;
// 模块统一导出
export * from "./modules/counter";
main.ts 使用 pinia
TypeScript
import { createSSRApp } from "vue";
import App from "./App.vue";
import pinia from "./stores";
export function createApp() {
const app = createSSRApp(App);
app.use(pinia); // 挂载pinia
return {
app,
};
}
测试
counter.ts
TypeScript
import { defineStore } from "pinia";
import { computed, ref } from "vue";
export const useCounterStore = defineStore("counter", () => {
// 声明 数据类型
const count = ref(0);
// 定义 计数器方法
const increment = () => {
count.value++;
}
// 声明基于数据派生的计算属性
const double = computed(() => {
return count.value * 2;
})
// 返回 计数器数据、方法、计算属性
return {
count,
double,
increment,
}
},
);
Test.vue
html
<script lang="ts" setup>
import { useCounterStore } from '@/stores';
import { storeToRefs } from 'pinia';
const counter = useCounterStore();
const { count } = storeToRefs(counter);
const {double} = storeToRefs(counter)
const {increment} = counter
</script>
<template>
<div class="Test">
<uni-card>
<text>计数:{{ count }}</text>
<br>
<text>双倍:{{ double }}</text>
</uni-card>
<up-button @tap="increment">+</up-button>
</div>
</template>
<style lang="scss" scoped></style>

pinia 持久化配置
执行命令安装 pinia-plugin-persistedstate 依赖
html
pnpm i pinia-plugin-persistedstate
index.ts配置持久化
html
import { createPinia } from "pinia";
import piniaPluginPersistedstate from "pinia-plugin-persistedstate";
const pinia = createPinia(); // 创建 Pinia 实例
pinia.use(piniaPluginPersistedstate); // 使用 pinia-plugin-persistedstate 持久化配置
// 默认导出,给 main.ts 使用
export default pinia;
// 模块统一导出
export * from "./modules/counter";
配置持久化 counter.ts
TypeScript
import { defineStore} from "pinia";
import { computed, ref } from "vue";
export const useCounterStore = defineStore("counter", () => {
// 声明 数据类型
const count = ref(100);
// 定义 计数器方法
const increment = () => {
count.value++;
console.log('增加了:',count.value);
}
// 声明基于数据派生的计算属性
const double = computed(() => {
return count.value * 2;
})
// 返回 计数器数据、方法、计算属性
return {
count,
double,
increment,
}
},
// 配置项
{
// 网页端的 持久化配置
// persist: true
// 移动端的 持久化配置
// persist: {
// storage: localStorage,
// key: 'count',
// }
// 小程序的 持久化配置, 同时兼容大部分浏览器H5
persist: {
storage: {
getItem(key) {
return uni.getStorageSync(key);
},
setItem(key, value) {
return uni.setStorageSync(key, value);
},
}
}
}
);
报错 X [ERROR] Could not resolve "destr"

解决方法:
降低 持久化依赖的版本
html
"pinia-plugin-persistedstate": "^3.2.3",
测试效果,成功持久化存储到本地

请求配置
添加拦截器
TypeScript
// src/utils/http.ts
import { useUserStore } from "@/stores/modules/user"
// 基础的请求地址
const baseUrl = "http://localhost:3000"
// 拦截器配置
const httpInterceptor = {
// 拦截前触发
invoke(options: UniApp.RequestOptions) {
// 1、非 http 开头需拼接地址
if (!options.url.startsWith('http')) {
options.url = baseUrl + options.url
}
// 2、请求超时,如果没有配置则默认 60s
options.timeout = options.timeout || 10000
// 3、添加小程序端请求头标识
options.header = options.header || {
...options.header, // 如果请求设置方法前配置了 header 则保留之前配置过的
'source-client': 'uniapp'
}
// 4、添加 token 请求标识
const userStore = useUserStore();
// 这里 ?. 表示 可选链操作符,如果 userStore.userInfo 为空,则 token 为 undefined
const token = userStore.userInfo?.token;
if (token) {
options.header['Authorization'] = 'Bearer ' + token;
}
}
}
// 添加拦截器,这里共用一份拦截器
uni.addInterceptor('request', httpInterceptor)
uni.addInterceptor('uploadFile', httpInterceptor)
添加封装请求函数
TypeScript
// src/utils/http.ts
// ..... 接着添加
// 2.3 指定响应数据结构
interface Data<T>{
code: number,
msg: string,
result: T
}
// 2.2 添加类型,支持泛型
const http = <T>(options: UniApp.RequestOptions) => {
// 返回 Promise 对象
return new Promise<Data<T>>((resolve, reject) => {
uni.request({
...options,
// 2、请求成功
success: (res) => {
// 2.1 提取核心数据 res.data
// 类型断言指定数据类型
resolve(res.data as Data<T>)
},
fail: (err: UniApp.GeneralCallbackResult) => {
reject(err)
}
})
})
}
添加响应拦截
TypeScript
// src/utils/http.ts
// ..... 接着添加
// 2.2 添加类型,支持泛型
const http = <T>(options: UniApp.RequestOptions) => {
// 返回 Promise 对象
return new Promise<Data<T>>((resolve, reject) => {
uni.request({
...options,
// 2、请求成功
success: (res) => {
// 2.1 提取核心数据 res.data
// 状态码 2xx,axios 就是这样设计的
if (res.statusCode >= 200 && res.statusCode < 300) {
// 类型断言指定数据类型
resolve(res.data as Data<T>)
} else if (res.statusCode === 401) {
// 401 错误 -> 清理用户信息,跳转登录页
const userStore = useUserStore();
userStore.clearUserInfo();
uni.navigateTo({ // 跳转登录页
url: '/pages/login/login'
});
reject(res);
} else {
// 其他错误 --> 根据后端错误信息轻提示
uni.showToast({
title: (res.data as Data<T>).msg || '请求错误',
icon: 'none'
});
reject(res);
}
},
// 响应失败
fail: (err: UniApp.GeneralCallbackResult) => {
uni.showToast({
title:'网络请求错误,请尝试切换网络',
icon: 'none'
});
reject(err)
}
})
})
}
--------------------------------- 持续更新中---------------------------------