系列文章
- 【unibest】uniapp + vue3 超实用模板
- 【unibest】uniapp + vue3 超实用模板(续)(本文)
- 【unibest】uniapp + vue3 超实用模板(终)
- 【unibest】uniapp + vue3 超实用模板(番外篇)
6、引入 unocss
pnpm add -D @unocss/preset-uno unocss-applet
然后配置 unocss.config.ts
// uno.config.ts
import {
Preset,
defineConfig,
presetAttributify,
presetIcons,
transformerDirectives,
transformerVariantGroup,
} from 'unocss'
import {
presetApplet,
presetRemRpx,
transformerApplet,
transformerAttributify,
} from 'unocss-applet'
const isH5 = process.env?.UNI_PLATFORM === 'h5'
const isMp = process.env?.UNI_PLATFORM?.startsWith('mp') ?? false
const presets: Preset[] = []
if (!isMp) {
/**
* you can add `presetAttributify()` here to enable unocss attributify mode prompt
* although preset is not working for applet, but will generate useless css
* 为了不生产无用的css,要过滤掉 applet
*/
// 支持css class属性化,eg: `<button bg="blue-400 hover:blue-500 dark:blue-500 dark:hover:blue-600" text="sm white">attributify Button</button>`
presets.push(presetAttributify())
}
export default defineConfig({
presets: [
presetApplet({ enable: !isH5 }),
presetRemRpx(),
...presets,
// 支持图标,需要搭配图标库,eg: @iconify-json/carbon, 使用 `<button class="i-carbon-sun dark:i-carbon-moon" />`
presetIcons({
scale: 1.2,
warn: true,
extraProperties: {
display: 'inline-block',
'vertical-align': 'middle',
},
}),
],
/**
* 自定义快捷语句
* @see https://github.com/unocss/unocss#shortcuts
*/
shortcuts: [['center', 'flex justify-center items-center']],
transformers: [
// 启用 @apply 功能
transformerDirectives(),
// 启用 () 分组功能
// 支持css class组合,eg: `<div class="hover:(bg-gray-400 font-medium) font-(light mono)">测试 unocss</div>`
transformerVariantGroup(),
// Don't change the following order
transformerAttributify({
// 解决与第三方框架样式冲突问题
prefixedOnly: true,
prefix: 'fg',
}),
transformerApplet(),
],
rules: [
[
'p-safe',
{
padding:
'env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left)',
},
],
['pt-safe', { 'padding-top': 'env(safe-area-inset-top)' }],
['pb-safe', { 'padding-bottom': 'env(safe-area-inset-bottom)' }],
],
})
/**
* 最终这一套组合下来会得到:
* mp 里面:mt-4 => margin-top: 32rpx
* h5 里面:mt-4 => margin-top: 1rem
*/
到这里还没完,页面上写 class="mt-4"
还不生效,接着做下面的动作:
src/main.ts
增加import 'virtual:uno.css'
。- 在
vite.config.ts
文件写入:
import UnoCSS from 'unocss/vite'
// 其他配置省略
plugins: [UnoCSS()],
8、引入 vite-plugin-uni-pages
在 Vite 驱动的 uni-app 上使用基于文件的路由系统。
8-1 安装 @uni-helper/vite-plugin-uni-pages
pnpm i -D @uni-helper/vite-plugin-uni-pages
8-2 配置vite.config.ts
// vite.config.ts
import { defineConfig } from 'vite'
import Uni from '@dcloudio/vite-plugin-uni'
import UniPages from '@uni-helper/vite-plugin-uni-pages'
// It is recommended to put it in front of Uni
export default defineConfig({
plugins: [UniPages(), Uni()],
})
8-3 配置 pages.config.ts
// pages.config.ts
import { defineUniPages } from '@uni-helper/vite-plugin-uni-pages'
export default defineUniPages({
// 你也可以定义 pages 字段,它具有最高的优先级。
pages: [],
globalStyle: {
navigationBarTextStyle: 'black',
navigationBarTitleText: '@uni-helper',
},
})
8-4 使用 route 标签配置路由信息
通过 pnpm dev:h5
发现 pages.json
被重写了。
此时可以在页面上(仅限src/pages里面的页面)增加 route block 来配置,如:
以后每个页面”要不要导航栏,标题要怎么写,标题样式要怎样“都可以在这里设置了,再也不用来回横切了,爽歪歪!
9、vite-plugin-uni-layouts
考虑到我们可能会有多套布局,tabbar页面,非tabbar页面,通屏页面,非通屏页面。对于通屏页面,需要自己实现导航栏,同时还要刘海的情况。我们不用在每个页面都引入某个类似布局的组件,这样太浪费生产力了,我们通过 vite-plugin-uni-layouts
可以声明式地设定使用哪个布局,爽歪歪。
9-1 安装 @uni-helper/vite-plugin-uni-layouts
pnpm i -D @uni-helper/vite-plugin-uni-layouts
9-2 配置vite.config.ts
// vite.config.ts
import { defineConfig } from 'vite'
import Uni from '@dcloudio/vite-plugin-uni'
import UniPages from '@uni-helper/vite-plugin-uni-pages'
import UniLayouts from '@uni-helper/vite-plugin-uni-layouts'
// It is recommended to put it in front of Uni
export default defineConfig({
plugins: [UniPages(), UniLayouts(), Uni()],
})
9-3 在 src/layouts 里面创建布局
9-4 使用layout
在页面上的route-block增加 layout 属性,设置想用的 layout,可选值是所有的 src/layouts里面的文件名,我这里是 "default"|"home".
重新运行,就可以看到效果了。
10、request 请求拦截器
10-1 先写好 store, 请求需要使用其中的token
src/store/user.ts
// src/store/user.ts
import { defineStore } from 'pinia'
import { ref } from 'vue'
import { UserInfo } from '../typings'
export const useUserStore = defineStore(
'user',
() => {
const userInfo = ref<UserInfo>()
const setUserInfo = (val: UserInfo) => {
userInfo.value = val
}
const clearUserInfo = () => {
userInfo.value = undefined
}
return {
userInfo,
setUserInfo,
clearUserInfo,
}
},
{
persist: true,
},
)
src/store/index.ts
// src/store/index.ts
import { createPinia } from 'pinia'
import { createPersistedState } from 'pinia-plugin-persistedstate' // 数据持久化
const store = createPinia()
store.use(
createPersistedState({
storage: {
getItem: uni.getStorageSync,
setItem: uni.setStorageSync,
},
}),
)
export default store
// 模块统一导出
export * from './user'
export * from './count'
10-2 请求拦截,支持设定返回类型
// src/utils/http.ts
/* eslint-disable no-param-reassign */
import { useUserStore } from '@/store'
import { UserInfo } from '@/typings'
const userStore = useUserStore()
type Data<T> = {
code: number
msg: string
result: T
}
// 请求基地址
const baseURL = 'http://localhost:5565/api'
// 拦截器配置
const httpInterceptor = {
// 拦截前触发
invoke(options: UniApp.RequestOptions) {
// 1. 非 http 开头需拼接地址
if (!options.url.startsWith('http')) {
options.url = baseURL + options.url
}
// 2. 请求超时
options.timeout = 10000 // 10s
// 3. 添加小程序端请求头标识
options.header = {
platform: 'mp-weixin', // 可选值与 uniapp 定义的平台一致,告诉后台来源
...options.header,
}
// 4. 添加 token 请求头标识
const { token } = userStore.userInfo as unknown as UserInfo
if (token) {
options.header.Authorization = `Bearer ${token}`
}
},
}
// 拦截 request 请求
uni.addInterceptor('request', httpInterceptor)
// 拦截 uploadFile 文件上传
uni.addInterceptor('uploadFile', httpInterceptor)
export const http = <T>(options: UniApp.RequestOptions) => {
// 1. 返回 Promise 对象
return new Promise<Data<T>>((resolve, reject) => {
uni.request({
...options,
// 响应成功
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错误 -> 清理用户信息,跳转到登录页
userStore.clearUserInfo()
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)
},
})
})
}
export default http
注意:上面代码设定,如果返回
401
则去/pages/login/login
也,请根据需要添加该页面或修改逻辑。
10-3 使用requst,可设定返回类型
const handleRequest = () => {
const res = http<UserItem[]>({
url: '/getUserList',
method: 'GET',
})
console.log(res)
}
11、多环境处理
11-1 编写env文件夹,里面放.env,.env.production,.env.development等文件
11-2 把http.ts文件的baseUrl 替换掉
// 请求基地址
- const baseURL = 'http://localhost:5565/api'
+ const baseURL = import.meta.env.VITE_SERVER_BASEURL
src/env-d.ts
/// <reference types="vite/client" />
/// <reference types="vite-svg-loader" />
declare module '*.vue' {
import { DefineComponent } from 'vue'
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
const component: DefineComponent<{}, {}, any>
export default component
}
// 下面都是新增的
interface ImportMetaEnv {
readonly VITE_APP_TITLE: string
readonly VITE_SERVER_PORT: string
readonly VITE_SERVER_BASEURL: string
readonly VITE_DELETE_CONSOLE: string
// 更多环境变量...
}
interface ImportMeta {
readonly env: ImportMetaEnv
}
11-3 vite.config.ts 针对console是否清楚的处理
首先需要 pnpm i -D terser
,然后加入如下代码。
// vite.config.ts
build: {
minify: 'terser',
terserOptions: {
compress: {
drop_console: env.VITE_DELETE_CONSOLE === 'true',
drop_debugger: env.VITE_DELETE_CONSOLE === 'true',
},
},
}
12、unocss icons 的使用
12-1 安装对应的库
安装格式如下:
pnpm i -D @iconify-json/[the-collection-you-want]
这里我安装carbon, 所以执行 pnpm i -D @iconify-json/carbon
,如果还要其他的还可以继续安装。
12-2 使用
<button class="i-carbon-sun dark:i-carbon-moon" />
而且可以在编辑器就可以预览,体验很好。
所有的图标都在 icones.js.org/ 这个网站,要啥就安装啥(而且不用科学上网,利好国人)。
13、引入uni-ui
13-1 安装
pnpm i -S @dcloudio/uni-ui
pnpm i -D @uni-helper/uni-ui-types
13-2 tsconfig.ts 增加类型
"types": [
"@dcloudio/types",
"@types/wechat-miniprogram",
"@uni-helper/uni-app-types",
+ "@uni-helper/uni-ui-types"
]
13-3 pages.config.ts 配置 easycom
easycom: {
autoscan: true,
custom: {
// uni-ui 规则如下配置
'^uni-(.*)': '@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue',
},
},
13-4 使用
<uni-icons type="contact" size="30"></uni-icons>
<uni-badge text="1"></uni-badge>
可以看到页面立马生效了。
14、自己写的常用组件,可以通过easycom引入
14-1 pages.config.ts 配置 easycom
easycom: {
autoscan: true,
custom: {
+ // 以 Fly 开头的组件,在 components 文件夹中查找引入(需要重启服务器)
+ '^Fly(.*)': '@/components/fly-$1/fly-$1.vue',
+ '^fly-(.*)': '@/components/fly-$1/fly-$1.vue',
// uni-ui 规则如下配置
'^uni-(.*)': '@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue',
},
},
虽然上面2种写法都支持,但是最好还是与主流框架统一,全部使用小写+中划线。
14-2 使用
<fly-header></fly-header>
<FlyHeader></FlyHeader>
可以看到页面立马生效了。
虽然上面2种写法都支持,但是最好还是与主流框架统一,全部使用小写+中划线。
完结,撒花~~
unibest 链接地址
最后还是贴几个链接,不然你们想要的都找不到~~
文档地址:unibest.tech/ (2024年11月搞定的域名)
[unibest.tech] 对应的是:feige996/unibest-docs 同一仓库生成的内容。
github
地址:github.com/feige996/un…
gitee
地址:gitee.com/feige996/un…
旧的文档地址(留个纪念):codercup/unibest-docs
微信交流群
因不能贴引流二维码,有需要的同学请看官方文档微信群 。