准备工作
使用vue-cli创建,脱离HBuilderX(真的很难用)
uni-app这里选择vue3 + typescript的版本
先把空壳拉下来npx degit dcloudio/uni-preset-vue#vite-ts my-vue3-project
或者通过官网的gitee下载点击下载
1. UI库选择
名称 | 特点 | 缺点 |
---|---|---|
uni-ui | 高性能,全端覆盖,支持nvue(uniapp官方出品) | 丑,封装的太死 |
ThorUI | 组件丰富,全端覆盖(比uni-ui好看) | 不支持nvue |
uview-plus3.0 | 组件丰富,支持nvue(比uni-ui好看) | 没用过,用的少,不做评价 |
如果你对ui库的需求不高,大多数都需要手写样式的话(产品要求的100%还原设计图那种),我建议组件库都不需要使用或者使用uni-ui即可
这里选择使用uni-ui作为项目的ui库(也可以自己更换其他的,操作是一样的)
js
pnpm install @dcloudio/uni-ui
uni-ui符合easycom规范,添加到src/pages.json即可实现自动引入(easycom规范是什么东西?点击查看)
js
// src/pages.json
{
"pages": [
// 你的页面
],
// 添加以下代码(实现自动引入uni-ui所有组件)
"easycom": {
"custom": {
"^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue"
}
}
}
如果需要改uni-ui的主题色,或者文字颜色什么的,直接改src/uni.scss,因为uni-ui用的都是里面的变量(改这个文件需要重新编译才可以生效)
2. 组件类型提示
相信大家在写uni-app的时候都有这样的场景
- 写个banner轮播图,如何改衔接滑动来着?(打开浏览器找文档)
- 记得组件的某个属性几个字母,也无法拼全和确定自己写的正不正确?(打开浏览器找文档)
以上场景来源于组件没有类型提示而造成的困扰。而 uni-app 官方对于 typeScript 支持只有 @dcloudio/types
,它提供了脚本部分的 typeScript 支持,但组件的 TypeScript 一直都没有。此时有一个为 uni-app 打造的 typeScript 支持库出现了@uni-helper/uni-typed
我们只需要关注这几个子包
- @uni-helper/uni-app-types(为 uni-app 组件提供 TypeScript 类型)
- @uni-helper/uni-cloud-types(为 uni-cloud 组件提供 TypeScript 类型)
- @uni-helper/uni-ui-types(为 uni-ui 组件提供 TypeScript 类型)
- @uni-helper/uni-types(以上三者的集合)
我现在的目标:需要uni-app的内置组件和uni-ui的组件拥有类型提示
我选择@uni-helper/uni-app-types
和@uni-helper/uni-ui-types
进行安装(如果使用uni-cloud和uni-ui的话,可直接安装@uni-helper/uni-types就好了)
js
pnpm install @uni-helper/uni-app-types @uni-helper/uni-ui-types
然后打开tsconfig.json
js
{
"compilerOptions": {
// 你其他配置
// ...
"types": [
// 为 vite 提供 TypeScript 类型
"vite/client",
// 为 uni-app API 提供 TypeScript 类型
"@dcloudio/types",
// 为 uni-app 组件提供 TypeScript 类型
"@uni-helper/uni-app-types",
// 为 uni-ui 组件提供 TypeScript 类型
"@uni-helper/uni-ui-types"
]
},
"vueCompilerOptions": {
// Vue - Official 调整解析行为
"plugins": [
"@uni-helper/uni-app-types/volar-plugin",
"@uni-helper/uni-ui-types/volar-plugin"
]
}
}
重启vscode后,此时组件已经变成绿色,证明生效啦。鼠标放上去,描述出现,点击查看组件文档,直接跳转,领导再也不会说你效率低了
然后你输入几个字母,看到提示后,眼泪流了下来,原来swper的衔接活动的属性是circular
搬砖佬:不好意思,我连几个字母都记不住,还不是得打开浏览器去找?
我:也不用,按住ctrl鼠标左键点击组件找到组件props类型更快哦
3. ESLint9
在我认为,eslint在前端应该是必不可少的东西,它能很好的矫正你的代码,以及提前发现你可能没发现的错误语法,使用eslint会使得一定的效率提升上去。
eslint9相比于之前的版本改动很大,掘友应该也看腻了,废话不多说,直接开始。
- eslint(核心包)
- eslint-plugin-vue(vue语法支持)
- @vue/eslint-config-typescript(vue ts支持)
- @vue/eslint-config-prettier(vue prettier支持)
- vite-plugin-eslint(vite使用eslint校验代码)
js
pnpm install eslint eslint-plugin-vue @vue/eslint-config-typescript @vue/eslint-config-prettier vite-plugin-eslint
根目录新建eslint.config.mjs(eslint用于处理代码语法问题)
js
import pluginVue from 'eslint-plugin-vue'
import { defineConfigWithVueTs, vueTsConfigs } from '@vue/eslint-config-typescript'
import prettierConfig from '@vue/eslint-config-prettier'
export default defineConfigWithVueTs(
pluginVue.configs['flat/recommended'],
vueTsConfigs.recommended,
prettierConfig,
[
{
rules: {
// 在这里改写覆盖规则
// ...
}
}
]
)
根目录新建prettier.config.mjs(prettier用于处理代码格式问题)
js
export default {
singleQuote: true, // 使用单引号
semi: false, // 行尾分号
printWidth: 100, // 每行代码最大宽度
trailingComma: 'none', // 尾随逗号
endOfLine: 'auto' // 行尾序列
}
配置vite.config.ts
js
import { defineConfig } from 'vite'
import uni from '@dcloudio/vite-plugin-uni'
import EslintPlugin from 'vite-plugin-eslint'
export default defineConfig({
plugins: [
uni(),
EslintPlugin()
]
})
重启vscode(代码问题一目了然)
鼠标右键编辑区域,选择使用...格式化文档,然后选择ESlint(设置之后,默认快捷键alt+shift+F即可格式化代码)
搬砖佬:让我团队每个人都这样设置一遍太麻烦了,有没有默认就帮他们设置好呢?(有的,在项目里新建.vscode/settings.json文件)
js
{
// 其他配置
// ...
// 默认格式化eslint
"[vue]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
},
"[javascript]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
},
"[typescript]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
},
// 保存自动格式化
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
}
}
4. 自动导入
问题一:还有就是请求做了封装,但是每次使用都import吗?这也太累了,用provide/inject来使用请求,但是每个页面都inject也很麻烦,有没有什么好方法呢?
问题二:vue和uni-app的生命周期以及各种函数背得滚瓜烂熟,每次都引入属实降低效率,应该怎么进行自动引入呢?
先说问题一的两种解决方案,一种是直接挂到uni对象上面去,另一种是使用unplugin-auto-import
自动导入
方案一(挂到uni对象上-不推荐)
js
// src/main.ts
import request from '@/utils/request'
uni.$http = request
搬砖佬:使用是可以使用了,但是没类型提示,很难受啊!
我:别着急,往下看,找到/src/env.d.ts
js
/// <reference types="vite/client" />
declare module '*.vue' {
import { DefineComponent } from 'vue'
import request from '@/utils/request'
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
const component: DefineComponent<{}, {}, any>
export default component
global {
// 给Uni对象添加属性
interface Uni {
$http: typeof request
}
}
}
搬砖佬:是可以了,但是为什么说这种方案不推荐呢?
我:因为这种破坏了uni的对象,万一以后需要升级uniapp版本,并且出了个新的属性和你挂上去的一样,就不好维护了。来看方案二
方案二(自动导入)
js
pnpm install unplugin-auto-import
打开vite.config.ts
js
import { defineConfig } from 'vite'
import uni from '@dcloudio/vite-plugin-uni'
import EslintPlugin from 'vite-plugin-eslint'
import AutoImport from 'unplugin-auto-import/vite'
export default defineConfig({
plugins: [
uni(),
EslintPlugin(),
AutoImport({
imports: [{ '@/utils/request.ts': [['default', 'request']] }]
})
]
})
我:现在,启动项目后会产生auto-imports.d.ts文件,里面就会包含你的request对象。你可以在任何地方直接使用request了。
搬砖佬:没生效啊?
我:查看你的tsconfig.json文件,如果写了include,那需要把auto-imports.d.ts加进去。建议删除include,这样的话会自动排除node_modules的检查,直接检查整个项目的文件
搬砖佬:可以了,也有类型提示,舒服的一匹。
我:说回第二个问题,直接在imports里面添加即可,自带了vue和uni-app的导入。
js
import { defineConfig } from 'vite'
import uni from '@dcloudio/vite-plugin-uni'
import EslintPlugin from 'vite-plugin-eslint'
import AutoImport from 'unplugin-auto-import/vite'
export default defineConfig({
plugins: [
uni(),
EslintPlugin(),
AutoImport({
imports: [{ 'vue', 'uni-app', '@/utils/request.ts': [['default', 'request']] }]
})
]
})
5. unocss(可选)
这玩意怎么说呢,有人喜欢有人恨,但是也出个配置的教程吧,也许能帮的上别人呢。
- unocss(核心包)
- unocss-preset-weapp(用于兼容小程序)
- @unocss/transformer-directives(支持@apply)
- @unocss/transformer-variant-group(支持组写法,如b-(1px solid red))
js
pnpm install unocss unocss-preset-weapp @unocss/transformer-directives @unocss/transformer-variant-group
根目录新建uno.config.ts文件
js
import { defineConfig } from 'unocss'
import presetWeapp from 'unocss-preset-weapp'
import transformerVariantGroup from '@unocss/transformer-variant-group'
import transformerDirectives from '@unocss/transformer-directives'
import { extractorAttributify, transformerClass } from 'unocss-preset-weapp/transformer'
const { presetWeappAttributify, transformerAttributify } = extractorAttributify()
export default defineConfig({
presets: [presetWeapp() as any, presetWeappAttributify()],
transformers: [
transformerVariantGroup(),
transformerDirectives(),
transformerAttributify() as any,
transformerClass()
],
theme: {
// 自定义颜色
colors: {
primary: '#26A79F'
}
},
// 自定义快捷样式
shortcuts: {
'flex-col': 'flex flex-col',
'flex-center': 'flex items-center justify-center',
'flex-center-x': 'flex items-center',
'flex-center-y': 'flex justify-center',
'flex-center-between': 'flex-center-x justify-between',
'flex-center-around': 'flex-center-x justify-around',
'flex-col-center': 'flex-col items-center justify-center',
'flex-col-between': 'flex-col justify-between',
'flex-col-around': 'flex-col justify-around',
'flex-col-center-x': 'flex-col justify-center',
'flex-col-center-y': 'flex-col items-center'
},
// 自定义规则
rules: [
// 格式化成rpx
[
/^(m|mt|mb|ml|mr|mx|my|p|pt|pb|pl|pr|px|py|rd|lh)-(\d+)$/,
([, key, value]) => {
const keys = {
m: 'margin',
mt: 'margin-top',
mb: 'margin-bottom',
ml: 'margin-left',
mr: 'margin-right',
mx: 'margin-left,margin-right',
my: 'margin-top,margin-bottom',
p: 'padding',
pt: 'padding-top',
pb: 'padding-bottom',
pl: 'padding-left',
pr: 'padding-right',
px: 'padding-left,padding-right',
py: 'padding-top,padding-bottom',
rd: 'border-radius',
lh: 'line-height'
}
return keys[key].split(',').reduce((acc, k) => ({ ...acc, [k]: `${value}rpx` }), {})
}
],
// bottom安全区域距离底部边界的距离
[
/^b-safe-(.*)$/,
([, value]) => ({
bottom: `calc(${Number(value) ? `${value}rpx` : value} + env(safe-area-inset-bottom))`
})
],
// padding-bottom安全区域距离底部边界的距离
[
/^pb-safe-(.*)$/,
([, value]) => ({
'padding-bottom': `calc(${Number(value) ? `${value}rpx` : value} + env(safe-area-inset-bottom))`
})
],
// 文字限制行数
[
/^text-row-(\d+)$/,
([, value]) => ({
display: '-webkit-box',
overflow: 'hidden',
'text-overflow': 'ellipsis',
'-webkit-box-orient': 'vertical',
'-webkit-line-clamp': value
})
]
]
})
安装插件
重启vscode后看到虚线效果(鼠标放上去看编译后的样式)
6. 精简项目(可选)
uni-app一堆依赖,但是我只开发微信小程序而已,却需要完全安装,也不知道哪个需要哪个不需要,看又看不懂,学又学不会,难搞
先贴个刚从官网拉下来的package.json
js
{
"name": "uni-preset-vue",
"version": "0.0.0",
"scripts": {
"dev:custom": "uni -p",
"dev:h5": "uni",
"dev:h5:ssr": "uni --ssr",
"dev:mp-alipay": "uni -p mp-alipay",
"dev:mp-baidu": "uni -p mp-baidu",
"dev:mp-jd": "uni -p mp-jd",
"dev:mp-kuaishou": "uni -p mp-kuaishou",
"dev:mp-lark": "uni -p mp-lark",
"dev:mp-qq": "uni -p mp-qq",
"dev:mp-toutiao": "uni -p mp-toutiao",
"dev:mp-weixin": "uni -p mp-weixin",
"dev:mp-xhs": "uni -p mp-xhs",
"dev:quickapp-webview": "uni -p quickapp-webview",
"dev:quickapp-webview-huawei": "uni -p quickapp-webview-huawei",
"dev:quickapp-webview-union": "uni -p quickapp-webview-union",
"build:custom": "uni build -p",
"build:h5": "uni build",
"build:h5:ssr": "uni build --ssr",
"build:mp-alipay": "uni build -p mp-alipay",
"build:mp-baidu": "uni build -p mp-baidu",
"build:mp-jd": "uni build -p mp-jd",
"build:mp-kuaishou": "uni build -p mp-kuaishou",
"build:mp-lark": "uni build -p mp-lark",
"build:mp-qq": "uni build -p mp-qq",
"build:mp-toutiao": "uni build -p mp-toutiao",
"build:mp-weixin": "uni build -p mp-weixin",
"build:mp-xhs": "uni build -p mp-xhs",
"build:quickapp-webview": "uni build -p quickapp-webview",
"build:quickapp-webview-huawei": "uni build -p quickapp-webview-huawei",
"build:quickapp-webview-union": "uni build -p quickapp-webview-union",
"type-check": "vue-tsc --noEmit"
},
"dependencies": {
"@dcloudio/uni-app": "3.0.0-4030620241128001", // 核心包(不能删)
"@dcloudio/uni-app-harmony": "3.0.0-4030620241128001", // 鸿蒙
"@dcloudio/uni-app-plus": "3.0.0-4030620241128001", // APP
"@dcloudio/uni-components": "3.0.0-4030620241128001", // uni组件(不能删)
"@dcloudio/uni-h5": "3.0.0-4030620241128001", // h5
"@dcloudio/uni-mp-alipay": "3.0.0-4030620241128001", // 支付宝
"@dcloudio/uni-mp-baidu": "3.0.0-4030620241128001", // 百度
"@dcloudio/uni-mp-jd": "3.0.0-4030620241128001", // 京东
"@dcloudio/uni-mp-kuaishou": "3.0.0-4030620241128001", // 快手
"@dcloudio/uni-mp-lark": "3.0.0-4030620241128001", // 飞书
"@dcloudio/uni-mp-qq": "3.0.0-4030620241128001", // QQ
"@dcloudio/uni-mp-toutiao": "3.0.0-4030620241128001", // 头条
"@dcloudio/uni-mp-weixin": "3.0.0-4030620241128001", // 微信
"@dcloudio/uni-mp-xhs": "3.0.0-4030620241128001", // 小红书
"@dcloudio/uni-quickapp-webview": "3.0.0-4030620241128001", // 快应用
"vue": "^3.4.21",
"vue-i18n": "^9.1.9" // 多语言
},
"devDependencies": {
"@dcloudio/types": "^3.4.8", // uni-app类型定义
"@dcloudio/uni-automator": "3.0.0-4030620241128001", // 自动化测试
"@dcloudio/uni-cli-shared": "3.0.0-4030620241128001", // 跨平台编译
"@dcloudio/uni-stacktracey": "3.0.0-4030620241128001", // 错误调试工具
"@dcloudio/vite-plugin-uni": "3.0.0-4030620241128001", // uni-app编译插件
"@vue/tsconfig": "^0.1.3",
"@vue/runtime-core": "^3.4.21",
"typescript": "^4.9.4",
"vite": "5.2.8",
"vue-tsc": "^1.0.24" // typescript类型检查
}
}
如果只开发微信小程序,下面是精简后的package.json
js
{
"name": "uni-preset-vue",
"version": "0.0.0",
"scripts": {
"dev": "uni -p mp-weixin",
"build": "uni build -p mp-weixin"
},
"dependencies": {
"@dcloudio/uni-app": "3.0.0-4030620241128001",
"@dcloudio/uni-components": "3.0.0-4030620241128001",
"@dcloudio/uni-mp-weixin": "3.0.0-4030620241128001",
"vue": "^3.4.21"
},
"devDependencies": {
"@dcloudio/types": "^3.4.8",
"@dcloudio/uni-automator": "3.0.0-4030620241128001",
"@dcloudio/uni-cli-shared": "3.0.0-4030620241128001",
"@dcloudio/uni-stacktracey": "3.0.0-4030620241128001",
"@dcloudio/vite-plugin-uni": "3.0.0-4030620241128001",
"@vue/tsconfig": "^0.1.3",
"@vue/runtime-core": "^3.4.21",
"typescript": "^4.9.4",
"vite": "5.2.8"
}
}