feat: 把 docs 仓库移动到本仓库

This commit is contained in:
Burt
2024-12-06 09:53:27 +08:00
parent 41f694b222
commit b2bf1efef3
164 changed files with 4684 additions and 99 deletions

196
docs/base/1-introduction.md Normal file
View File

@@ -0,0 +1,196 @@
# 简介
<div class="md-center" style="margin-top: 20px;">
[![GitHub Repo stars](https://img.shields.io/github/stars/codercup/unibest?style=flat&logo=github)](https://github.com/codercup/unibest)
[![GitHub Repo stars](https://img.shields.io/github/stars/feige996/unibest?style=flat&logo=github)](https://github.com/feige996/unibest)
[![star](https://gitee.com/codercup/unibest/badge/star.svg?theme=dark)](https://gitee.com/codercup/unibest)
![node version](https://img.shields.io/badge/node-%3E%3D18-green)
![pnpm version](https://img.shields.io/badge/pnpm-%3E%3D7.30-green)
![GitHub License](https://img.shields.io/github/license/codercup/unibest)
</div>
> 上面前 2 个 `star` 分别是旧仓库 `codercup` 和新仓库 `feige996` 的 `star` 数。
`unibest` 是最好的 `uniapp` 开发框架,由 `uniapp` + `Vue3` + `Ts` + `Vite5` + `UnoCss` + `VSCode`(可选 `webstorm`) + `uni插件`+ `wot-ui`(可选其他 UI 库)构建,集成了多种工具和技术,使用了最新的前端技术栈,无需依靠 `HBuilderX`,通过命令行方式即可运行 `web``小程序``App`。(注:`App` 还是需要 `HBuilderX`
`unibest` 内置了 `约定式路由``layout布局``请求封装``请求拦截``登录拦截``UnoCSS``i18n多语言` 等基础功能,提供了 `代码提示``自动格式化``统一配置``代码片段` 等辅助功能,让你编写 `uniapp` 拥有 `best` 体验 `unibest 的由来`)。
> `unibest` 目前支持 `H5`、`小程序` 和 `App`。
## ⭐ Star History
Github Star History 实时地址:[https://star-history.com/#codercup/unibest&Date](https://star-history.com/#codercup/unibest&Date) 。
[![Star History Chart](https://api.star-history.com/svg?repos=codercup/unibest&type=Date)](https://star-history.com/#codercup/unibest&Date)
与同类型模板对比,如下图,红色的为 `unibest`,后来居上,遥遥领先。
:::details
[![Star History Chart](https://api.star-history.com/svg?repos=codercup/unibest,Ares-Chang/uni-vitesse,uni-helper/vitesse-uni-app&type=Date)](https://star-history.com/#codercup/unibest&Ares-Chang/uni-vitesse&uni-helper/vitesse-uni-app&Date)
同类模板对比实时地址:[https://star-history.com/#codercup/unibest&Ares-Chang/uni-vitesse&uni-helper/vitesse-uni-app&Date](https://star-history.com/#codercup/unibest&Ares-Chang/uni-vitesse&uni-helper/vitesse-uni-app&Date)
:::
## 🗂 生成过程
`unibest` 由最初始的官方 cli 脚手架模板生成,执行的命令如下:
```sh
npx degit dcloudio/uni-preset-vue#vite-ts my-vue3-project
```
`uniapp` 官方链接:[点击跳转 - quickstart-cli](https://uniapp.dcloud.net.cn/quickstart-cli.html)
在官方生成的项目基础上,增加了如下内容:
- 前端基础配置六件套
- prettier
- eslint
- stylelint
- husky
- lint-staged
- commitlint
- UnoCSS
- UnoCSS Icons
- Uni 插件
- vite-plugin-uni-pages
- vite-plugin-uni-layouts
- vite-plugin-uni-manifest
- vite-plugin-uni-platform
- UI 库(默认 `wot-ui`,支持替换其他 `UI库`)
- pinia + pinia-plugin-persistedstate
- 通用功能
- 请求封装
- 请求拦截
- 路由拦截
## ✨ 特性
- ⚡️ [Vue 3](https://github.com/vuejs/core), [Vite](https://github.com/vitejs/vite), [pnpm](https://pnpm.io/), [esbuild](https://github.com/evanw/esbuild) - 就是快!
- 🔥 最新语法 - `<script lang="ts" setup>` 语法
- 🎨 [UnoCSS](https://unocss.dev/) - 高性能且极具灵活性的即时原子化 CSS 引擎
- 😃 [UnoCSS Icons](https://unocss.dev/presets/icons) & [icones](https://icones.js.org/) - 海量图标供你选择
- 🍍 [pinia](https://pinia.vuejs.org/) & [pinia-plugin-persistedstate](https://prazdevs.github.io/pinia-plugin-persistedstate/zh/guide/) - 全端适配的全局数据管理
- 🗂 `uni.request` 请求封装 - 一键引入,快捷使用
- 📦 `路由拦截` 基础封装,支持扩展,快捷使用,拒绝黑盒
- 📥 [API 自动加载](https://github.com/antfu/unplugin-auto-import) - 直接使用 Composition API 无需引入
- 🎉 `v3` Code Snippets 加快你的页面生成
- 🦾 `Pritter` & `ESLint` & `Stylelint` & `husky` & `lint-staged` + `commitlint` - 保证代码质量
- 🌈 `TypeScript` 加持,同时又兼容 `js` ,同时满足不同人群
- 💡 `ES6 import` 自动排序,`css 属性` 自动排序,增强编码一致性
- 🖥 `多环境` 配置分开,想则怎么配置就怎么配置
## 📦 目录结构
通过 `tree -I node_modules -I dist -I .git -a > tree.md` 命令生成。
```txt
.
├── .editorconfig
├── .eslintignore
├── .eslintrc-auto-import.json
├── .eslintrc.cjs
├── .gitignore
├── .husky
├── .npmrc
├── .prettierignore
├── .prettierrc.cjs
├── .stylelintignore
├── .stylelintrc.cjs
├── .vscode
├── LICENSE
├── README.md
├── commitlint.config.cjs
├── env
│   ├── .env
│   ├── .env.development
│   ├── .env.production
│   └── .env.test
├── favicon.ico
├── index.html
├── manifest.config.ts
├── package.json
├── pages.config.ts
├── src
│   ├── App.vue
│   ├── components
│   │   └── .gitkeep
│   ├── env.d.ts
│   ├── hooks
│   │   ├── .gitkeep
│   │   ├── useRequest.ts
│   │   └── useUpload.ts
│   ├── interceptors
│   │   ├── index.ts
│   │   ├── prototype.ts
│   │   ├── request.ts
│   │   └── route.ts
│   ├── layouts
│   │   ├── default.vue
│   │   └── demo.vue
│   ├── main.ts
│   ├── manifest.json
│   ├── pages
│   │   ├── about
│   │   │   ├── about.vue
│   │   │   └── components
│   │   │   ├── request.vue
│   │   │   └── upload.vue
│   │   └── index
│   │   └── index.vue
│   ├── pages-sub
│   │   └── demo
│   │   └── index.vue
│   ├── pages.json
│   ├── service
│   │   └── index
│   │   └── foo.ts
│   ├── static
│   │   ├── images
│   │   │   └── .gitkeep
│   │   ├── logo.svg
│   │   └── tabbar
│   │   ├── example.png
│   │   ├── exampleHL.png
│   │   ├── home.png
│   │   ├── homeHL.png
│   │   ├── personal.png
│   │   └── personalHL.png
│   ├── store
│   │   ├── index.ts
│   │   └── user.ts
│   ├── style
│   │   └── index.scss
│   ├── types
│   │   ├── auto-import.d.ts
│   │   ├── global.d.ts
│   │   ├── shims-uni.d.ts
│   │   └── uni-pages.d.ts
│   ├── typings.ts
│   ├── uni.scss
│   ├── uni_modules
│   │   └── .gitkeep
│   └── utils
│   ├── http.ts
│   ├── index.ts
│   └── platform.ts
├── tsconfig.json
├── uni-pages.d.ts
├── uno.config.ts
└── vite.config.ts
```

163
docs/base/10-i18n.md Normal file
View File

@@ -0,0 +1,163 @@
# 多语言篇
`多语言` 是一个常见的需求, `unibest` 专门开发了一个 `i18n`模板,可以直接生成 `多语言模板项目`
```sh
pnpm create unibest my-project -t i18n
```
`vue组件` 里面使用方式如下:
```html
<view class="m-4">{{ $t('app.name') }}</view>
```
`非vue组件` 里面怎么使用呢?比如 `ts` 文件。
这时需要用到作者编写的 `translate` 函数,使用方式如下:
```ts
import { translate as t } from '@/locale/index'
/** 非vue 文件使用 i18n */
export const testI18n = () => {
console.log(t('app.name'))
// 下面同样生效
uni.showModal({
title: 'i18n 测试',
content: t('app.name'),
})
}
```
上面基本的使用都是没问题的,但是传递参数时,只有 `H5端` 生效,`其他端` 是不生效的,代码如下:
```html
<view class="m-4">{{ $t('weight', { heavy: 100 }) }}</view>
```
`H5端` 效果如下,正常显示:
![alt text](./assets/10-1.png)
`非H5端` 效果如下,异常显示:
![alt text](./assets/10-2.png)
下面我们就来处理这个问题。
## 多语言传参
上面提到 `vue-i18n``非H5端` 传参时显示异常,那我们就来处理一下,主要方式就是通过 `正则` 替换 `多语言字符串`
编写一个函数 `formatI18n`,如下:
```ts
/**
* formatI18n('我是{name},身高{detail.height},体重{detail.weight}',{name:'张三',detail:{height:178,weight:'75kg'}})
* 暂不支持数组
* @param template 多语言模板字符串eg: `我是{name}`
* @param obj 需要传递的对象里面的key与多语言字符串对应eg: `{name:'菲鸽'}`
* @returns
*/
export function formatI18n(template, data) {
const match = /\{(.*?)\}/g.exec(template)
if (match) {
const variableList = match[0].replace('{', '').replace('}', '').split('.')
let result = data
for (let i = 0; i < variableList.length; i++) {
result = result[variableList[i]] || ''
}
return formatStr(template.replace(match[0], result), data)
} else {
return template
}
}
```
`vue组件` 里面使用方式如下:
```html
<view class="m-4">{{ formatI18n(translate('introduction'), user) }}</view>
```
用到的函数引入如下:
```js
import { formatI18n, translate } from '@/locale/index'
```
对应的 en.json 文件如下:
```json
{ "introduction": "I am {name},height:{detail.height},weight:{detail.weight}" }
```
`user` 对象如下:
```js
{name:'张三',detail:{height:178,weight:'75kg'}}
```
这样,在 `H5端``非H5端` 都能正常显示,如下:
![alt text](./assets/10-3.png)
very good !
## 导航栏标题
目前发现 `导航栏标题``小程序端` 不会跟随多语言切换而切换,比如说刚开始是中文,切换成英文后,页面内容都变成英文了,标题栏还是中文。
> `App端` 说明:`App模拟器`,以我的 `mac电脑` `ios模拟器` 来说,是正常的,可以直接切换,多语言也是生效的。
>
> 但是 `安卓真机` 会出现`切换多语言后,自动重启,然后界面多语言是生效的`。
>
> 既然 `App 正常`,这里主要说 `小程序端` 不正常的处理。
`小程序端` 需要使用 `uni.setNavigationBarTitle` 来手动处理,`API` 使用如下:
```js
uni.setNavigationBarTitle({
title: '新的标题',
})
```
结合 `translate` 函数,则:
```js
uni.setNavigationBarTitle({
title: translate('app.name'),
})
```
可以满足大部分场景。
## tabbar 标题
`导航栏标题`
## App 端视频
这里给出 `2``App端` 的视频,加深开发者的认识和印象。
:::details
### `ios模拟器` 多语言直接就是生效的
<video src="./assets/10-ios.mp4" controls="controls" width="100%" height="100%"></video>
### `安卓真机` 会自动重启,重启后界面多语言是生效的
<video src="./assets/10-android.mp4" controls="controls" width="100%" height="100%"></video>
:::
## 总结
本文介绍了 `unibest` 里面使用 `多语言` 的基本方式,还处理了 `3` 个多端异常的问题:
- `多语言传参` 不生效 BUG
- `导航栏标题` 切换多语言不生效 BUG
- `tabbar标题` 切换多语言不生效 BUG
全文完~

111
docs/base/11-build.md Normal file
View File

@@ -0,0 +1,111 @@
# 运行发布
## 运行
- `h5 平台` `pnpm dev:h5` 或者简单点 `pnpm dev` ),然后浏览器打开 `http://localhost:9000/`
- `wx 小程序``pnpm dev:mp-weixin`,然后打开微信开发者工具,导入本地文件夹,选择本项目的 `dist/dev/mp-weixin` 文件。
- ![alt text](./assets/11-1.png)
- `APP 平台``pnpm dev:app`,然后打开 `HBuilderX`,导入刚刚生成的 `dist/dev/app` 文件夹,选择运行到 `模拟器`( `开发时优先使用` ),或者 `运行到安卓/ios 基座` (真机调试时使用) 。
![alt text](./assets/11-2.png)
![alt text](./assets/11-3.png)
![alt text](./assets/11-4.png)
> 如果需要配置其他模拟器,可以参考:[安装模拟器](https://uniapp.dcloud.net.cn/tutorial/run/installSimulator.html)
> 这样操作的话,开发时都会有热更新,开发体验很爽!
## 发布
- `h5 平台` `pnpm build:h5`,打包后的文件在 `dist/build/h5`,可以放到 web 服务器,如 nginx 运行。如果最终不是放在根目录,可以在 `manifest.config.ts` 文件的 `h5.router.base` 属性进行修改。
- `wx 小程序``pnpm build:mp-weixin`,打包后的文件在 `dist/build/mp-weixin`,然后通过微信开发者工具导入,并点击右上角的“上传”按钮进行上传。
- `APP 平台``pnpm build:app`,然后打开 `HBuilderX`,导入刚刚生成的 `dist/build/app` 文件夹,选择 `发行` - `原生APP-云打包`
![alt text](./assets/11-13.png)
![alt text](./assets/11-5.png)
![alt text](./assets/11-6.png)
> 熟悉原生 APP 开发的开发者也可以使用 `原生APP-本地打包`。
## APP 打包注意事项(上)
很多开发者发现打包失败,或者打包白屏,这里简单说明一下。
- 1. 重新获取自己的 `AppId`
![alt text](./assets/11-7.png)
- 2. 根据上面获取到的 `AppId` 修改 `env/.env` 文件的 `VITE_UNI_APPID` 字段
![alt text](./assets/11-8.png)
- 3. (可选)云打包如果有出现解析时出问题的,把 `minSdkVersion` 版本改低一点就好了,比如 `21`。(最低 `21`,不能低于 `21`;我模板里面设置的是 `30`)。
![alt text](./assets/11-9.png)
## APP 打包注意事项 (下)
### `uni-app SDK` 版本
> 特别备注:`2024-05-03`,新的 `base` 模板的 `uni-app SDK` 版本已经升级到 `4.14` 了。
>
> ![alt text](./assets/11-100.png)
`2024-04-14`,新的 `base` 模板的 `uni-app SDK` 版本已经升级到 `4.08` ,记得更新您的 `HBuilderx` 版本。
`"@dcloudio/uni-app": "3.0.0-4000820240401001"` 表示 `uni-app``3.0.0` 版本,对应的 `HBuilderx` 版本为 `4.08`,后面的 `20240401001` 是发布日期。
> `40008` 第一个数字 `4` 表示主要版本,后面每 `2` 位数为一组,所以代表 `4.0.8`。
>
> 类似的,`30812` 代表 `3.8.12` 版本,`30909` 代表 `3.9.9` 版本。
>
> 另外,从 `3.99` 开始,后面 2 个小版本合并书写,于是 `3.9.9` 变成 `3.99``4.0.8` 变成 `4.08`。
`unibest` 历史用过的 `@dcloudio/uni-app` 版本:
```text
"@dcloudio/uni-app": "3.0.0-3081220230817001", => 3.8.12
"@dcloudio/uni-app": "3.0.0-3090920231225001", => 3.99
"@dcloudio/uni-app": "3.0.0-4000820240401001", => 4.08
"@dcloudio/uni-app": "3.0.0-4010420240430001", => 4.14
```
![alt text](./assets/11-10.png)
### `uni-app SDK` 版本匹配 `HBuilderX`
> 温馨提示:下面的部分是使用 `uni-app` 版本为 `3.8.12` 时写的文档,适当参考~
本模板使用的是 `3.8.12` 的库版本(`"@dcloudio/uni-app": "3.0.0-3081220230817001",`),所以尽量使用 `3.8.12` 版本的 `HBuilderX` 来打包,否则可能有未知的风险,出现情况如下图。
> 原来的图不见了,重新补了一张。
![alt text](./assets/11-11.png)
上图表示您的 `HBuilderX` 版本是 `4.08`,但是代码 `uni-app SDK` (即 `"@dcloudio/uni-app": "3.0.0-4010420240430001"` ) 是 `4.14`,版本不匹配。
- 点击 `ignore`(忽略) 后若可以正常使用,那就不用管。(可选添加如下配置)
```json
"app-plus" : { "compatible": { "ignoreVersion": true } }
```
- 如果出现白屏啥的,请更新您的 `HBuilderX``uni-app SDK` 相同版本(这里是 `4.14` )。
### 多个 `HBuilderX` 版本安装
> 温馨提示:下面的部分是使用 `uni-app` 版本为 `3.8.12` 时写的文档,适当参考~
`MAC` 可以安装多个版本的软件,如下图我安装了 `3.8.12` (3.8.12.20230817) 和最新的 `3.99` (3.99.2023122611) 两个版本,平时的项目使用 `3.99`, 打包 `unibest` 的时候使用 `3.8.12`
![alt text](./assets/11-12.png)
> `window` 系统也可以同时安装多个 `HBuilderX` 版本,安装时选择安装到不同目录下即可。
## 总结
本文描述了多端的运行和发布,希望对您有帮助。
全文完~

89
docs/base/12-env.md Normal file
View File

@@ -0,0 +1,89 @@
# 环境变量
主要介绍 `vite` 环境变量和 `uni` 环境变量。
## `vite` 环境变量
`Vite` 在一个特殊的 `import.meta.env` 对象上暴露环境变量。环境变量定义在 `.env` 文件里。
### .env 文件
创建环境文件:
```yml
.env # 所有情况下都会加载
.env.local # 所有情况下都会加载,但会被 git 忽略
.env.[mode] # 只在指定模式下加载
.env.[mode].local # 只在指定模式下加载,但会被 git 忽略
# 注意 .env.local 无法覆盖 .env.[mode]
```
环境文件只包含环境变量的 `键值对`
```yml
VITE_SOME_KEY=123
DB_PASSWORD=foobar
```
> 为了防止意外地将一些环境变量泄漏到客户端,只有以 `VITE_` 为前缀的变量才会暴露给经过 `vite` 处理的代码。
如上配置,只有 `VITE_SOME_KEY` 会被暴露为 `import.meta.env.VITE_SOME_KEY` 提供给客户端源码,而 `DB_PASSWORD` 则不会。
```js
console.log(import.meta.env.VITE_SOME_KEY) // "123"
console.log(import.meta.env.DB_PASSWORD) // undefined
```
### mode 模式
Vite 允许你为不同的构建环境指定不同的模式。通常在 `npm scripts` 里面指定 `mode` 参数:
```sh
"scripts": {
"dev": "uni",
"dev-dev": "uni --mode development",
"dev-test": "uni --mode test",
"dev-prod": "uni --mode production",
}
```
运行不同模式的脚本时,`Vite` 会自动加载对应的 `.env.[mode]` 文件,就能获取到不同的环境变量。
`Vite` 运行 `dev` 时默认会加载 `.env.development` 文件(若有)。
`Vite` 运行 `build` 时默认会加载 `.env.production` 文件(若有)。
故,如上配置 `pnpm dev``pnpm dev-dev` 是一个效果。
## `uni` 环境变量
`uni` 环境变量这里指运行 `uni` 的平台变量,通过 `vite``define` 配置可以暴露出来。
```
define: {
__UNI_PLATFORM__: JSON.stringify(UNI_PLATFORM),
},
```
代码里面使用:
```js
export const platform = __UNI_PLATFORM__
export const isH5 = __UNI_PLATFORM__ === 'h5'
export const isApp = __UNI_PLATFORM__ === 'app'
export const isMp = __UNI_PLATFORM__.startsWith('mp-')
const PLATFORM = {
platform,
isH5,
isApp,
isMp,
}
export default PLATFORM
```
## 总结
本文描写了 `vite` 环境变量和 `uni` 环境变量如何配置和使用。
全文完~

67
docs/base/13-hbx.md Normal file
View File

@@ -0,0 +1,67 @@
# hbx 模板
为了方便使用 `HBuilderX` 的开发者,`unibest` 也提供 `hbx` 模板。
`hbx 模板` 适用于 `2 类用户`
- 使用 `uniCloud` 云开发的用户,必须使用 `hbx 版本`,因为 `uniCloud``HBuilderX` 是绑定的。
- 开发 `App` 的用户,可选使用 `hbx 版本`
## 仓库地址
- gitee: [https://gitee.com/feige996/unibest-hbx.git](https://gitee.com/feige996/unibest-hbx.git)
- github: [https://github.com/feige996/unibest-hbx.git](https://github.com/feige996/unibest-hbx.git)
没有梯子的用户优先推荐使用 `gitee` 仓库,速度更快。(两个仓库会实时同步,无差别。)
## 导入项目
有 2 种方式导入项目:
-`Git` 导入...
- 从本地目录导入...
## 运行项目
此时运行菜单会提示 `本项目类型无法运行`,如下图
![alt text](./assets/13-1.png)
![alt text](./assets/13-2.png)
需要执行如下 2 步:
- 项目下执行 `pnpm i`
- 右键项目,选择 `重新识别项目类型`
![alt text](./assets/13-3.png)
## 运行效果
经过上面的操作后,就可以正常运行了。
- ios 模拟器运行效果如下:
![alt text](./assets/13-4.png)
![alt text](./assets/13-5.png)
![alt text](./assets/13-6.png)
- 微信小程序运行效果如下:
![alt text](./assets/13-7.png)
> 目前微信小程序静态资源还有点问题,如下图 `logo 不见了`,后续会修复。
![alt text](./assets/13-8.png)
> 另外还发现 `UnoCSS Icon` 不生效,原因未知。
## 总结
本文描述了 `hbx` 模板的由来,使用方式。
有需要的可以试试,但是不太建议使用。另外精力有限,该模板不再维护。
全文完~

116
docs/base/14-faq.md Normal file
View File

@@ -0,0 +1,116 @@
# 常见问题
本篇介绍一些常见的问题,会持续更新。
## 1. 如何设置/修改首页?
`vue` 文件的 `route-block` 块里面设置 `type="home"` 即可,请确保项目里面 `只有一个页面` 是这个配置。
> 注意:如果有多个,会按照字母顺序排列,第一个是首页。(可能不是您的想要的效果。)
## 2. 修改 `pages.json`、`manifest.json` 被覆盖问题
- `pages.json`
本项目引入了 `@uni-helper/vite-plugin-uni-pages``pages.json` 文件将会自动生成,手动修改 `pages.json` 将会被覆盖。
全局的东西请在 `pages.config.ts` 里面配置,页面的东西请在 `vue` 文件的 `route-block` 配置。
- `manifest.json`
与上面类似。本项目引入了 `@uni-helper/vite-plugin-uni-manifest``manifest.json` 文件将会自动生成,手动修改 `manifest.json` 将会被覆盖。
如需修改,请在 `manifest.config.ts` 里面修改。
## 3. 怎么分包?
`vite.config.ts` 里面有一个配置,如下:(其中 `subPackages` 就是用来分包的)
```ts [vite.config.ts]{3}
UniPages({
exclude: ['**/components/**/**.*'],
subPackages: ['src/pages-sub'], // 是个数组,可以配置多个
}),
```
## 4. 首次运行 `pnpm:mp` 时报错。
首次运行 `pnpm:mp` 时报错,报错如下:
```text
Error: ENOENT: no such file or directory, open '/Users/burtlai/unibest-projects/unibest/src/manifest.json'
```
首次运行 `非h5端` 时都可能出现上面的问题,需要先执行一下 `pnpm i` 以生成 `src/manifest.json` 文件,后面就不会报错了。
## 5. `git commit` 报错。
请看 `commitlint.config.ts` 里面的配置,需要满足对应的设定。根据自己的需要,可以修改 `commitlint.config.ts` 里面的配置。
如果是一次的(比如引入了某个第三方库),可以通过 `--no-verify` 参数跳过校验:
```sh
git commit -m "feat: xxx" --no-verify
```
第三方库还有另外一种处理方式,放到特定的文件夹,然后在 `.eslintignore` 和 `.styleintignore` 里面加上该文件夹。
## 6. `uni-app` 无法使用 `process.env` 变量,怎么办?
使用 `import.meta.env` 替代!
## 7. 如何跟随 `uni-app` 官方升级?
项目下,执行 `npx @dcloudio/uvm@latest` 即可更新。
![alt text](./assets/14-1.png)
> 注意,上面的命令会自动安装 `vue-i18n`,可以手动删除(`pnpm un vue-i18n`),也可以不理它(没多大影响)。
## 8. 如何把已经加入 `git` 管理的文件移出 `git` 管理?
- 第一步,先把文件移出`git` 管理,操作如下:
```text
# git rm -r --cached file1 file2 ## 针对某些文件
# git rm -r --cached dir1 dir2 ## 针对某些文件夹
# git rm -r --cached . ## 针对所有文件
```
- 第二步,提交 `commit` 以正式删除的文件
> 总结:`git rm -r --cached .` + `git commit` 即可。
## 9. 支付宝小程序运行报错。
- 默认运行是会报错的,如下图
![alt text](./assets/14-2.png)
- 只需要勾上 `本地开发跳过 ES5 转译` 即可正常运行,如下图
![alt text](./assets/14-3.png)
> 总结:勾上 `本地开发跳过 ES5 转译` 即可。
## 10. 支持 `uni-app x` 吗?
不支持。但我们一直保持关注。[uni-app x 传送门](https://doc.dcloud.net.cn/uni-app-x/)
目前 `unibest` 已经有 `hbx` 模板,后续接入 `uni-app x` 会很容易,坐等官方发布。
## 11. 为啥 `vue` 已经 `3.4+` 了,还不支持 `defineModel` ?
`uni-app` 官方虽然已经把 `vue` 升级到 `3.4+` 了,但是目前只有 `H5端` 支持 `defineModel`,其他端目前运行报错,详情请看 `uni-app` 官网的发布日志:
[HBuilder X - Release Notes](https://3085868976.hiecheimaetu.com:22443/qn-GO8xCsKgpKDZWIBAkVCUkI1EnGmQUMT4.update.dcloud.net.cn/hbuilderx/changelog/4.14.2024043013.html)
关键截图如下:
![alt text](./assets/14-4.png)
真实运行报错截图如下:(分别是 `小程序` 和 `APP`
![alt text](./assets/14-5.png)
![alt text](./assets/14-6.png)
全文完~

267
docs/base/15-faq.md Normal file
View File

@@ -0,0 +1,267 @@
# 常见问题 2
## 1. `wot-ui` 的 `toast` + `message-box` 不生效。
- 1. `layout` 引入 `wot-ui``toast` + `message-box`
```vue [src/layouts/default.vue]
<!-- src/layouts/default.vue -->
<template>
<view>
<slot />
<wd-toast />
<wd-message-box />
</view>
</template>
```
> `unibest@2.1.0` 开始已经默认引入。
- 2.页面使用
```ts
import { useMessage } from 'wot-design-uni'
const message = useMessage()
const handleClick = () => {
// 顺便测试 message 的使用
message.show('显示隐藏切换')
}
```
## 2. `uni-app` 插件市场的插件如何使用?
`hbx` 模板可以直接引入,不在讨论范围内,下面描述的是 `普通模板`。
> 如果该插件支持 `npm` 安装,则直接安装即可,推荐统一使用 `pnpm` 安装。接着根据该插件的文档使用即可。
下面描写的是不支持 `npm` 安装的插件。
这里以 `sp-editor` 富文本插件为例,[插件地址](https://ext.dcloud.net.cn/plugin?id=14726)
- 1. 下载 `uni-app` 插件市场的代码。(居然要登录+看广告)
![alt text](./assets/15-1.png)
- 2. 解压并拷贝到 `unibest` 项目的 `uni_modules` 目录下。
![alt text](./assets/15-2.png)
- 3. 整理插件文件夹名称,把 `sp-editor_1.3.7` 改为 `sp-editor`。
> 不改会报错,因为内部代码都是用 `sp-editor` 不带版本号的。会导致查找文件失败。
![alt text](./assets/15-3.png)
- 4. 代码直接使用,无需引入组件。( `uni-app插件` 有一套规范,`uni-app` 会自动查找,跟 `easycom` 类似。)
```html
<template>
<view class="home">
<view class="editor-box">
<sp-editor
:toolbar-config="{
excludeKeys: ['direction', 'date', 'lineHeight', 'letterSpacing', 'listCheck'],
iconSize: '18px',
}"
@init="initEditor"
@input="inputOver"
@upinImage="upinImage"
@overMax="overMax"
@addLink="addLink"
@exportHtml="exportHtml"
></sp-editor>
</view>
</view>
</template>
```
完整版见下:
:::details
```vue
<route lang="json5">
{
layout: 'demo',
style: { navigationBarTitleText: '富文本' },
}
</route>
<template>
<view class="home">
<view class="editor-box">
<sp-editor
:toolbar-config="{
excludeKeys: ['direction', 'date', 'lineHeight', 'letterSpacing', 'listCheck'],
iconSize: '18px',
}"
@init="initEditor"
@input="inputOver"
@upinImage="upinImage"
@overMax="overMax"
@addLink="addLink"
@exportHtml="exportHtml"
></sp-editor>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue'
const editorIns = ref(null)
/**
* 获取输入内容
* @param {Object} e {html,text} 内容的html文本和text文本
*/
function inputOver(e) {
// 可以在此处获取到编辑器已编辑的内容
console.log('==== inputOver :', e)
}
/**
* 超出最大内容限制
* @param {Object} e {html,text} 内容的html文本和text文本
*/
function overMax(e) {
// 若设置了最大字数限制,可在此处触发超出限制的回调
console.log('==== overMax :', e)
}
/**
* 编辑器就绪
* @param {Object} editor 编辑器实例你可以自定义调用editor实例的方法
* @tutorial editor组件 https://uniapp.dcloud.net.cn/component/editor.html#editor-%E7%BB%84%E4%BB%B6
* @tutorial 相关api https://uniapp.dcloud.net.cn/api/media/editor-context.html
*/
function initEditor(editor) {
editorIns.value = editor // 保存编辑器实例
// 保存编辑器实例后,可以在此处获取后端数据,并赋值给编辑器初始化内容
preRender()
}
function preRender() {
setTimeout(() => {
// 异步获取后端数据后,初始化编辑器内容
editorIns.value.setContents({
html: `<div>&nbsp;&nbsp;猫猫<img src="https://img.yzcdn.cn/vant/cat.jpeg"/></div>`,
})
}, 1000)
}
/**
* 直接运行示例工程插入图片无法正常显示的看这里
* 因为插件默认采用云端存储图片的方式
* 以$emit('upinImage', tempFiles, this.editorCtx)的方式回调
* @param {Object} tempFiles
* @param {Object} editorCtx
*/
function upinImage(tempFiles, editorCtx) {
/**
* 本地临时插入图片预览
* 注意:这里仅是示例本地图片预览,因为需要将图片先上传到云端,再将图片插入到编辑器中
* 正式开发时,还请将此处注释,并解开下面 使用 uniCloud.uploadFile 上传图片的示例方法 的注释
* @tutorial https://uniapp.dcloud.net.cn/api/media/editor-context.html#editorcontext-insertimage
*/
// #ifdef MP-WEIXIN
// 注意微信小程序的图片路径是在tempFilePath字段中
editorCtx.insertImage({
src: tempFiles[0].tempFilePath,
width: '80%', // 默认不建议铺满宽度100%,预留一点空隙以便用户编辑
success: function () {},
})
// #endif
// #ifndef MP-WEIXIN
editorCtx.insertImage({
src: tempFiles[0].path,
width: '80%', // 默认不建议铺满宽度100%,预留一点空隙以便用户编辑
success: function () {},
})
// #endif
/**
* 使用 uniCloud.uploadFile 上传图片的示例方法(可适用多选上传)
* 正式开发环境中,请将上面 本地临时插入图片预览 注释后,模仿以下写法
*/
// tempFiles.forEach(async (item) => {
// uni.showLoading({
// title: '上传中请稍后',
// mask: true
// })
// let upfile = await uniCloud.uploadFile({
// filePath: item.path,
// // 同名会导致报错 policy_does_not_allow_file_overwrite
// // cloudPath可由 想要存储的文件夹/文件名 拼接若不拼文件夹名则默认存储在cloudstorage文件夹中
// cloudPath: `cloudstorage/${item.name}`,
// cloudPathAsRealPath: true
// })
// editorCtx.insertImage({
// src: upfile.fileID,
// width: '80%', // 默认不建议铺满宽度100%,预留一点空隙以便用户编辑
// success: function () {
// uni.hideLoading()
// }
// })
// })
}
/**
* 导出 - toolbar需要开启export工具
* @param {string} e 导出的html内容
*/
function exportHtml(e) {
uni.navigateTo({
url: '/pages/out/out',
success(res) {
// 传至导出页面解析即可
res.eventChannel.emit('e-transmit-html', {
data: e,
})
},
})
}
/**
* 添加超链接
* @param {Object} e { text: '链接描述', href: '链接地址' }
*/
function addLink(e) {
console.log('==== addLink :', e)
}
</script>
```
:::
## 3. Vue-Office 使用哪个版本?
使用 `1.8x`,而不是 `2.x`,否则出现下面这样的问题:
![alt text](./assets/15-4.png)
## 4. 为啥不用 `vant-ui`
`vant-ui` 是 `WEB` 端 `UI 库`,不适用于 `uni-app`。
`uni-app` 没有 `window`, `document` 等 `WEB API`,所以凡是使用 `WEB API` 的 `框架`、`UI 库` 等都不适用于 `uni-app`。
## 4. 控制台报错 `[plugin:uni:mp-using-component] Unexpected token S in JSON at position 208`。
控制台报错如下:
![alt text](./assets/15-6.png)
原因是 `uni-pages` 这个插件最新版本 `0.2.22` 有问题,需要回退到 `0.2.20`。
![alt text](./assets/15-5.png)
执行如下命令即可:
```
pnpm add @uni-helper/vite-plugin-uni-pages@0.2.20
```
> 因为 `unibest` 在 `2.3.0(含)` 之前没有把 `pnpm-lock.yaml` 加入到版本管理,导致小版还是有细微差别。
>
> 在 `2.4.0` 开始已经加入,不会再出现这个问题。

119
docs/base/2-start.md Normal file
View File

@@ -0,0 +1,119 @@
# 快速开始
- 前置依赖
- **Node.js** - `>=v18`
- **pnpm** - `>=7.30`(推荐使用 `8.12+`
- **`VSCode`** - 可选 `WebStrom`
- **`HBuilderX`** - `APP` 的运行和发布还是离不开它
- **Vue-Office** - `1.8x`,别升到 `2.x`
## 创建项目
通过下面的命令可以快速生成项目模板,`pnpm create unibest <项目名称>` ,如果不写 `<项目名称>` 会进入命令行交互模式。
```bash
# 如果没有 pnpm请先安装: npm i -g pnpm
pnpm create unibest my-project
```
npm 创建如下(不推荐)
:::details
如果使用 `npm`,可能有缓存,需要加上 `@latest` 标识,如果创建失败,请使用 `pnpm` 安装。
```bash
npm create unibest my-project
# 如果提示报错,或者生成的项目版本太旧,请使用下面的命令,增加 @latest 标识
npm create unibest@latest my-project
```
:::
实际操作截图如下:
![create project](./assets/2-1.png)
`create-unibest``v1.10.0` 开始会有版本号,如下:
![alt text](./assets/2-2.png)
![unibest templates](https://oss.laf.run/ukw0y1-site/xmind/unibest模板.png)
`create unibest` 支持 `-t` 参数选择模板,目前已有两大类 `8` 个模板
- `普通` 模板( `4个` ):分别是 `base``tabbar``i18n``demo`、~~`js`~~
- `hbx` 模板(`2个` ):分别是 `hbx-base``hbx-demo`
不带 `-t` 参数时会默认生成 `base` 模板。
`base` 模板是最基本的模板,更新最及时,推荐使用 `base` 模板创建新项目。其他几个模板也是基于 `base` 模板得到的。 `demo` 模板则作为参考用。
`js` 模板不推荐使用,可以使用 `base` 模板替代,里面已经做了兼容配置,可以直接编写 `js`,原本的 `ts` 文件还能提供部分类型,何乐而不为?
```sh
# VS Code 模板
pnpm create unibest my-project # 默认用 base 模板
pnpm create unibest my-project -t base # 基础模板
pnpm create unibest my-project -t tabbar # 自定义 tabbar 模板
pnpm create unibest my-project -t i18n # 多语言模板
pnpm create unibest my-project -t demo # 所有demo的模板(包括i18n)
# pnpm create unibest my-project -t js # js 模板
# HBuilderX 模板,方便使用 uniCloud 云开发 (未来可以对接 uni-app x)
pnpm create unibest my-project -t hbx-base # hbx的base模板
pnpm create unibest my-project -t hbx-demo # hbx的demo模板包含所有的demo
```
## 项目仓库地址
`github``gitee` 实时同步,代码一致。
### 普通模板:
- https://github.com/feige996/unibest
- https://gitee.com/feige996/unibest
> `demo` 模板是在 `hello-unibest` 项目中,仓库地址如下:
- https://github.com/feige996/hello-unibest
- https://gitee.com/feige996/hello-unibest
### hbx 模板
- https://github.com/feige996/unibest-hbx
- https://gitee.com/feige996/unibest-hbx
> `hbx` 目前由 `青谷` 大佬维护,微信号:`qingguxixi`[青谷 github 地址](https://github.com/Xiphin) 。
## 安装、运行
```bash [pnpm]
pnpm i
pnpm dev
# dev默认运行的是h5其他平台执行dev:<uni-platform>,如:
pnpm dev:mp-weixin
```
`pnpm dev` 之后在浏览器打开 `http://localhost:9000/`。
> 其他平台构建和发布,查看 [运行发布篇](./11-build)。
## 第一次 `commit`
```bash
git add .
git commit -m "feat: init project"
```
## `v3` 代码块
在 `vue` 文件中,输入 `v3` 按 `tab` 即可快速生成页面模板,可以大大加快页面生成。
> 原理:基于 `VSCode` 代码块生成。
![alt text](./assets/2-4.gif)
## 注意事项
- 若代码里面自动引入的 `API` 报错,只需要 `pnpm dev` 即可。
- 若代码运行后,`H5端` 浏览器界面底部没有 `tabbar` 刷新浏览器或者再次 `pnpm dev` 即可。

25
docs/base/20-best.md Normal file
View File

@@ -0,0 +1,25 @@
# 最佳实践
新项目使用 `base` 模板,可选 `tabbar` 模板。如果需要多语言,可以选 `i18n` 模板。
同时参考 `demo` 模板,可以直接 `clone` `demo` 项目,用来参考用。
> 推荐先全部体验一下 `demo` 的示例
```sh
# 新项目创建
pnpm create unibest my-project -b base
# 参考项目
git clone https://github.com/feige996/hello-unibest unibest-demo
# 参考项目-gitee (与 github 同步,无梯子用户优先使用 gitee)
git clone https://gitee.com/feige996/hello-unibest unibest-demo
```
## 必看章节
- [介绍](/base/1-introduction)
- [快速开始](/base/2-start)
- [uni 插件](/base/3-plugin)
- [常见问题](/base/14-faq)
- [常见问题 2](/base/15-faq)
- [运行发布](/base/11-build)

158
docs/base/3-plugin.md Normal file
View File

@@ -0,0 +1,158 @@
# uni 插件
## 引言
有群友第一次看到 `unibest` 里面 `vue` 文件 `route-block` 这种写法,表示很奇怪,重来没见过!
```vue
<route lang="json5">
{
layout: 'demo',
style: {
navigationBarTitleText: '标题',
},
}
</route>
<template>
<view class="text-green-500">菲鸽你好我喜欢你</view>
</template>
```
## uni 插件总览
哈哈,这个当然是 `uni插件` 的功劳了,具体点是 `@uni-helper/vite-plugin-uni-pages` 插件的功劳,该插件由 `uni-helper` 官方团队开发。
本文就来说说 `unibest` 都引入了哪些有用的 `uni插件`。下面这个表格描述了各个插件的主要作用。
| 插件名 | 作用 |
| :----------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| @dcloudio/vite-plugin-uni | **最核心的 `uni 插件`**,没有它就不能在 vite 项目跑 uniapp其他所有的 `uni插件` 都需要经通过它的手来编译,所以写法上,都是先写 `UniXXX`,再写 `Uni`,见下文 |
| @uni-helper/vite-plugin-uni-pages | `uni 插件`,也是 `unibest 灵魂插件``route-block` 就是它的功劳,让你可以直接在本文件就能设置页面的路元信息,无需跑去 `pages.json` 配置,同时支持 `pages.config.ts` 编写 `pages.json` |
| @uni-helper/vite-plugin-uni-layouts | `uni 插件`,支多种 `layouts` 布局,群友脑洞大开,充分利用这个特性实现平时不容实现的写法 |
| @uni-helper/vite-plugin-uni-manifest | `uni 插件`,支持 `manifest.config.ts` 编写 `manifest.json` |
`UniXXX()` 插件都需要在 `uni()` 之前引入,因为最终都需要 `Uni` 来处理所有的代码。如下图:
![vite uni plugin](./assets/3-1.png)
接下来介绍一下 `uni 插件`,其他 `通用插件` 大家都比较熟悉,不再赘述。
`unibest` 引入了 `uni-helper` 团队的几个重要插件,少了它们 `unibest` 就缺少了灵魂,感谢 `uni-helper` 团队的贡献。`Uni 插件` 列表如下:
- `vite-plugin-uni-pages`
- 介绍:为 `Vite` 下的 `uni-app` 提供基于文件系统的路由
- 额外:使用 `TypeScript` 来编写 `uni-app``pages.json`
- 访问地址:[@uni-helper/vite-plugin-uni-pages](https://github.com/uni-helper/vite-plugin-uni-pages)
- `vite-plugin-uni-layouts`
- 介绍:为 `Vite` 下的 `uni-app` 提供类 `nuxt``layouts` 系统
- 访问地址:[@uni-helper/vite-plugin-uni-layouts](https://github.com/uni-helper/vite-plugin-uni-layouts)
- `vite-plugin-uni-manifest`
- 介绍:使用 `TypeScript` 来编写 `uni-app``manifest.json`
- 访问地址:[@uni-helper/vite-plugin-uni-manifest](https://github.com/uni-helper/vite-plugin-uni-manifest)
## vite-plugin-uni-pages
得益于 [@uni-helper/vite-plugin-uni-pages](https://github.com/uni-helper/vite-plugin-uni-pages),约定式路由(文件路由)的实现轻而易举。
`src/pages` 目录下的每个文件都代表着一个路由。要创建新页面,只需要在这个目录里新增 `.vue` 文件,插件会自动生成对应的 `pages.json` 文件。
`route` 代码块则可以配置页面相关信息,这些信息会自动同步到 `page.json`,无需切换到 `page.json` 进行配置。
> `pages.json` 文件是自动生成的,请不要手动修改,全局的东西请在 `pages.config.ts` 里面配置,页面上的东西请在 `vue` 文件的 `route` 代码块配置,如下图。
```vue [src/pages/index.vue]
<!-- 使用 type="home" 属性设置首页其他页面不需要设置默认为page -->
<!-- 推荐使用json5更强大且允许注释 -->
<route lang="json5" type="home">
{
style: {
navigationStyle: 'custom',
navigationBarTitleText: '首页',
},
}
</route>
<template>
<div>
<h1>欢迎使用 unibest</h1>
<h4>unibest 是最好的 uniapp 开发模板</h4>
</div>
</template>
```
```vue [src/pages/about.vue]
<route lang="json5">
{
style: {
navigationBarTitleText: '关于',
},
}
</route>
<template>
<view>
<view>通过 `/pages/about` 来访问这个页面</view>
</view>
</template>
```
### 设置首页
通过在 `route-block` 里面配置 `type="home"` 即可,尽量保证一个项目 `只有一个` 这个配置,如果有多个,会按照字母顺序来排列,最终可能不是您想要的效果。
### 设置 pages 过滤和分包
- 过滤:默认 `src/pages` 里面的 `vue` 文件都会生成一个页面,如果不需要生成页面可以对 `vite.config.ts` 中的 `UniPages` 进行 `exclude` 配置。
- 分包:如果需要设置 `分包` 则可以通过 `subPackages` 进行配置,该配置项是个数组,可以配置多个 `分包`,注意分包的目录不能为 `src/pages` 里面的子目录。
```ts [vite.config.ts]
UniPages({
exclude: ['**/components/**/**.*'],
subPackages: ['src/pages-sub'], // 是个数组,可以配置多个,但不能为 `src/pages` 里面的子目录
})
```
## vite-plugin-uni-layouts
得益于 [@uni-helper/vite-plugin-uni-layouts](https://github.com/uni-helper/vite-plugin-uni-layouts),你可以轻松地切换不同的布局。
`src/layouts` 文件夹下的 `vue` 文件都会自动生成一个布局,默认的布局文件名为 `default` ,路径 `src/layouts/default.vue` 。
如果需要修改使用的布局,可以通过 `vue` 文件内 `route` 代码块指定需要的布局,如下示例使用 `demo` 布局。
```vue [src/pages/demo.vue]{3}
<route lang="json5">
{
layout: 'demo',
style: {
navigationBarTitleText: '关于',
},
}
</route>
```
```vue [src/layouts/demo.vue]
<template>
<view>
<!-- 这里可以写通用的布局比如导航栏tabbar等 -->
<!-- slot里面装的就是子页面的内容 -->
<slot />
</view>
</template>
```
## vite-plugin-uni-manifest
得益于 [@uni-helper/vite-plugin-uni-manifest](https://github.com/uni-helper/vite-plugin-uni-manifest),你可以使用 `TypeScript` 来编写 `manifest.json`。
> `manifest.json` 文件是自动生成的,请不要手动修改,需要配置的内容请在 `manifest.config.ts` 里面配置。
## 总结
本文介绍了 `unibest` 引入的几个重要的 `uni插件`。
如果还想了解更多信息,可以去 `uni-helper` [github 仓库](https://github.com/uni-helper) 看看。

220
docs/base/4-style.md Normal file
View File

@@ -0,0 +1,220 @@
# 样式篇
本篇主要介绍 `UnoCSS` 的使用,以及如何与 `设计稿尺寸` 对应。
## UnoCSS
[UnoCSS](https://unocss.dev/) 是按需使用的原子 CSS 引擎,提供了良好的样式支持。
![alt text](./assets/4-1.png)
在 VSCode 中还可以预览,
![alt text](./assets/4-2.png)
![alt text](./assets/4-3.png)
> 如果原子化 `UnoCSS` 没有预览效果,请安装 `VSCode` 插件 `antfu.unocss`。
如果不记得原子类,可以查 `UnoCSS 的原子类`[UnoCSS Interactive](https://unocss.dev/interactive/),如下图
![alt text](./assets/4-4.png)
也可以查看 `tailwindcss` 的原子类,更加清晰明了,[链接 - tailwindcss](https://tailwindcss.com/),如下图:
![alt text](./assets/4-5.png)
## 常用的原子类
- 宽高内外边距: `w-2`, `h-4`, `px-6`, `mt-8`
- 前景色背景色:`text-green-400`, `bg-green-500`
- border: `border-2`, `border-solid`, `border-green-600`, `b-r-2` (注意 `border` = `border-1`,就是说边框 `1px` 时,一般简写为 `border` )
- border-radius: `rounded-full`, `rounded-6`, `rounded-sm` (不是 `br-10`, 也不是 `b-r-10`)
- line-height: `leading-10` (不是 `l-10`, 也不是 `lh-10`)
- hover: `hover:text-green-200`, `hover:bg-green-300`, `hover:border-dashed`
- flex: `flex`, `items-center`, `justify-center`, `flex-1`
## `UnoCSS` 配置
下面内容选读:
:::details
`unocss.config.ts` 文件内容如下:
```ts
// uno.config.ts
import {
type Preset,
defineConfig,
presetUno,
presetAttributify,
presetIcons,
transformerDirectives,
transformerVariantGroup,
} from 'unocss'
import { presetApplet, presetRemRpx, transformerAttributify } from 'unocss-applet'
// @see https://unocss.dev/presets/legacy-compat
import { presetLegacyCompat } from '@unocss/preset-legacy-compat'
const isMp = process.env?.UNI_PLATFORM?.startsWith('mp') ?? false
const presets: Preset[] = []
if (isMp) {
// 使用小程序预设
presets.push(presetApplet(), presetRemRpx())
} else {
presets.push(
// 非小程序用官方预设
presetUno(),
// 支持css class属性化
presetAttributify(),
)
}
export default defineConfig({
presets: [
...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',
},
}),
// 将颜色函数 (rgb()和hsl()) 从空格分隔转换为逗号分隔更好的兼容性app端example
// `rgb(255 0 0)` -> `rgb(255, 0, 0)`
// `rgba(255 0 0 / 0.5)` -> `rgba(255, 0, 0, 0.5)`
presetLegacyCompat({
commaStyleColorFunction: true,
}) as Preset,
],
/**
* 自定义快捷语句
* @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',
}),
],
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 == 16px
* h5 里面mt-4 => margin-top: 1rem == 16px
*
* 另外,我们还可以推算出 UnoCSS 单位与设计稿差别4倍。
* 375 * 4 = 1500把设计稿设置为1500那么设计稿里多少pxunocss就写多少述职。
* 举个例子设计稿显示某元素宽度100px就写w-100即可。
*
* 如果是传统方式写样式,则推荐设计稿设置为 750这样设计稿1px代码写1rpx。
* rpx是响应式的可以让不同设备的屏幕显示效果保持一致。
*/
```
### UnoCSS presets
主要有 `4`个:
- `presetUno` —— `UnoCSS` 默认的预设,`H5端` 适用,`非H5端` 不支持,代码已经作区别处理。
- `presetApplet` 小程序预设,因为默认 `Unocss 预设` 是针对 `WEB` 的,如果不加以处理,会报错,比如小程序不支持 `*` 没有 `body` 等。该预设同样对 `APP` 生效。
- `presetIcons`,专门使用 `UnoCSS Icons`需要搭配图标库使用eg: `@iconify-json/carbon`, 代码编写如 `<button class="i-carbon-sun dark:i-carbon-moon" />`
- `presetLegacyCompat` 针对低端 `APP` 不认识新的函数颜色的兼容性预设,可以将颜色函数 `rgb()和hsl()` 里面空格分隔转换为逗号分隔,更好的兼容性`APP`example
> `rgb(255 0 0)` -> `rgb(255, 0, 0)`
>
> `rgba(255 0 0 / 0.5)` -> `rgba(255, 0, 0, 0.5)`
### UnoCSS shortcuts
```ts
/**
* 自定义快捷语句
* @see https://github.com/unocss/unocss#shortcuts
*/
shortcuts: [['center', 'flex justify-center items-center']],
```
可以编写一些常用的快捷类名,如上表示 `center` 就是 `flex justify-center items-center` 的组合,合理的添加快捷类名可以加快样式编写。
:::
## 设计稿尺寸
不同的编写方式,需要设置不同的设计稿尺寸,请看下文:
### 1. 传统编写方式
如果有设计稿,通常使用传统的编写 `CSS` 的方式,里面的对应尺寸规律如下。以蓝湖为例,假如设计稿宽度为 `750px`,则直接复制样式代码到 css 代码,同时把 `px` 批量替换为 `rpx` 即可。
如果设计稿不是 `750px` 可以调整蓝湖的设置,让设计稿宽度为 `750px`
> 下面为一段辅助说明文案,从 `uniapp` 官网搬运而来。
`rpx` 是相对于基准宽度的单位,可以根据屏幕宽度进行自适应。`uni-app` 规定屏幕基准宽度 `750rpx`
开发者可以通过设计稿基准宽度计算页面元素 `rpx` 值,设计稿 `1px` 与框架样式 `1rpx` 转换公式如下:
`设计稿 1px / 设计稿基准宽度 = 框架样式 1rpx / 750rpx`
换言之,页面元素宽度在 `uni-app` 中的宽度计算公式:
`750 * 元素在设计稿中的宽度 / 设计稿基准宽度`
举例说明:
若设计稿宽度为 `750px`,元素 `A` 在设计稿上的宽度为 `100px`,那么元素 `A``uni-app` 里面的宽度应该设为:`750 * 100 / 750`,结果为:`100rpx`
若设计稿宽度为 `640px`,元素 `A` 在设计稿上的宽度为 `100px`,那么元素 `A``uni-app` 里面的宽度应该设为:`750 * 100 / 640`,结果为:`117rpx`
若设计稿宽度为 `375px`,元素 `B` 在设计稿上的宽度为 `200px`,那么元素 `B``uni-app` 里面的宽度应该设为:`750 * 200 / 375`,结果为:`400rpx`
### 2. UnoCSS 编写方式
经过上一节的 `unocss.config.ts` 配置,可以得到下面的组合:
> mp 里面mt-4 => margin-top: 32rpx == 16px
>
> h5 里面mt-4 => margin-top: 1rem == 16px
我们还是把设计稿设置为 `750`,设计稿上多少 `px` 的元素,写成多少 `rpx` 即可。
元素 `A` 在设计稿上的宽度为 `100px`,则写 `w-100rpx` 即可。
就是把 `传统编写方式` 中写在 `css` 中的样式搬到了 `UnoCSS` 中。
如果要想用 `w-100` 这种方式,需要做额外的处理(待验证):
:::details
太忙了,有空再写吧。
:::
## 总结
本文主要介绍了 `UnoCSS` 的使用,以及 `unocss.config.ts` 中的一些配置项。
同时说明了设计稿在两种编写方式下的宽度的设置,分别为 `750``1500`.
最后说明一下,`原子化CSS``传统方式` 两者不是互斥的,他们是互补的,合适的地方使用合适的方式。

189
docs/base/5-icons.md Normal file
View File

@@ -0,0 +1,189 @@
# 图标篇
本文主要介绍了 `图标` 的使用方式,通常有以下几种方式使用图标:
- `UI 库 Icons`
- `UnoCSS Icons`
- `iconfont`
下面笔者一一介绍
## UI 库 Icons
如果您已经引入了 `UI库`,并且正好该 `UI库` 已经有你想要的 `Icons`,那直接用最方便了,无需额外引入其他库,代码也是最少的。
这里介绍几个常用 `UI库` 的图标使用。
### `uni-ui Icons`
> 注意:`uni-ui Icons` 颜色只能通过 `color` 属性设置;使用 `UnoCSS` 设置无效。
```html
<uni-icons type="contact" size="30"></uni-icons>
<uni-icons type="contact" size="30" color="red"></uni-icons>
<uni-icons type="contact" size="30" class="text-green"></uni-icons>
<uni-icons type="contact" size="30" color="red" class="text-green"></uni-icons>
```
![alt text](./assets/5-1.png)
### `wot-ui Icons`
> 注意:`wot-ui icons` 颜色可以通过 `color` 属性设置,也可以通过 `UnoCSS` 设置;同时设置时,`color` 属性优先级高。
```html
<wd-icon name="add-circle"></wd-icon>
<wd-icon name="add-circle" color="red"></wd-icon>
<wd-icon name="add-circle" class="text-green"></wd-icon>
<wd-icon name="add-circle" class="text-green" color="red"></wd-icon>
```
![alt text](./assets/5-2.png)
### `uv-ui Icons`
> 注意:跟 `uni-ui Icons` 一样,`uv-ui Icons` 的颜色只能通过 `color` 属性设置;使用 `UnoCSS` 设置无效。
```html
<uv-icon name="home"></uv-icon>
<uv-icon name="home" color="red"></uv-icon>
<uv-icon name="home" class="text-green"></uv-icon>
<uv-icon name="home" color="red" class="text-green"></uv-icon>
```
![alt text](./assets/5-3.png)
> 注意,经过检测这 `3个UI库Icons` 都不支持使用 `UnoCSS` 改变大小(优先级低被覆盖),必须使用 `size` 属性来设置大小才有效果(行内样式优先于 css 样式)。
>
> 另外,经过检测,都支持动态 `iconName`和动态 `color` ! 即下面这样的写法是生效的:
```ts
const iconName = ref<string>('contact')
const colorName = ref<string>('red')
onLoad(() => {
setTimeout(() => {
iconName.value = 'chat'
colorName.value = 'green'
}, 1000)
})
```
```html
<uni-icons :type="iconName" :color="colorName" class="text-green w-8"></uni-icons>
<!-- 其他2个UI库同样生效 -->
```
## `UnoCSS Icons`
`UnoCSS Icons` 可以方便接入 `iconify` 图标库,后者拥有 `10万+` 的海量图标,总能找到你想要的。
### 1. 安装 iconify
在使用 `iconify` 之前需要安装对应的图标库,安装格式如下:
`pnpm i -D @iconify-json/[the-collection-you-want]`
以安装 `carbon` 为例,执行 `pnpm i -D @iconify-json/carbon` 即可。
> `unibest` 已经装好了 `carbon` 图标库,可以直接使用。
### 2. 找到 iconify 想要的图标名
打开网址:<https://icones.js.org/>
- 在里面找到某个库,如 `carbon`
![alt text](./assets/5-4.png)
- 搜索想要的图表,如 `avatar`,出现的搜索结果,查看类名,也可以点击图标,会出现详情( `details` 里面)。
![alt text](./assets/5-5.png)
![alt text](./assets/5-6.png)
- 如上图( `details` 里面),拿到 `carbon:user-avatar`
### 3. 编写代码
- 代码里面 `class` 填写 `i-carbon-user-avatar`(所有的单词用中划线连接即可)并且支持改颜色。
```html
<view class="i-carbon-user-avatar text-red" />
```
![alt text](./assets/5-7.png)
> 如果图标没有预览效果,请安装 `VSCode` 插件 `antfu.iconify`。
预览效果:
![alt text](./assets/5-8.png)
### 4. 动态图标名
昨天有网友反馈,`UnoCSS Icons` 无法使用动态类名,我来试试:(我先说结论:是支持的!)
```ts
const iconName = ref<string>('i-carbon-car')
onLoad(() => {
setTimeout(() => {
iconName.value = 'i-carbon-user-avatar'
}, 1000)
})
```
```html
<view :class="iconName" />
```
一秒后会由 `i-carbon-car`(一辆车) 变成 `i-carbon-user-avatar`(一个头像),一切都是 OK 的。
> 但是注意,跨文件的话动态图标名不能生效。
## iconfont 图标库
`iconfont` 同样有海量免费的图标,同时支持上传自己的图标。公司项目通常会有自己的图标,由专业的 `UI设计师` 设计,这时通常会使用 `iconfont` 方式使用图标。
- 1. 打开`阿里巴巴矢量图标库 iconfont`,地址:[https://www.iconfont.cn/](https://www.iconfont.cn/),并登录。
- 2. 寻找需要的图标,加入项目,也可以上传自己的图标。
- 3. 图标方式选择 `Font class``项目设置` 勾选上 `base64`,否则`非H5端` 不支持,然后点击生成链接。
![alt text](./assets/5-9.png)
![alt text](./assets/5-10.png)
- 4. 把上面的 `css` 链接里面的内容写入在 `style/iconfont.css`,并引入到 `style/index.scss`
- 5. 页面上直接写 `<i class="iconfont icon-package text-red"></i>` 即可!
```html
<view class="m-4">
<text mr-2>iconfont:</text>
<i class="iconfont icon-package text-red"></i>
<i class="iconfont icon-chat text-red"></i>
<i class="iconfont icon-my text-red"></i>
</view>
```
预览如下:
![alt text](./assets/5-11.png)
> 上面的选择有疑问的可以看详细版 - [iconfont 详细版](/other/iconfont/iconfont)
## 其它图标库
其他优秀的可以免费商用的图标库:
- 字节跳动的 `IconPark`,链接 [https://iconpark.oceanengine.com](https://iconpark.oceanengine.com/)。
- 不知道谁家的 `yesicon`,链接 [https://yesicon.app](https://yesicon.app/)。
## 总结
本文介绍了 `3` 种使用图标的方式,分别是 `UI 库 Icons``UnoCSS Icons``iconfont`
- `UI 库 Icons` 颜色和大小属性都主要由 `UI 库` 本身控制,且都支持动态图标名和动态颜色。
- `UnoCSS Icons` 最省心,强烈推荐使用。
- `iconfont` 需要勾选 `Base64` 才能兼容多端。
全文完~

181
docs/base/6-svg.md Normal file
View File

@@ -0,0 +1,181 @@
# SVG 篇
上一章《五、图标篇》主要介绍了 `线上图标` 的使用,今天带给大家本地 `SVG` 图标的使用。
本地 `SVG` 图标使用方式主要有:
- `image + src` 方式
- `static目录` 图标
- `相对目录` 图标
- `线上地址` 图标
> **`图片`** 也是使用上面几种方式。
## `image + src` 方式
根据图片地址不同,分为 2 种:`static目录`图标 `相对目录`图标。
### 1. `static目录` 图标
这种方式直接编写代码即可,如下:
```html
<image src="/static/svg/demo.svg" mode="scaleToFill" class="h-20 w-20" />
```
### 2. `相对目录` 图标
这种方式需要先引入,再使用,代码编写如下:
```html
<template>
<image :src="iconUrl" mode="scaleToFill" class="h-20 w-20" />
</template>
<script lang="ts" setup>
import iconUrl from './demo.svg'
</script>
```
### 3. `线上地址` 图标
这种方式直接使用,代码编写如下:
```html
<template>
<image src="https://xxx.com/demo.svg" mode="scaleToFill" class="h-20 w-20" />
</template>
```
## 其他
> `SvgComponent` 方式 和 `SvgIcon` 方式,仅 `H5端` 适用,感兴趣的可以阅读下
:::details
### `SvgComponent` 方式
`Web端` 过来的同学都知道 `SvgComponent` 这种方式,只需要引入 `vite-svg-loader` 插件即可,支持 `3种` 方式引入 `svg`: `url`, `raw`, `component`
- URL
SVGs can be imported as URLs using the `?url` suffix:
```js
import iconUrl from './my-icon.svg?url'
// 'data:image/svg+xml...'
```
Used in template:
```html
<template>
<image :src="iconUrl" mode="scaleToFill" class="h-20 w-20" />
</template>
```
- Raw
SVGs can be imported as strings using the `?raw` suffix:
```js
import iconRaw from './my-icon.svg?raw'
// '<?xml version="1.0"?>...'
```
Used in template:
```html
<template>{{ iconRaw }}</template>
```
- Component
SVGs can be explicitly imported as Vue components using the `?component` suffix:
```js
import IconComponent from './my-icon.svg?component'
// <IconComponent />
```
Used in template:
```html
<template>
<IconComponent />
</template>
```
但是目前经过测试,只有 `url` 的方式所有端可以使用,与上面的 `image + src - 相对目录 图标` 是一个效果。至于 `component` 只有 `H5端生效`,其他端不行。
### `SvgIcon` 方式
`Web端` 过来的同学都知道 `SvgIcon` 这种方式,只需要引入 `vite-plugin-svg-icons` 插件 + `vite 配置`,再编写一个通用的 `SvgIcon` 即可,但是同样只有 `H5端生效`,其他端不行。
`vite` 配置如下:
```
createSvgIconsPlugin({
// 指定要缓存的文件夹
iconDirs: [path.resolve(process.cwd(), 'src/assets')],
// 指定symbolId格式
symbolId: 'icon-[dir]-[name]',
}),
```
如上,只需要把 `svg` 放到 `src/assets` 目录即可。
`SvgIcon` 代码如下:
```html
<template>
<svg aria-hidden="true">
<use :href="symbolId" :fill="color" />
</svg>
</template>
<script lang="ts" setup name="SvgIcon">
const props = withDefaults(
defineProps<{
prefix?: string
name: string
color?: string
}>(),
{
prefix: 'icon',
name: '',
color: '#333',
},
)
const symbolId = computed(() => `#${props.prefix}-${props.name}`)
</script>
```
使用方式如下:
```html
<!-- src/assets/demo.svg -->
<SvgIcon name="demo" class="h-20 w-20"></SvgIcon>
<!-- src/assets/dir/demo.svg -->
<SvgIcon name="dir-demo" class="h-20 w-20"></SvgIcon>
```
> `SvgComponent` 依赖 `vite-svg-loader` 插件
>
> `SvgIcon` 依赖 `vite-plugin-svg-icons` 插件
:::
## 总结
本地 `svg` 的使用方式,如果要全端适配,那就只能使用 `image + src` 的方式。
> `SvgComponent` 依赖 `vite-svg-loader` 插件
>
> `SvgIcon` 依赖 `vite-plugin-svg-icons` 插件
其他 2 种方式 —— `SvgComponent` + `SvgIcon``h5` 端生效,其他端都不能用,既然不能使用,那就删了,对应的 2 个插件也一起删了,目前 `base` 分支已经删了。
全文完~

120
docs/base/7-ui.md Normal file
View File

@@ -0,0 +1,120 @@
# UI 库替换篇
## 默认 UI 库
`unibest` 经过几次更迭,先后使用 `uni-ui``uv-ui`作为默认 UI 库,目前使用 `wot-ui` 为默认 UI 库。
`wot-ui``vue3+ts` 编写的全端支持的 UI 库,编码体验比 `uv-ui` 更好;而官方维护的 `uni-ui` 则样式略丑,组件较少,故弃之。
> `wot-ui` 全称 `wot-design-uni`,是 `wot-design` 的 `uniapp` 版本,文档地址:[https://wot-design-uni.netlify.app/](https://wot-design-uni.netlify.app/).
---
很多群友反馈有其他 `UI` 库的需求,那么更换 `UI 库` 需要哪些步骤呢?
- 先卸载原有的 `wot-ui`
- 再安装其他 `UI 库`
下面我们简单描述一下更换 2 个主流 `UI库` —— `uni-ui` + `uv-ui` 的过程。
> 当然也支持同时存在多个 `UI 库`,有 ES 摇树特性,不必担心打包后的体积。
## 卸载 wot-ui 库
卸载 `wot-ui` 过程如下:
- 1. 删除 `wot-ui` 库:
```sh
pnpm un wot-design-uni
```
- 2. `pages.config.ts` 文件 `easycom.custom` 删除相关配置:
```diff
easycom: {
autoscan: true,
custom: {
- '^wd-(.*)': 'wot-design-uni/components/wd-$1/wd-$1.vue',
},
},
```
- 3. ` tsconfig.json` 文件 `compilerOptions.types` 删除相关配置:
```diff
"types": [
"@dcloudio/types",
"@types/wechat-miniprogram",
- "wot-design-uni/global.d.ts",
"./components.d.ts",
"./global.d.ts"
]
```
## 安装 `uni-ui` 库
- 1. 安装 `uni-ui` 库:
```sh
pnpm add @dcloudio/uni-ui
```
- 2. `pages.config.ts` 文件 `easycom.custom` 添加相关配置:
```diff
easycom: {
autoscan: true,
custom: {
+ '^uni-(.*)': '@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue',
},
},
```
- 3. ` tsconfig.json` 文件 `compilerOptions.types` 添加相关配置:
```diff
"types": [
"@dcloudio/types",
"@types/wechat-miniprogram",
+ "@uni-helper/uni-ui-types",
"./components.d.ts",
"./global.d.ts"
]
```
## 安装 `uv-ui` 库
- 1. 安装 `uv-ui` 库:
```sh
pnpm add @climblee/uv-ui
```
- 2. `pages.config.ts` 文件 `easycom.custom` 添加相关配置:
```diff
easycom: {
autoscan: true,
custom: {
+ '^uv-(.*)': '@climblee/uv-ui/components/uv-$1/uv-$1.vue',
},
},
```
- 3. ` tsconfig.json` 文件 `compilerOptions.types` 添加相关配置:
```diff
"types": [
"@dcloudio/types",
"@types/wechat-miniprogram",
+ "@ttou/uv-typings/shim",
+ "@ttou/uv-typings/v2",
"./components.d.ts",
"./global.d.ts"
]
```
> 其他 UI 库的安装类似,不再赘述。
全文完~

163
docs/base/8-request.md Normal file
View File

@@ -0,0 +1,163 @@
# 请求篇
本篇分为三块内容:
- 普通请求
- 图片上传
- 多后台地址
## 普通请求
普通请求分 2 种处理,一种是只在页面请求一次的一次性请求,这种请求占大多数;一种是项目多处用到的请求,这种请求占小部分,需要单独编写一个请求函数放到 `api文件夹` or `service文件夹`
> `unibest` 里面是使用 `service文件夹` 后面不再说明。
下面来分别演示:
### 一次性请求
`template` 部分编码如下:
```html
<template>
<button @click="run">请求</button>
<view v-if="loading" class="text-blue h-10">请求中...</view>
<view v-if="error" class="text-red h-10">请求错误</view>
<view v-else class="text-green h-10">{{ JSON.stringify(data) }}</view>
</template>
```
`script` 部分使用 `菲鸽` 封装好的 `useRequest` 即可实现请求状态一体化,如下:
```ts
<script setup>
type IFooItem = { name: string }
const { loading, error, data, run } = useRequest<IFooItem>(() => httpGet('/foo', { name: '菲鸽' }))
</script>
```
看吧,使用非常简单。
### 重复性请求
`重复性请求``一次性请求``html部分` 是一样的,唯一的区别是 `请求函数` 放到了 `service文件夹`,如下所示:
```ts
<script setup>
import { getFooAPI, IFooItem } from '@/service/index/foo' // 看这里
const { loading, error, data, run } = useRequest<IFooItem>(() => getFooAPI('菲鸽'))
</script>
```
对应的 `src/service/index/foo.ts` 文件如下:
```ts
import { http, httpGet } from '@/utils/http'
export interface IFooItem {
id: string
name: string
}
/** GET 请求 */
export const getFooAPI = (name: string) => {
return http<IFooItem>({
url: `/foo`,
method: 'GET',
query: { name },
})
}
/** GET 请求 - 再次简化,看大家是否喜欢这种简化 */
export const getFooAPI2 = (name: string) => {
return httpGet<IFooItem>('/foo', { name })
}
```
依然非常简洁,深受妹子喜爱。
## 图片上传
`template` 部分编码如下:
```html
<template>
<view class="p-4 text-center">
<wd-button @click="run">选择图片并上传</wd-button>
<view v-if="loading" class="text-blue h-10">上传...</view>
<template v-else>
<view class="m-2">上传后返回的图片地址:</view>
<view class="m-2">{{ data }}</view>
<view class="h-80 w-full">
<image v-if="data" :src="data" mode="scaleToFill" />
</view>
</template>
</view>
</template>
```
`script` 部分使用 `菲鸽` 封装好的 `useUpload` 即可实现请求状态一体化,如下:
```ts
<script lang="ts" setup>
const { loading, data, run } = useUpload<string>({ user: '菲鸽' })
</script>
```
使用非常简单,深受汉子和妹子的喜爱。
## 多后台地址
上面的 `普通请求` 默认是只有一个请求地址的,在 `.env` 里面配置 `VITE_SERVER_BASEURL`,如下:
```text
VITE_SERVER_BASEURL = 'https://ukw0y1.laf.run'
```
并且在 `src/interceptors/request.ts` 里面有设置:
- 如果是 `http` 开头的请求路径,则直接请求
- 如果不是,则拼接上 `VITE_SERVER_BASEURL`
![alt text](./assets/8-1.png)
但在多后台地址时就不能这么玩了,需要处理如下:(关注上图的箭头部分)
```ts
// 可以写一个映射对象,如:
const proxyMap = {
cms:'http://localhost:8080/cms',
ums:'http://localhost:8080/ums',
}
// 拦截器部分(上图箭头部分)修改如下
Object.keys(proxyMap).forEach(key=>{
if(options.url.startsWith(`/${key}`)){
options.url = proxyMap[key] + options.url
}
}
// 接口调用的地方使用如下格式:
export const getFooAPI = (name: string) => {
return http<IFooItem>({
url: `/cms/foo`, // 看这里,前缀不用!!!
method: 'GET',
query: { name },
})
}
```
## 环境变量配置
- `普通请求` 需要在 `.env` 里面配置 `VITE_SERVER_BASEURL`,用在 `src/interceptors/request.ts` 文件拼接请求地址;而 `多后台地址` 时则用不上,可以删除。
```text
VITE_SERVER_BASEURL = 'https://ukw0y1.laf.run'
```
- `图片上传` 需要在 `.env` 里面配置 `VITE_UPLOAD_BASEURL`:
```text
VITE_UPLOAD_BASEURL = 'https://ukw0y1.laf.run/upload'
```
全文完~

165
docs/base/9-state.md Normal file
View File

@@ -0,0 +1,165 @@
# 状态篇
本文主要介绍了全局状态管理 `pinia` 和 简单状态 `ref` + `reactive`
## pinia
`unibest` 已经内置了 `Pinia` + `pinia-plugin-persistedstate`(数据持久化插件),并提供了开箱即用的示例。
### 兼容性处理
本身 `pinia-plugin-persistedstate` 是不支持 `uniapp` 的,但是 `pinia-plugin-persistedstate` 提供了修改 `storage` 存储 API 的方式(默认是 `localStorage`,是一个 `WEB API``非H5端` 不支持),目前 `unibest` 已经处理好了。关键代码如下:
```ts
import { createPinia } from 'pinia'
import { createPersistedState } from 'pinia-plugin-persistedstate' // 数据持久化
const store = createPinia()
store.use(
createPersistedState({
storage: {
getItem: uni.getStorageSync, // 看这里
setItem: uni.setStorageSync, // 看这里
},
}),
)
```
### 定义 `pinia` 全局状态
`src/store/xxx.ts` 里面编写代码,如下是 `src/store/count.ts` 文件。
注意 `defineStore` 第三个参数可以设置是否需要持久化,默认不需要。
```ts [src/store/count.ts]{26}
import { defineStore } from 'pinia'
import { ref } from 'vue'
export const useCountStore = defineStore(
'count',
() => {
const count = ref(0)
const increment = () => {
count.value++
}
const decrement = () => {
count.value--
}
const reset = () => {
count.value = 0
}
return {
count,
decrement,
increment,
reset,
}
},
{
// 如果需要持久化就写 true, 不需要持久化就写 false或者去掉这个配置项
persist: true,
},
)
```
> 请不要随意把数据丢到 `pinia`,能不用就不用。简单状态尽量使用 `ref` 或者 `reactive`。
### 使用 `pinia` 全局状态
在 `vue` 文件中就可以使用了,如下是 `src/pages/demo.vue` 文件:
```vue
<template>
<view class="flex justify-center items-center text-blue-500 mt-4 mb-4">
<view class="w-20">Count: {{ countStore.count }}</view>
<button class="ml-2 mr-2" @click="countStore.decrement">-1</button>
<button class="ml-2 mr-2" @click="countStore.increment">+1</button>
<button class="ml-2 mr-2" @click="countStore.reset">重置</button>
</view>
</template>
<script lang="ts" setup>
import { useCountStore } from '@/store'
const countStore = useCountStore()
</script>
```
## 简单状态
你可以直接使用 `Vue` 提供的 `ref` 或 `reactive` 方法来做简单状态管理。
### ref
如下是 `src/pages/demo/useCount.ts` 文件,定义简单状态。
```ts [src/pages/demo/useCount.ts]
// 全局状态
const globalCount = ref(1)
export function useCount() {
// 本地状态
const localCount = ref(1)
function increment() {
globalCount.value++
localCount.value++
}
return {
globalCount,
localCount,
increment,
}
}
```
如下是 `src/pages/demo/index.vue`,与 `ref` 简单状态文件放到同一个目录下,方便管理。
```vue [src/pages/demo/index.vue]
<script setup lang="ts">
import useCount from './useCount.ts'
const { globalCount, localCount, increment } = useCount()
</script>
<template>
<button @click="increment()">
{{ globalCount }}
{{ localCount }}
</button>
</template>
```
## reactive
`reactive` 与 `ref` 类似。
如下是 `src/pages/demo/count.ts` 文件,定义状态。
```ts [src/pages/demo/count.ts]
export const countStore = reactive({
count: 0,
increment() {
this.count++
},
})
```
如下是 `src/pages/demo/index.vue`,与 `reactive` 简单状态文件放到同一个目录下,方便管理。
```vue [src/pages/demo/index.vue]
<script setup lang="ts">
import { countStore } from './count.ts'
</script>
<template>
<button @click="countStore.increment()">
{{ countStore.count }}
</button>
</template>
```
## 总结
本文介绍了 `unibest` 里面状态管理的 `2` 种方式:`pinia` 全局状态 和 `ref\reactive` 简单状态,分别演示了如何定义状态和使用状态。
注意需要灵活使用 `pinia` 和 `简单状态`,局部的状态尽量使用 `简单状态` 的方式来处理,减少 `pinia` 里面全局变量的数量。
全文完~

BIN
docs/base/assets/1-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 291 KiB

BIN
docs/base/assets/10-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

BIN
docs/base/assets/10-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

BIN
docs/base/assets/10-3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

BIN
docs/base/assets/10-ios.mp4 Normal file

Binary file not shown.

BIN
docs/base/assets/11-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
docs/base/assets/11-10.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 485 KiB

BIN
docs/base/assets/11-100.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

BIN
docs/base/assets/11-11.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 KiB

BIN
docs/base/assets/11-12.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 484 KiB

BIN
docs/base/assets/11-13.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 245 KiB

BIN
docs/base/assets/11-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

BIN
docs/base/assets/11-3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

BIN
docs/base/assets/11-4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

BIN
docs/base/assets/11-5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

BIN
docs/base/assets/11-6.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 KiB

BIN
docs/base/assets/11-7.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 642 KiB

BIN
docs/base/assets/11-8.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 888 KiB

BIN
docs/base/assets/11-9.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 705 KiB

BIN
docs/base/assets/13-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

BIN
docs/base/assets/13-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

BIN
docs/base/assets/13-3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

BIN
docs/base/assets/13-4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

BIN
docs/base/assets/13-5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

BIN
docs/base/assets/13-6.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 KiB

BIN
docs/base/assets/13-7.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 KiB

BIN
docs/base/assets/13-8.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 286 KiB

BIN
docs/base/assets/14-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

BIN
docs/base/assets/14-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

BIN
docs/base/assets/14-3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

BIN
docs/base/assets/14-4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

BIN
docs/base/assets/14-5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 513 KiB

BIN
docs/base/assets/14-6.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 549 KiB

BIN
docs/base/assets/15-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

BIN
docs/base/assets/15-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

BIN
docs/base/assets/15-3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

BIN
docs/base/assets/15-4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 KiB

BIN
docs/base/assets/15-5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

BIN
docs/base/assets/15-6.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

BIN
docs/base/assets/2-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 KiB

BIN
docs/base/assets/2-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

BIN
docs/base/assets/2-3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

BIN
docs/base/assets/2-4.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 648 KiB

BIN
docs/base/assets/3-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 536 KiB

BIN
docs/base/assets/4-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 232 KiB

BIN
docs/base/assets/4-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 KiB

BIN
docs/base/assets/4-3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

BIN
docs/base/assets/4-4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 317 KiB

BIN
docs/base/assets/4-5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 542 KiB

BIN
docs/base/assets/5-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
docs/base/assets/5-10.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

BIN
docs/base/assets/5-100.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
docs/base/assets/5-11.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
docs/base/assets/5-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
docs/base/assets/5-3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

BIN
docs/base/assets/5-4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 418 KiB

BIN
docs/base/assets/5-5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

BIN
docs/base/assets/5-6.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

BIN
docs/base/assets/5-7.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

BIN
docs/base/assets/5-8.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
docs/base/assets/5-9.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

BIN
docs/base/assets/8-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 534 KiB

BIN
docs/base/image.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

BIN
docs/base/ui/image-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

BIN
docs/base/ui/image-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

BIN
docs/base/ui/image.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

125
docs/base/ui/ui.md Normal file
View File

@@ -0,0 +1,125 @@
# UI 库选型篇
## 背景
`unibest` 作为最好的 `uniapp` 开发模板,那 `UI 框架` 的选择也是要仔细斟酌的。
`unibest` 作为 `vue3` 项目,`vue2` 时代的 `uview` 就不考虑在内了。但是在 `uview` 的基础上衍生出来的支持 `vue3``uview 系``ui框架` 还有不少,而且热度很高。
官方维护的 `uni-ui`,支持全端,而且有类型提示,但样式略丑,且其他优秀的 `UI 库` 已经包含了 `uni-ui` 的组件,所以直接用第三方 `UI 库` 就好了。
> tip1: `uni-ui` 本身是 `js` 开发的,但是官方提供了完备的类型提示( by `@uni-helper/uni-ui-types`)所以看起来就像是 `ts` 开发的一样,开发体验很好。所有的组件都有提示,很方便,很贴心。
> tip2: 再次重申一下 `uview` 不支持 `Vue3`,不然又有人问我为啥不用 `uview`。(臣妾做不到啊~
## UI 库总览
经过搜寻了一番,目前参加对比的 UI 框架有:
- uv-ui (uveiw 系) - [文档地址](https://www.uvui.cn/)
- uview-plus (uveiw 系) - [文档地址](https://uiadmin.net/uview-plus/)
- Wot Design Uni (wot 系) - [文档地址](https://wot-design-uni.netlify.app/)
- TuniaoUI (图鸟系) - [文档地址](https://vue3.tuniaokj.com/zh-CN/)
还有 2 个 UI 框架也很优秀,但是只有部分组件开源免费,大半组件收费,咱暂不考虑。
- FirstUI [文档链接](https://doc.firstui.cn/)
- ThorUI [文档链接](https://thorui.cn/doc/)
> 温馨提示:收费没有对错,只要做得好,提供优质的组件,别人愿意付费,也是极好的。
---
下面通过几个方面对 `UI 库` 进行对比
## 开源热度
截止到 `2024-05-30` 发表文章时的数据:
| UI 框架 | uv-ui | uview-plus | wot-ui | TuniaoUI |
| ------------ | :---: | :--------: | :----: | :------: |
| github stars | 568 | 362 | 492 | 192 |
| gitee stars | 555 | 126 | 35 | - |
| github forks | 1.1k | 158 | 188 | 20 |
| gitee forks | 75 | 4 | 30 | - |
其实到这里就一决高下了,`github star 数` `uv-ui(568)` > `wot-ui(492)` > `uview-plus(362)` > `TuniaoUI(192)`,其中 `uv-ui``wot-ui` 拔得头筹。
[![Star History Chart](https://api.star-history.com/svg?repos=Moonofweisheng/wot-design-uni,climblee/uv-ui,ijry/uview-plus,tuniaoTech/tuniaoui-rc-vue3-uniapp&type=Date)](https://star-history.com/#Moonofweisheng/wot-design-uni&climblee/uv-ui&ijry/uview-plus&tuniaoTech/tuniaoui-rc-vue3-uniapp&Date)
源码仓库地址展示如下_纯粹为了方便大家查阅_ (虽然大概率你们也不会去访问,/手动狗头)
| UI 框架 | 文档地址 | github | gitee |
| ---------- | ------------------------------------- | ------------------------------------------------------- | ------------------------------------------------- |
| uv-ui | <https://www.uvui.cn/> | <https://github.com/climblee/uv-ui> | <https://gitee.com/climblee/uv-ui> |
| uview-plus | <https://uiadmin.net/uview-plus/> | <https://github.com/ijry/uview-plus> | <https://gitee.com/uiadmin/uview-plus> |
| wot-ui | <https://wot-design-uni.netlify.app/> | <https://github.com/Moonofweisheng/wot-design-uni> | <https://gitee.com/wot-design-uni/wot-design-uni> |
| TuniaoUI | <https://vue3.tuniaokj.com/zh-CN/> | <https://github.com/tuniaoTech/tuniaoui-rc-vue3-uniapp> | - |
> 接着奏乐接着舞,我们继续正文 ^\_^
## 多端支持情况
| UI 框架 | uv-ui | uview-plus | wot-ui | TuniaoUI |
| ------------ | ----- | ---------- | ------ | -------- |
| h5 | ✅ | ✅ | ✅ | ✅ |
| app(ios) | ✅ | ✅ | ✅ | ✅ |
| app(android) | ✅ | ✅ | ✅ | ✅ |
| 微信小程序 | ✅ | ✅ | ✅ | ✅ |
| 支付宝小程序 | ✅ | ✅ | ✅ | ✅ |
| QQ 小程序 | ✅ | ✅ | ❌ | ❌ |
| 百度小程序 | ✅ | ✅ | ❌ | ❌ |
| 头条小程序 | ✅ | ✅ | ❌ | ❌ |
## 组件数量
| UI 框架 | uv-ui | uview-plus | wot-ui | TuniaoUI |
| -------- | :---: | :--------: | :----: | :------: |
| 总数 | 67 | 67 | 71 | 55 |
| 基础组件 | 8 | 11 | 8 | 5 |
| 表单组件 | 16 | 17 | 20 | 14 |
| 数据组件 | 13 | 4 | 18 | 4 |
| 反馈组件 | 8 | 10 | 16 | 8 |
| 布局组件 | 7 | 9 | - | 8 |
| 导航组件 | 8 | 8 | 9 | 5 |
| 其他组件 | 7 | 8 | - | 5 |
| 内容组件 | - | - | - | 6 |
组件数:`wot(71)` > `uv-ui(67)` = `uview-plus(67)` > `TuniaoUI(55)`
## `ts` 支持情况
查看 4 个组件库的源码,可以了解到:
- `uv-ui``uView-plus` 都是 `js` 写的,并非 `ts`,可以通过 `ttou/uv-typings` 提供类型支持。
- `wot``TuniaoUI` 都是 `ts` 写的,编码体验会好很多。
> 小知识:代码里如何辨别一个库是否有 ts 支持,写代码的时候按 `ctrl + i` (Mac 里 `cmd + i`),如果有提示就是有,啥都没有就是没有。
>
> 举个例子,编写 `<xx-button type="" ...`,在 `type=""` 双引号里面按 `ctrl + i`,看提示就知道了。
- `wot` 有提示
![alt text](image.png)
- ~~`uv-ui` 无提示~~
![alt text](image-1.png)
`tsconfig.json` 文件里面 `types` 里面的 `@ttou/uv-typings/v3` 改为 `@ttou/uv-typings/v2` 就正常了(也是群友发现的),如下。
![alt text](image-2.png)
## `wot-ui` 和 `uv-ui` 皇城 `PK`
`wot-ui``uv-ui` 皇城 `PK`
[![Star History Chart](https://api.star-history.com/svg?repos=Moonofweisheng/wot-design-uni,climblee/uv-ui&type=Date)](https://star-history.com/#Moonofweisheng/wot-design-uni&climblee/uv-ui&Date)
目前 `wot-ui` 还是比不过 `uv-ui` 的,但是我 `wot-ui` 有反超的势头。主要是看了源码后,还是选定了 `vue3+ts` 编写的 `wot-ui`
> 别说我偏心,两位 `ui` 框架的作者都是我的好友,我是 `uv-ui` 群的管理员,`wot-ui` 作者在我的大群里面。选择 `wot-ui` 确实因为它很优秀。
## 总结
很高兴我们已经为宇宙最强 `uniapp` 开发模板 `unibest` 选好了 `UI 组件库``wot-ui` 是最终的幸运儿。为此我特意去 `wot-ui` 官网里面捐赠了一杯咖啡钱给作者,开源不易,要支持一下。