--- url: 'https://unibest.tech/advanced/showcase/showcase.md' --- # ⭐ 优秀案例 我们非常欢迎大家一起贡献优秀的案例,欢迎在此 [issue](https://github.com/feige996/unibest/issues/139) 提交案例。 `unibest` 已被很多公司和团队在生产环境使用,下面是一些优秀的案例: --- --- url: 'https://unibest.tech/advanced/contact/contact.md' --- # ⭐ 联系我 如果你有商业上的合作需求,或者想定制化 unibest,欢迎联系我,备注:商业合作。 如果你有外包需求,也可以联系我,备注:外包。 --- --- url: 'https://unibest.tech/advanced/rewards/rewards.md' --- # 🥤 打赏 如果本项目对你的工作起到了帮助,加快了您的项目进展,解决了您的问题,欢迎 `打赏` ! # 交流群 千万记得 `先看一遍文档`,可以解决大部分基础疑问。 > 必看章节:[uni 插件篇](/base/3-plugin) 和 [常见问题](/base/14-faq) ## 免费 QQ 群 ①②③④⑤⑥⑦ 群已满,下面是 ⑧ 群。 ## 付费微信群 目前已经有 `9个` 微信群,维护需要精力(回答各种问题 + 微信群 7 天就过期)。从 `2025-07-01` 开始,不再提供免费微信交流群。 如果确实有需要的,进群后发 `专属红包 20元` 给群主 `菲鸽` 即可。(注意:没发的会被移出群聊。) > 专属红包这样发: ## 联系我 如果你有商业上的合作需求,或者想定制化 unibest,欢迎联系我,备注:`商业合作`。 如果你有外包需求,也可以联系我,备注:`外包`。 --- --- url: 'https://unibest.tech/base/18-app.md' --- # App 专题 ![alt text](./assets/11-22.png) ## 1. 其他端正常,`App` 白屏 请检查 `useXxxStore` 的调用,需要在函数内部调用,而不是在函数外部调用。(估计是顶层调用的时候 `pinia` 没有初始化,导致的问题,`app` 端独有的问题。) ```ts // 错误写法 const userStore = useUserStore(); function foo() { userStore.xxx; } // 正确写法 function foo() { const userStore = useUserStore(); userStore.xxx; } ``` ## 2.unibest 的 `App` 模块配置 > 核心解决办法就是把 `manifest.json` 的内容搬运到 `manifest.config.ts` 中。 我们默认的的 `manifest.config.ts` 只包含了比较基础的 `uniapp` 配置,有的时候我们需要在打包 `app` 时在 `hbuilderx` 里面额外设置一些配置,那么就需要配置好后把 `manifest.json` 中的内容拷贝到 `manifest.config.ts` 中,后面运行就不会丢失了。 举例子,我在 `manifest.json` 里面配置了 2 个模块配置,如下: ![alt text](image-18.png) 点击左侧下面的 `源码视图` 就可以看到增加了如下内容: ![alt text](image-18-2.png) 只需要把对应的内容拷贝到 `manifest.config.ts` 中的 `distribute.plugins` 里面即可。 ## 3. `app` 热更新 ### 3.1 `ios` 模拟器热更新 * `pnpm dev:app` * 把 `dist/dev/app` 文件夹导入到 `hbx编辑器` 里面,然后运行。这样在编码的时候是可以热更新的。 > 但是上面的方法,在 android 模拟器里面不生效。 ### 3.2 `android` 热更新 * 在 `android` 里面,把`dist/dev/app` 文件夹导入到 `hbx编辑器` 里面运行,无法热更新!! * 需要把整个 `unibest 项目文件夹` 导入到 `hbx编辑器` 里面,然后运行,这样就可以热更新。 * 不管是模拟器还是真机调试,都是这样。 ![alt text](./assets/11-23.png) ### 3.3. `鸿蒙` 热更新 同 `android` 热更新。 ## 4. 打包原生插件 这里说的是传统 `uni-app App` 原生语言插件,不是 `UTS` 插件。 > 思路:把整个 `unibest` 项目导入 `HBuilderX`,把本地原生插件放到项目根目录的 `nativeplugins` 目录,在 `src/manifest.json` 里配置好 `App 原生插件`,再把新增配置同步到 `manifest.config.ts`,最后制作包含该插件的自定义运行基座。 > > 注意:标准基座不包含你自己的本地原生插件。出现“当前运行的基座不包含原生插件”时,通常是还在使用标准基座,或者自定义基座没有重新包含该插件。 > > `pnpm build:app` 会把项目根目录的 `nativeplugins` 自动复制到 `dist/build/app/nativeplugins`。如果没有复制,请确认 `env/.env` 中的 `VITE_COPY_NATIVE_RES_ENABLE` 为 `true`。 步骤: * 1. 把本地原生插件放到项目根目录的 `nativeplugins` 目录下。目录名使用官方约定的全小写 `nativeplugins`。 * 2. 在 `HBuilderX` 里打开整个 `unibest` 项目,在 `src/manifest.json` 的 `App 原生插件配置` 中选择本地插件。 ![alt text](18-app-1.png) * 3. 切换到 `manifest.json` 源码视图,把新增的原生插件配置同步到 `manifest.config.ts`。因为 `src/manifest.json` 是生成文件,只改它后续会被覆盖。 * 4. 制作自定义运行基座。 ![alt text](18-app-2.png) * 5. 使用自定义基座运行或真机调试。 ![alt text](18-app-3.png) * 6. 发布时再执行 `pnpm build:app`,然后在 `HBuilderX` 中导入 `dist/build/app` 进行云打包或本地打包。`pnpm build:app` 只负责生成 App 项目文件并复制 `nativeplugins`,不会自动制作自定义基座。 > 其他参看文章 [掘金教程 - Unibest 原生插件模块配置](https://juejin.cn/post/7496807547447427081) --- --- url: 'https://unibest.tech/changelog/CHANGELOG.md' --- # CHANGELOG 更新日志 > 完整的更新日志,查看 [github releases 日志](https://github.com/unibest-tech/unibest/releases) ## v4.0.16(2026-04-25) ### CLI 新增 `wot-ui-v2` 支持 * 新增 UI 选项 `wot-ui-v2`(`@wot-ui/ui`),并在交互中前置显示 * 保留 `wot-ui`(`wot-design-uni`)用于兼容旧项目 * 选择 `wot-ui-v2` 时自动注入 `wot-ui-resolver.ts` 与 `vite.config.ts` 的 `UniComponents` resolver 配置,修复 H5 下 `wd-*` 组件样式不生效问题 ## v4.0.15(2026-02-14) ### 新增图表库支持 * 新增 `lime-echart` 图表库特性支持 * 新增 `ucharts` 图表库特性支持 ### 新增 UI 库 * 新增 `tdesign` UI 库支持 ### Tabbar 增强 * 支持根据用户角色动态过滤标签页 * 新增关于页面,支持配置仅管理员可见的标签页 ### CI/CD 能力增强 * 新增上传脚本,自动化部署上传小程序代码 * 支持抖音小程序开发者工具自动打开 ### 其他优化 * 添加 demo 示例的分包配置 ## v4.0.0(2026-02-02) ### 重大更新 - CLI 脚手架重构 * **Monorepo 架构**:整合 CLI 脚手架到主仓库 * 新增 `packages/cli/` 目录,发布到 npm 包 `create-unibest` * CLI 从 Git base 分支克隆模板 * **新增 Feature 机制**:支持动态注入 i18n、login 等功能 * **简化使用方式**:支持命令行参数 `--i18n --login` * **新增 CLI 开发指南**:详见 [CLI 开发篇](/base/18-cli) * **文档更新**:新增使用方式优先级、架构说明等内容 ## v3.11.0(2025-08-24) ### 新增 `root 插件` 新增 `root 插件`,支持在 `App.ku.vue` 配置全局性的东西。 增加从 `App.ku.vue` 暴露状态的方法,以便在 `vue` 中使用。 ## v3.10.0(2025-08-22) ### 新增 `登录策略` * 新增 `登录策略` 配置项,用于配置登录时的策略。 * `DEFAULT_NO_NEED_LOGIN:0`:黑名单策略,默认可以进入 APP * `DEFAULT_NEED_LOGIN: 1`:白名单策略,默认不可以进入 APP,需要强制登录 * 外加配套的 `EXCLUDE_PAGE_LIST`: 排除在外的列表,白名单策略指白名单列表,黑名单策略指黑名单列表 * 并编写了配套的 `pages/login/login` 路由和 `pages/me/me` 路由,已经根据登录策略进行了跳转。 ## v3.8.0(2025-08-08) ### tabbar 改版 框架内支持 `UI库` 无关的自定义 `tabbar`,以便部分无 `tabbar` 组件的 `UI库` 的接入。 * 支持多种类型的图标( `uniUi Icons, uiLib Icons, unocss Icons, iconfont, image` 等) * 支持 `tabbar` 中间鼓包 (bulge) 的 `tabbatItem` ### 路由拦截增强 支持直接进入应用路由的的路由拦截,如 `h5` 直接输入路由、`微信小程序` 分享后进入等。 ## v3.4.0(2025-07-19) ### 多语言模版 * `tabbar` 和 `navbar` 无需用户自己做多语言的切换操作,框架已经处理好了。 详情请看 [多语言篇-tabbar 标题](/base/10-i18n#tabbar-标题) ## v3.0.0(2025-06-21-周六) ### 重大更新 * 原本的 `base`、`tabbar`、`spa` 合并为新的 `base` 模板。并把新的 `base` 分支重命名为 `main` 分支。详情见 [tabbar 专题](/base/2-tabbar.md) * 原本的 `main` 分支是文档相关的分支,已经单独放到新的仓库了。 > 掘金文章链接:[🎉 unibest 3.0 发布了!看看都更新了啥好用的功能~](https://juejin.cn/post/7518343357765124136) ### 格式化工具优化 * 鉴于 `oxlint` 暂时还不支持 `vue` 文件,考虑到不少团队很大,无法检测 `vue` 文件确实不妥,就使用了 `antfu` 的 `eslint-config`。 > 注意:等 `oxlint` 支持 `vue` 文件,我们第一时间加回来,真的非常快。 **提交代码的时候会自动触发。** 如果想主动检测,可以使用 `pnpm lint` 命令。 ## v2.12.1(2025-06-13) ### `oxlint` 优化 * `oxlint` 从 `0.11.0` 升级到 `1.0.0`。 > 注意:最新的 `1.1.0` 还有问题,运行报错,所以使用 `1.0.0`。(别贪新) **提交代码的时候会自动触发。** 如果想主动检测,可以使用 `pnpm lint` 命令。 ## v2.11.1(2025-06-11) ### `hello-unibest` * 新增 `echarts`(推荐) 和 `ucharts` 示例。 ### docs 文档 * 更新 `App 专题` `热更新`内容。( `android端` 无法热更新的问题,已经解决了!) ## v2.11.0(2025-06-03) ### 依赖降级 * 将 `unocss` 从 `66.0.0` 降级到 `65.4.2`。(因为有部分网友会出现问题,所以降级了。) ### 新模板 * 新增 `base-sard-ui` 模板,方便用户直接使用 `sard-ui` 这个 UI 库开发。 ## ... ## v0.0.0(2023-12.21) 创建项目,首次提交。 --- --- url: 'https://unibest.tech/base/18-cli.md' --- # CLI 开发指南 本篇介绍如何参与 `create-unibest` CLI 工具的开发。 ## 项目架构 unibest 采用 **Monorepo** 架构: ``` unibest/ ├── packages/ │ └── cli/ # CLI 脚手架源码(发布到 npm) ├── src/ # 模板源码 └── 其他配置文件 ``` **分支说明:** * **`main` 分支** - CLI 开发分支,包含 `packages/cli/` 和模板源码 * **`base` 分支** - 纯净模板,用户创建项目时克隆 ## 开发环境 ```bash # 前置依赖 node >= 20 pnpm >= 9 ``` ## 快速开始 ### 1. 克隆仓库 ```bash git clone https://github.com/feige996/unibest.git cd unibest ``` ### 2. 进入 CLI 目录 ```bash cd packages/cli ``` ### 3. 安装依赖 ```bash pnpm install ``` ### 4. 开发模式 ```bash pnpm dev ``` 开发模式下会监听文件变化,自动重新构建。 ### 5. 测试本地 CLI ```bash # 方式一:使用 start 脚本 pnpm start -- my-test-project # 方式二:直接运行 node bin/index.js my-test-project ``` ### 6. 构建发布 ```bash pnpm build ``` 构建产物输出到 `dist/` 目录。 ## 项目结构 ``` packages/cli/ ├── bin/ │ └── index.js # CLI 入口 ├── features/ # 功能模块 │ ├── i18n/ # 多语言功能 │ └── login/ # 登录功能 ├── src/ │ ├── commands/ # 命令实现 │ │ ├── add.ts # add 命令 │ │ └── create.ts # create 命令 │ ├── features/ # 功能加载器 │ ├── utils/ # 工具函数 │ └── index.ts # 入口 ├── package.json └── tsup.config.ts # 构建配置 ``` ## 发布到 npm ```bash # 1. 登录 npm npm login --registry=https://registry.npmjs.org/ # 2. 升级版本 npm version patch # 3. 构建 pnpm build # 4. 发布 npm publish --no-workspaces --registry=https://registry.npmjs.org/ ``` > 发布时可能会要求输入 OTP 验证码。 ## 添加新 Feature 1. 在 `features/` 目录下创建新文件夹 2. 添加 `hooks.js` 和 `package.json` 3. 在 `src/features/index.ts` 中注册 ## 调试技巧 ### 本地调试 ```bash # 使用本地模板测试 LOCAL_TEMPLATE=true pnpm start -- my-test-project ``` ### 查看日志 CLI 使用 `@clack/prompts` 提供交互式命令行界面,调试信息会直接输出到终端。 ## 相关资源 * [GitHub 仓库](https://github.com/feige996/unibest) * [npm 包](https://www.npmjs.com/package/create-unibest) * [AGENTS.md](https://github.com/feige996/unibest/blob/main/AGENTS.md) - AI 开发者指南 --- --- url: 'https://unibest.tech/base/13-hbx.md' --- # hbx 模板 为了方便使用 `HBuilderX` 的开发者,`unibest` 也提供 `hbx` 模板。 `hbx 模板` 适用于 `2 类用户` * \~~使用 `uniCloud` 云开发的用户,必须使用 `hbx 版本`,因为 `uniCloud` 跟 `HBuilderX` 是绑定的。~~ * 开发 `App` 的用户,可选使用 `hbx 版本`。 > 现在 `base` 模板已经完全可以替代 `hbx` 模板了,所以 `hbx` 模板不再维护。 > > 1. `base` 模板一样可以使用 `uniCloud` 云开发。 > 2. `base` 模板支持 `App` 开发,并且也可以热更新,详情请见 [APP 专区](./18-app)。 ## 仓库地址 > `hbx` 目前由 `青谷` 大佬维护,微信号:`qingguxixi`,[青谷 github 地址](https://github.com/Xiphin) 。 * gitee: [unibest-hbx](https://github.com/uni-run/unibest-hbx) * github: [unibest-hbx](https://github.com/uni-run/unibest-hbx) 没有梯子的用户优先推荐使用 `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` 模板的由来,使用方式。 有需要的可以试试,但是不太建议使用。另外精力有限,该模板不再维护。 全文完~ --- --- url: 'https://unibest.tech/base/6-svg.md' --- # SVG 篇 上一章《五、图标篇》主要介绍了 `内置图标` 的使用,今天带给大家本地 `SVG` 图标的使用。 > 注意:`小程序` 和 `APP` 都不支持 `SVG` 标签,只能通过 `image` 的方式使用。即下面的 `image + src` 方式。 * `image + src` 方式 * `static目录` 图标 * `相对目录` 图标 * `线上地址` 图标 > PS:`小程序` 和 `APP` 对 `图片` 也是这面几种方式,下面统一称为 “图片”。 ## `image + src` 方式 如果图片在项目里面,根据放的位置不同,分为 2 种:`static目录`图标 , `相对目录`图标。 ### 1. `static目录` 图标 这种方式直接编写代码即可,如下: ```html ``` ### 2. `相对目录` 图标 这种方式需要先引入,再使用,代码编写如下: ```html ``` ### 3. `线上地址` 图标 这种方式直接使用,代码编写如下: ```html ``` ## H5 额外支持的其他方式 > `SvgComponent` 方式 和 `SvgIcon` 方式,仅 `H5端` 适用,感兴趣的可以阅读下。 > 因为只有 `H5端` 支持,所以 unibest 没有引入这些,但是其他 `web` 项目可以参考。 :::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 ``` * Raw SVGs can be imported as strings using the `?raw` suffix: ```js import iconRaw from './my-icon.svg?raw' // '...' ``` Used in template: ```html ``` * Component SVGs can be explicitly imported as Vue components using the `?component` suffix: ```js import IconComponent from './my-icon.svg?component' // ``` Used in template: ```html ``` 但是目前经过测试,只有 `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 ``` 使用方式如下: ```html ``` > `SvgComponent` 依赖 `vite-svg-loader` 插件 > > `SvgIcon` 依赖 `vite-plugin-svg-icons` 插件 ::: ## 总结 适用于跨端的 `svg 和 图片` 的使用方式,只有 `image + src` 的方式。其他方式只能用于 `web` 端,仅供参考。 全文完~ --- --- url: 'https://unibest.tech/base/2-tabbar.md' --- # tabbar 专题 哔哩哔哩录制了视频,感兴趣的可以去看看,如果对您有帮助的话,记得一键三连哈。 ![alt text](2-tabbar-bilibili.png) ## 策略总览 > 2025-06-21 开始,新的 `base` 模板同时支持旧的 `tabbar` 和 `spa` 模板,这里大致介绍一下使用。(`tabbar` 和 `spa` 模板已经不再需要了。) `tabbar` 分为 `3 种` 情况:0,1,2。(`2025-12-31` 更新,去掉了几乎用不上的 `无缓存的自定义 tabbar`(3)) * 0: 'NO\_TABBAR' `无 tabbar` * 1: 'NATIVE\_TABBAR' `原生 tabbar` * 2: 'CUSTOM\_TABBAR' `自定义 tabbar` *** * 0 `无 tabbar`,只有一个页面入口,底部无 `tabbar` 显示;常用于临时活动页。 * 1 `原生 tabbar`,使用 `switchTab` 切换 tabbar,`tabbar` 页面有缓存。 * 优势:原生自带的 tabbar,最先渲染,有缓存。 * 劣势:只能使用 2 组图片来切换选中和非选中状态,修改颜色只能重新换图片(或者用 iconfont)。 * 2 `自定义 tabbar`,使用 `switchTab` 切换 tabbar,`tabbar` 页面有缓存。使用了第三方 UI 库的 `tabbar` 组件,并隐藏了原生 `tabbar` 的显示。 * 优势:可以随意配置自己想要的 `svg icon`,切换字体颜色方便。有缓存。可以实现各种花里胡哨的动效等。 * 劣势:首次点击 tabbar 会闪烁(据我所知,是无解的)。 ## 策略配置 首先选择使用哪个 `策略`,然后配置对应的 `tabbarList`。代码如下: ```ts /** * tabbar 选择的策略,更详细的介绍见 tabbar.md 文件 * 0: 'NO_TABBAR' `无 tabbar` * 1: 'NATIVE_TABBAR' `原生 tabbar` * 2: 'CUSTOM_TABBAR' `自定义 tabbar` * * 温馨提示:本文件的任何代码更改了之后,都需要重新运行,否则 pages.json 不会更新导致配置不生效 */ export const TABBAR_STRATEGY_MAP = { NO_TABBAR: 0, NATIVE_TABBAR: 1, CUSTOM_TABBAR: 2, }; // TODO: 1/3. 通过这里切换使用tabbar的策略 // 如果是使用 NO_TABBAR(0),nativeTabbarList 和 customTabbarList 都不生效 // 如果是使用 NATIVE_TABBAR(1),只需要配置 nativeTabbarList,customTabbarList 不生效 // 如果是使用 CUSTOM_TABBAR(2),只需要配置 customTabbarList,nativeTabbarList 不生效 export const selectedTabbarStrategy = TABBAR_STRATEGY_MAP.CUSTOM_TABBAR; // TODO: 2/3. 使用 NATIVE_TABBAR 时,更新下面的 tabbar 配置 export const nativeTabbarList: NativeTabBarItem[] = [ { iconPath: 'static/tabbar/home.png', selectedIconPath: 'static/tabbar/homeHL.png', pagePath: 'pages/index/index', text: '首页', }, { iconPath: 'static/tabbar/personal.png', selectedIconPath: 'static/tabbar/personalHL.png', pagePath: 'pages/me/me', text: '个人', }, ]; // TODO: 3/3. 使用 CUSTOM_TABBAR 时,更新下面的 tabbar 配置 // 如果需要配置鼓包,需要在 'tabbar/store.ts' 里面设置,最后在 `tabbar/index.vue` 里面更改鼓包的图片 export const customTabbarList: CustomTabBarItem[] = [ { text: '首页', pagePath: 'pages/index/index', // 注意 unocss 图标需要如下处理:(二选一) // 1)在fg-tabbar.vue页面上引入一下并注释掉(见tabbar/index.vue代码第2行) // 2)配置到 unocss.config.ts 的 safelist 中 iconType: 'unocss', icon: 'i-carbon-home', // badge: 'dot', }, { pagePath: 'pages/me/me', text: '我的', // 1)在fg-tabbar.vue页面上引入一下并注释掉(见tabbar/index.vue代码第2行) // 2)配置到 unocss.config.ts 的 safelist 中 iconType: 'unocss', icon: 'i-carbon-user', // badge: 10, }, // 其他类型演示 // 1、uiLib // { // pagePath: 'pages/index/index', // text: '首页', // iconType: 'uiLib', // icon: 'home', // }, // 2、iconfont // { // pagePath: 'pages/index/index', // text: '首页', // // 注意 iconfont 图标需要额外加上 'iconfont',如下 // iconType: 'iconfont', // icon: 'iconfont icon-my', // }, // 3、image // { // pagePath: 'pages/index/index', // text: '首页', // // 使用 ‘image’时,需要配置 icon + iconActive 2张图片 // iconType: 'image', // icon: '/static/tabbar/home.png', // iconActive: '/static/tabbar/homeHL.png', // }, ]; /** * 是否启用 tabbar 缓存 * NATIVE_TABBAR(1) 和 CUSTOM_TABBAR(2) 时,需要tabbar缓存 */ export const tabbarCacheEnable = [ TABBAR_STRATEGY_MAP.NATIVE_TABBAR, TABBAR_STRATEGY_MAP.CUSTOM_TABBAR, ].includes(selectedTabbarStrategy); /** * 是否启用自定义 tabbar * CUSTOM_TABBAR(2) 时,启用自定义tabbar */ export const customTabbarEnable = [TABBAR_STRATEGY_MAP.CUSTOM_TABBAR].includes( selectedTabbarStrategy ); /** * 是否需要隐藏原生 tabbar * CUSTOM_TABBAR(2) 时,需要隐藏原生tabbar */ export const needHideNativeTabbar = selectedTabbarStrategy === TABBAR_STRATEGY_MAP.CUSTOM_TABBAR; const _tabbarList = customTabbarEnable ? customTabbarList.map((item) => ({ text: item.text, pagePath: item.pagePath })) : nativeTabbarList; export const tabbarList = customTabbarEnable ? customTabbarList : nativeTabbarList; const _tabbar: TabBar = { // 只有微信小程序支持 custom。App 和 H5 不生效 custom: selectedTabbarStrategy === TABBAR_STRATEGY_MAP.CUSTOM_TABBAR, color: '#999999', selectedColor: '#018d71', backgroundColor: '#F8F8F8', borderStyle: 'black', height: '50px', fontSize: '10px', iconWidth: '24px', spacing: '3px', list: _tabbarList as unknown as TabBar['list'], }; export const tabBar = tabbarCacheEnable ? _tabbar : {}; ``` 上面的代码已经传到各个主分支了。 ## 自定义 tabbar 状态同步 自定义 tabbar 的选中状态以当前页面栈为准,模板会在应用恢复、H5 页面重新显示、tabbar 点击完成后重新同步一次 `curIdx`。 如果你在业务里手动改了路由逻辑,注意下面几点: * tabbar 页面跳转优先使用 `uni.switchTab`,不要只手动修改 `tabbarStore.curIdx`。 * 非 tabbar 页面返回后,不要强制把 `curIdx` 改成首页;应保留页面栈里最近的 tabbar 页面。 * 登录拦截、分享进入、H5 最小化后恢复这类场景,页面栈可能比生命周期参数更可靠,优先调用 `tabbarStore.syncCurIdxByCurrentPageAsync()`。 如果出现“页面已经切过去,但 tabbar 高亮不对”或“点击当前高亮 tab 没反应”,优先检查是否有业务代码提前 return,或者是否只根据缓存的 `curIdx` 判断当前页面。 --- --- url: 'https://unibest.tech/base/7-ui.md' --- # UI 库替换篇 > 2026-04-25 更新:脚手架新增 `wot-ui-v2` 选项(`@wot-ui/ui`),并在交互中前置显示;`wot-ui` 表示 `v1`(`wot-design-uni`)用于兼容老项目。 ```txt ◆ 请选择UI库 │ ● wot-ui-v2 │ ○ wot-ui(v1) │ ○ uview-pro │ ○ sard-uniapp │ ○ uv-ui │ ○ uview-plus │ ○ 无UI库 ``` ## wot-ui-v2(推荐) `wot-ui-v2` 对应官方 `Wot UI 2.x` 的 npm 包:`@wot-ui/ui`。 * 创建命令: ```sh pnpm create unibest my-project -u wot-ui-v2 -p h5,mp-weixin ``` * 脚手架会自动处理以下配置: * 安装 `@wot-ui/ui` * 在 `pages.config.ts` 注入 `easycom` 规则 `^wd-(.*)` * 在 `tsconfig.json` 注入 `@wot-ui/ui/global` * 补充 `sass` 依赖 * 生成与 `vite.config.ts` 同级的 `wot-ui-resolver.ts` * 在 `vite.config.ts` 的 `UniComponents` 中注入 `resolvers: [WotResolver()]` > 官方文档参考:[Wot UI 快速上手](https://wot-ui.cn/guide/quick-use.html) * 温馨提示:`uview-plus` 跟 `uv-ui` 是非常类似的,但是 `uview-plus` 需要强制看广告,如果不想看的话,可以选用 `uv-ui`(所以我把 `uv-ui` 排在前面)。 * 温馨提示:不同 `UI库` 的使用占比请看 2026-01-01 数据 `wot-ui`(62.2%) > `uview-pro`(10.0%) > `uview-plus`(7.5%) > `sard-uniapp`(6.1%) > `uv-ui`(4.7%) 【另外 `none` 占比 9.5%】 **下面的文档大概率用不到了,仅做参考。** ## 默认 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` 版本,文档地址:. *** 很多群友反馈有其他 `UI` 库的需求,那么更换 `UI 库` 需要哪些步骤呢? * 先卸载原有的 `wot-ui` 库 * 再安装其他 `UI 库` ## 卸载 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" ] ``` ## 安装 `uview-pro` 库 * 1. 安装 `uview-pro` 库: ```sh pnpm add uview-pro ``` * 2. 引入 uView Pro 主库 在项目`src` 目录中的 `main.ts` 中,引入并使用 `uView Pro` 的工具库。 ```diff import { createSSRApp } from "vue"; + import uViewPro from "uview-pro"; export function createApp() { const app = createSSRApp(App); + app.use(uViewPro); // 其他配置 return { app, }; } ``` * 3. `pages.config.ts` 文件 `easycom.custom` 添加相关配置: ```diff easycom: { autoscan: true, custom: { + '^u-(.*)': 'uview-pro/components/u-$1/u-$1.vue', }, }, ``` * 4. `uni.scss` 中末尾引入 `uView Pro` 的颜色变量 ```scss @import 'uview-pro/theme.scss'; ``` * 5. `App.vue` 中首行的位置引入 `uView Pro` 的基础样式 ```scss ``` ## 安装 `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" ] ``` ## 安装 `uview-plus` 库 * 1. 安装 `uview-plus` 库: ```sh pnpm add uview-plus ``` * 2. `pages.config.ts` 文件 `easycom.custom` 添加相关配置: ```diff easycom: { autoscan: true, custom: { + '^u--(.*)': 'uview-plus/components/u-$1/u-$1.vue', + '^up-(.*)': 'uview-plus/components/u-$1/u-$1.vue', + '^u-([^-].*)': 'uview-plus/components/u-$1/u-$1.vue', }, }, ``` * 3. ` tsconfig.json` 文件 `compilerOptions.types` 添加相关配置: ```diff "types": [ "@dcloudio/types", "@types/wechat-miniprogram", + "uview-plus/types",, "./components.d.ts", "./global.d.ts" ] ``` * 4. `uni.scss` 中末尾引入 `uview-plus` 的颜色变量 ```scss @import 'uview-plus/theme.scss'; // /* 行为相关颜色 */ ``` ## 安装 `sard-uniapp` 库 * 1. 安装 `sard-uniapp` 库: ```sh pnpm add sard-uniapp ``` * 2. `pages.config.ts` 文件 `easycom.custom` 添加相关配置: ```diff easycom: { autoscan: true, custom: { + '^sar-(.*)': 'sard-uniapp/components/$1/$1.vue', }, }, ``` * 3. ` tsconfig.json` 文件 `compilerOptions.types` 添加相关配置: ```diff "types": [ "@dcloudio/types", "@types/wechat-miniprogram", + "sard-uniapp/global", "./components.d.ts", "./global.d.ts" ] ``` * 4. `App.vue` 中首行的位置引入 `sard-uniapp` 的基础样式 ```scss ``` > 其他 UI 库的安装类似,不再赘述。 全文完~ --- --- url: 'https://unibest.tech/base/ui/ui.md' --- # 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/) * Sard uniapp (Sard系) - [文档地址](https://sard.wzt.zone/sard-uniapp-docs/) 还有 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 | | | | | uview-plus | | | | | wot-ui | | | | | TuniaoUI | | | - | > 接着奏乐接着舞,我们继续正文 ^\_^ ## 多端支持情况 | 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`),如果有提示就是有,啥都没有就是没有。 > > 举个例子,编写 ` 别说我偏心,两位 `ui` 框架的作者都是我的好友,我是 `uv-ui` 群的管理员,`wot-ui` 作者在我的大群里面。选择 `wot-ui` 确实因为它很优秀。 ## 总结 很高兴我们已经为宇宙最强 `uniapp` 开发模板 `unibest` 选好了 `UI 组件库`,`wot-ui` 是最终的幸运儿。为此我特意去 `wot-ui` 官网里面捐赠了一杯咖啡钱给作者,开源不易,要支持一下。 --- --- url: 'https://unibest.tech/base/3-plugin.md' --- # uni 插件 ## 引言 有群友第一次看到 `unibest` 里面 `vue` 文件 `route-block` 这种写法,表示很奇怪,从来没见过! ```vue { layout: 'demo', style: { navigationBarTitleText: '标题', }, } ``` > 2025-08-28 更新, `route-block` 在 `v3.12.0` 已被 `definePage` 替代. * 对象形式(静态配置): ```js definePage({ style: { navigationBarTitleText: '首页', }, }); ``` * 函数形式(动态计算): ```js definePage(() => ({ style: { navigationBarTitleText: computedTitle(), }, })); ``` * 异步函数形式(异步数据获取): ```js definePage(async () => { const title = await fetchPageTitle(); return { style: { navigationBarTitleText: title, }, }; }); ``` 更多详情请看:[definePage](https://uni-helper.js.org/blog/definepage) ## 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` 代码块则可以配置页面相关信息,这些信息会自动同步到 `pages.json`,无需切换到 `pages.json` 进行配置。 ### 温馨提示 > `pages.json` 文件是自动生成的,请不要手动修改,全局的东西请在 `pages.config.ts` 里面配置,页面上的东西请在 `vue` 文件的 `route` 代码块配置,如下图。 ```vue [src/pages/index.vue] { style: { navigationStyle: 'custom', navigationBarTitleText: '首页', }, } ``` ```vue [src/pages/about.vue] { style: { navigationBarTitleText: '关于', }, } ``` ### 设置首页 通过在 `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` 里面的子目录 }); ``` ### 额外配置页面和条件页面 普通页面建议直接放到 `src/pages`,通过文件路由自动生成 `pages.json`。如果确实有少量页面不能通过文件路由生成,也可以在 `pages.config.ts` 中追加 uni-app 原生的 `pages` 配置。 ```ts [pages.config.ts] export default defineUniPages({ pages: [ { path: 'pages/manual/index', style: { navigationBarTitleText: '手动配置页面', }, }, ], }) ``` 如果页面只在某个平台存在,不要手动修改生成后的 `pages.json`。推荐把平台差异放到独立目录,然后在 `vite.config.ts` 的 `UniPages` 配置中按 `UNI_PLATFORM` 控制 `exclude`、`include` 或 `subPackages`。 ```ts [vite.config.ts] const { UNI_PLATFORM } = process.env const excludePages: string[] = ['**/components/**/**.*'] const subPackages: string[] = ['src/pages-demo'] if (UNI_PLATFORM === 'mp-weixin') { subPackages.push('src/pages-weixin') } else { excludePages.push('src/pages-weixin/**/**.*') } UniPages({ exclude: excludePages, subPackages, }) ``` `pages.config.ts` 适合放全局配置和少量手动页面;单个页面自己的标题、导航栏等配置,仍然优先写在页面的 `route` 代码块里。 ## 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} { layout: 'demo', style: { navigationBarTitleText: '关于', }, } ``` 如果是 `definePage`写法则为: ```ts [src/pages/demo.vue] definePage({ layout: 'demo', style: { navigationBarTitleText: '关于', }, }); ``` ```vue [src/layouts/demo.vue] ``` ## 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` 里面配置。 ## App.ku.vue 全局挂载组件 在 `src/App.ku.vue` 里面可以全局挂载组件,这样在所有页面都可以使用这个组件。 文档地址:[uni-ku/root](https://github.com/uni-ku/root) 目的:解决 `uniapp` 无法使用根部组件问题 ## 总结 本文介绍了 `unibest` 引入的几个重要的 `uni插件`。 如果还想了解更多信息,可以去 `uni-helper` [github 仓库](https://github.com/uni-helper) 看看。 --- --- url: 'https://unibest.tech/gif.md' --- --- --- url: 'https://unibest.tech/other/iconfont/iconfont.md' --- ## iconfont 图标库 `iconfont` 同样有海量免费的图标,同时支持上传自己的图标。公司项目通常会有自己的图标,由专业的 `UI设计师` 设计,这时通常会使用 `iconfont` 方式使用图标。 * 1. 打开`阿里巴巴矢量图标库 iconfont`,地址:https://www.iconfont.cn/,并登录。 * 2. 寻找需要的图标,加入项目,也可以上传自己的图标。 ![alt text](./assets/5-9.png) ![alt text](./assets/5-10.png) ![alt text](./assets/5-11.png) > 初次接触 `iconfont` 的同学,可能会找不到自己的项目,如下图:资源管理 -- 我的项目 ![alt text](./assets/5-12.png) * 3.图标方式选择,如下图有 `Unicode` `Font class` `Symbol` 三种方式,分别预览和使用如下: ![alt text](./assets/5-13.png) ![alt text](./assets/5-14.png) ![alt text](./assets/5-15.png) * `Unicode` 的方式太落后,语义化不明显,不推荐; * `Symbol` 的方式太先进(背后原理是生成了 `SVG` 雪碧图),先进到 `小程序` 和 `APP` 都不支持,只能无奈放弃。 > `Symbol` 的方式生成 `svg` 雪碧图,如下所示: > > ![alt text](./assets/5-16.png) * `Font class` 则是我们最合适的选择,有 `Symbol` 一样的语义化(都是`icon-xxx`方式),引入和使用也方便( `Symbol` 是一个 `js` 文件,`Font class` 是一个 `css` 文件)。 * 3. 点击选中 `Font class` 后再点击 `查看在线连接` 按钮,可以拿到一个 `css` 的链接,如 [//at.alicdn.com/t/c/font\_4032028\_mbcuy517h6.css](//at.alicdn.com/t/c/font_4032028_mbcuy517h6.css) ,如果期间新加入了图标,记得点击更新链接,会重新生成一个链接,只有最后面一串 hash 有改变,并且旧的链接依然可以访问。 ![alt text](./assets/5-17.png) 我们使用的是 `Font class` 的方式,只需要这一个 `css` 链接就行,无需 `下载至本地`,想要本地预览的话才需要 `下载至本地`。 > `iconfont` 有默认的前缀 `icon-`,可以设置为其他的,如我的一个项目设置为 `bap-icon-`,以防跟其他的冲突。 ![alt text](./assets/5-18.png) > 注意 `uniapp` 项目拿到 `css` 链接放到 `index.html` 是不对的,这样做只在 `h5` 中生效,`小程序` 和 `APP` 都不生效,正确的做法是放到代码里面显示引入。下面会讲: * 4.在 `style/index.scss` 中写上上面的 `css` 链接里面的内容(`style/index.scss` 已经在 `main.ts` 引入了,`unibest` 模板已经内置),如下 > 注意: `url(//at.alicdn.com)` 里面的路径要改为 `url(https://at.alicdn.com)`,因为 APP 里面 `//` 是文件协议。 —— 设定 `https` 协议 ```css @font-face { font-family: iconfont; /* Project id 4032028 */ src: url('//at.alicdn.com/t/c/font_4032028_mbcuy517h6.woff2?t=1713685013355') format('woff2'), url('//at.alicdn.com/t/c/font_4032028_mbcuy517h6.woff?t=1713685013355') format('woff'), url('//at.alicdn.com/t/c/font_4032028_mbcuy517h6.ttf?t=1713685013355') format('truetype'); } .iconfont { font-family: iconfont !important; font-size: 16px; font-style: normal; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } .icon-facebook::before { content: '\e87d'; } .icon-twitter::before { content: '\e646'; } .icon-telegram::before { content: '\f245'; } ``` * 5. 编写代码,`` ![alt text](./assets/5-23.png) * 6. 预览,`h5 `端正常,APP 端不正常,小程序端看着正常,控制台也会报错,如下图: ![alt text](./assets/5-22.png) * 7. 这个怎么处理呢?转成 `base64` 是最快捷的,`iconfont` 本身就支持, `3`步搞定: * 7.1 如下图,勾选 `Base64` ![alt text](./assets/5-21.png) * 7.2 生成新链接,并得到新的 `css` 代码 ![alt text](./assets/5-20.png) * 7.3 引入新代码,刷新界面,小程序不报错了,APP 也正常了! ![alt text](./assets/5-19.png) --- --- url: 'https://unibest.tech/other/滚动穿透处理.md' --- ## 微信里如何解决 `滚动穿透` ```ts /** * 锁定页面,弹出框存在时锁定页面滚动 */ export function useLockPage() { const pageStyle = ref(''); const setPageStyle = (uni as any).setPageStyle; const lockPage = (isTabbar = false) => { if (CommonUtil.isFunction(setPageStyle)) { setPageStyle({ style: { overflow: 'hidden', }, }); } else { pageStyle.value = `height:calc(100vh - ${ isTabbar ? '50px' : '0' } - constant(safe-area-inset-bottom));height:calc(100vh - ${ isTabbar ? '50px' : '0' } - env(safe-area-inset-bottom));overflow:hidden;position:fixed;`; } }; const unlockPage = () => { if (CommonUtil.isFunction(setPageStyle)) { setPageStyle({ style: { overflow: 'visible', }, }); } pageStyle.value = ''; }; return { lockPage, unlockPage, pageStyle, }; } ``` --- --- url: 'https://unibest.tech/other/全局分享.md' --- ## 全局分享 ![alt text](2.png) 需要把 pinia 初始化放到内部。否则会报错: ![alt text](3.png) --- --- url: 'https://unibest.tech/advanced/wechat/wechat.md' --- # 交流群 千万记得 `先看一遍文档`,可以解决大部分基础疑问。 > 必看章节:[uni 插件篇](/base/3-plugin) 和 [常见问题](/base/14-faq) ## 免费 QQ 群 ①②③④⑤⑥ 群已满,下面是 ⑦ 群。 > QQ 群永久有效,微信群 7 天就过期。QQ 群无需每 7 天替换一次。 ## 付费微信群 目前已经有 `9个` 微信群,维护需要精力(回答各种问题)。从 `2025-07-01` 开始,不再提供免费微信交流群。 如果确实有需要的,进群后发 `专属红包 20元` 给群主 `菲鸽` 即可。(注意:没发的会被移出群聊。) > 专属红包这样发: ## 联系我 如果你有商业上的合作需求,或者想定制化 unibest,欢迎联系我,备注:`商业合作`。 如果你有外包需求,也可以联系我,备注:`外包`。 --- --- url: 'https://unibest.tech/base/4-style2.md' --- # 关于使用 TailwindCSS 对于 unibest 项目使用 TailwindCSS 的评估如下: 1. **直接使用TailwindCSS的限制**: * 原生TailwindCSS是为Web设计的,在小程序环境下会有兼容性问题 * 不支持rpx单位,在小程序适配上有困难 * 需要额外配置postcss和purgeCSS才能在小程序工作 2. **当前UnoCSS的优势**: * 您的项目已经配置了`unocss-applet`,专门为小程序优化 * 支持rpx单位转换(通过presetRemRpx) * 支持小程序属性化写法(transformerAttributify) * 体积更小,按需生成样式 3. **替代方案建议**: * 保持使用UnoCSS,它已经实现了Tailwind的大部分功能 * 可以通过安装`@unocss/preset-wind`来获得Tailwind风格的类名: ```bash pnpm add -D @unocss/preset-wind ``` 然后在uno.config.ts中添加: ```typescript import { presetWind } from '@unocss/preset-wind' export default defineConfig({ presets: [ presetWind(), // 其他presets... ], }) ``` 4. **结论**: 在uni-app项目中,UnoCSS是比原生TailwindCSS更合适的选择,特别是针对小程序开发。通过`preset-wind`可以获得类似Tailwind的开发体验。 --- --- url: 'https://unibest.tech/advanced/me/me.md' --- # 关于我 我叫 `菲鸽`,江西宋城人。前端工程师,全栈实践者,精通 `vue`、`react`、`uniapp`、`typescript`、`小程序`、`Nodejs` 等。 热爱编程,喜欢分享,平时比较宅,喜欢撸代码,偶尔打篮球和玩王者荣耀。 ## 找到我 * Github: [feige996](https://github.com/feige996) * Gitee: [feige996](https://gitee.com/feige996) * 掘金:[菲鸽](https://juejin.cn/user/3263006241460792/posts) * 微信:`feige996` = `菲鸽`,大家都叫我 `鸽鸽` * QQ:`1020103647` * 邮箱:`1020103647@qq.com` ## 微信公众号 微信公众号:`菲鸽爱编程` ![微信公众号](./screenshots/wx-gzh.png) --- --- url: 'https://unibest.tech/base/20-best.md' --- # 最佳实践 新项目使用 `base` 模板,可选 `tabbar` 模板。如果需要多语言,可以选 `i18n` 模板。 同时参考 `demo` 模板,可以直接 `clone` `demo` 项目,用来参考用。 ![unibest templates](https://oss.laf.run/ukw0y1-site/xmind/unibest模板.png) ## 创建项目 推荐使用 `pnpm` : ```sh # 新项目创建 pnpm create unibest my-project -t base ``` ## DEMO 模板 `demo` 模版-在线地址: 推荐先全部体验一下 `demo` 的示例 ## 必看章节 * [介绍](/base/1-introduction) * [快速开始](/base/2-start) * [uni 插件](/base/3-plugin) * [常见问题](/base/14-faq) * [常见问题 2](/base/15-faq) * [运行发布](/base/11-build) ## 抖音小程序开发者工具下载地址 * --- --- url: 'https://unibest.tech/changelog/upgrade.md' --- # 升级指南 > 先插一句,有群友直接 `merge` `unibest 里面的 main 分支`,需要的也可以试试。 > > 如果 `OK` 的话,下面的就不需要了。 分为 `6` 部分的内容:(2025-06-14 周六) * `uniapp sdk 升级` * `uni-helper 插件升级` * `oxlint 升级` * `移除 eslint, stylelint` * `unocss 升级` (可选) * `vscode 配置文件升级` (可选) ## uniapp sdk 升级 ```sh pnpm uvm # 升级 uniapp sdk # 如果以上命令不存在,请使用下面的 npx @dcloudio/uvm@latest ``` 然后进入交互式的升级模式,按照提示进行升级。期间包管理器选择 `pnpm`。 升级完后,会自动引入 `vue-i18n`,不需要的可以删除它。(可选) ## uni-helper 插件升级 ```sh "@uni-helper/uni-types": "1.0.0-alpha.3", "@uni-helper/unocss-preset-uni": "^0.2.11", "@uni-helper/vite-plugin-uni-components": "0.2.0", "@uni-helper/vite-plugin-uni-layouts": "0.1.10", "@uni-helper/vite-plugin-uni-manifest": "0.2.8", "@uni-helper/vite-plugin-uni-pages": "0.2.28", "@uni-helper/vite-plugin-uni-platform": "0.0.4", ``` 把你项目里面的 `package.json` 里面的相关依赖包版本改成上面的。然后执行 `pnpm i` 安装。 ## oxlint 升级 ```sh pnpm add -D oxlint@v1.0.0 # 注意不要贪最新,最新的 v1.1.0 有问题,会报错。 ``` `package.json` 里面的 `"lint-staged"` 内容改为: ```json "lint-staged": { "**/*.{html,cjs,json,md,scss,css,txt}": [ "prettier --write --cache" ], "**/*.{js,jsx,ts,tsx,vue,mjs,cjs,mts,cts}": [ "oxlint --fix", "prettier --write --cache" ], "!**/{node_modules,dist}/**": [] }, ``` `package.json` 里面的 `scripts` 添加: ```json scripts: { // ... 其他 "lint": "oxlint", "lint-fix": "oxlint --fix" } ``` 然后在项目根目录新建 `.oxlintrc.json` 文件,内容如下: ```json { "$schema": "./node_modules/oxlint/configuration_schema.json", "extends": ["config:recommended"], "plugins": ["import", "typescript", "unicorn"], "rules": { "no-console": "off", "no-unused-vars": "off" }, "env": { "es6": true }, "globals": { "foo": "readonly" }, "ignorePatterns": [ "node_modules", "dist", "src/static/**", "src/uni_modules/**", "vite.config.ts", "uno.config.ts", "pages.config.ts", "manifest.config.ts" ], "settings": {}, "overrides": [ { "files": ["*.test.ts", "*.spec.ts"], "rules": { "@typescript-eslint/no-explicit-any": "off" } } ] } ``` ## 移除 eslint, stylelint 上面配置了 `oxlint` 后,`eslint` 不需要了,可以把 `依赖包` 和 `配置文件` 都都删除。 `stylelint` 可以保留也可以删除,因为几乎都是用 `unocss` 来写样式的,所以 `stylelint` 不要也可以。 ## unocss 升级(可选) 1、升级 `unocss` ```sh pnpm add -D unocss@65.4.2 # 注意不要贪最新,最新的 v66+ 有问题,会报错。 ``` 2、 更新 `uno.config.ts` 配置文件 ```ts // https://www.npmjs.com/package/@uni-helper/unocss-preset-uni import { presetUni } from '@uni-helper/unocss-preset-uni'; import { defineConfig, presetIcons, presetAttributify, transformerDirectives, transformerVariantGroup, } from 'unocss'; export default defineConfig({ presets: [ presetUni({ attributify: { // prefix: 'fg-', // 如果加前缀,则需要在代码里面使用 `fg-` 前缀,如:
prefixedOnly: true, }, }), presetIcons({ scale: 1.2, warn: true, extraProperties: { display: 'inline-block', 'vertical-align': 'middle', }, }), // 支持css class属性化 presetAttributify(), ], transformers: [ // 启用指令功能:主要用于支持 @apply、@screen 和 theme() 等 CSS 指令 transformerDirectives(), // 启用 () 分组功能 // 支持css class组合,eg: `
测试 unocss
` transformerVariantGroup(), ], shortcuts: [ { center: 'flex justify-center items-center', }, ], 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)' }], ], theme: { colors: { /** 主题色,用法如: text-primary */ primary: 'var(--wot-color-theme,#0957DE)', }, fontSize: { /** 提供更小号的字体,用法如:text-2xs */ '2xs': ['20rpx', '28rpx'], '3xs': ['18rpx', '26rpx'], }, }, }); ``` 3、 更新 `vite.config.ts` 中 `unocss` 的引入方式: ```ts export default async ({ command, mode }) => { // @see https://unocss.dev/ const UnoCSS = (await import('unocss/vite')).default // ... 其他代码 }) ``` ## vscode 配置文件升级 `.vscode/settings.json` 里面 `explorer.fileNesting.patterns` 配置如下: ```json "explorer.fileNesting.patterns": { "README.md": "index.html,favicon.ico,robots.txt,CHANGELOG.md", "pages.config.ts": "manifest.config.ts,openapi-ts-request.config.ts", "package.json": "pnpm-lock.yaml,pnpm-workspace.yaml,LICENSE,.gitattributes,.gitignore,.gitpod.yml,CNAME,.npmrc,.browserslistrc", ".oxlintrc.json": "tsconfig.json,.commitlintrc.*,.prettier*,.editorconfig,.commitlint.cjs,.eslint*" } ``` --- --- url: 'https://unibest.tech/other/blog.md' --- # 博客列表 `unibest` 相关文章主要发布在 `掘金`,我的 [掘金 unibest 专栏](https://juejin.cn/column/7307183009604894735)。 * [🔥2024 年最好用的 uniapp 开发模板,近一个月 star 数飙升!🔥](https://juejin.cn/post/7329034439408615451) * [【unibest】uniapp + vue3 超实用模板](https://juejin.cn/post/7315246744158191666) * [【unibest】uniapp + vue3 超实用模板(续)](https://juejin.cn/post/7315461542697500682) * [【unibest】uniapp + vue3 超实用模板(终)](https://juejin.cn/post/7321930742400188453) * [【unibest】uniapp + vue3 超实用模板(番外篇)](https://juejin.cn/editor/drafts/7315308701051519030) --- --- url: 'https://unibest.tech/other/可能有用的代码片段.md' --- # 可能有用的代码片段 ## 时间拓展 ```ts import dayjs from 'dayjs'; import calendar from 'dayjs/plugin/calendar'; import quarterOfYear from 'dayjs/plugin/quarterOfYear'; import relativeTime from 'dayjs/plugin/relativeTime'; import updateLocale from 'dayjs/plugin/updateLocale'; import utc from 'dayjs/plugin/utc'; import weekday from 'dayjs/plugin/weekday'; import 'dayjs/locale/zh-cn'; dayjs.extend(calendar); dayjs.extend(quarterOfYear); dayjs.extend(relativeTime); dayjs.extend(updateLocale); dayjs.extend(utc); dayjs.extend(weekday); dayjs.locale('zh-cn'); dayjs.updateLocale('zh-cn', { calendar: { sameDay: 'HH:mm', nextDay: '[明天]', nextWeek: 'dddd', lastDay: '[昨天] HH:mm', lastWeek: 'dddd HH:mm', sameElse: 'YYYY年M月D日 HH:mm', }, relativeTime: { future: '%s后', past: '%s前', s: '几秒', m: '1分钟', mm: '%d分钟', h: '1小时', hh: '%d小时', d: '1天', dd: '%d天', M: '1个月', MM: '%d个月', y: '1年', yy: '%d年', }, }); /** 时间工具 */ export const dateUtil = dayjs; export const DATETIME_FORMAT = 'YYYY-MM-DD HH:mm:ss'; export const DATE_FORMAT = 'YYYY-MM-DD'; export const TIME_FORMAT = 'HH:mm'; /** * 格式化日期 * @param _date 日期对象、时间戳或字符串 * @param format 格式字符串 * @returns 格式化后的日期字符串 */ function _format(_date: dayjs.ConfigType, format: string): string { if (!_date) { return _date as any; } const date = dateUtil(_date); return date.isValid() ? date.format(format) : (_date as string); } /** * 格式化为日期时间字符串 * @param date 日期对象、时间戳或字符串 * @param format 格式字符串,默认为 DATETIME_FORMAT * @returns 格式化后的日期时间字符串 */ export function formatToDatetime( date: dayjs.ConfigType = undefined, format: string = DATETIME_FORMAT ): string { return _format(date, format); } /** * 格式化为日期字符串 * @param date 日期对象、时间戳或字符串 * @param format 格式字符串,默认为 DATE_FORMAT * @returns 格式化后的日期字符串 */ export function formatToDate( date: dayjs.ConfigType = undefined, format: string = DATE_FORMAT ): string { return _format(date, format); } /** * 格式化为日期字符串 * @param date 日期对象、时间戳或字符串 * @param format 格式字符串,默认为 TIME_FORMAT * @returns 格式化后的日期字符串 */ export function formatToTime( date: dayjs.ConfigType = undefined, format: string = TIME_FORMAT ): string { return _format(date, format); } /** * 时间人性化显示 * @param date 要格式化的日期 * @param oppositeDate 参考日期,默认为当前时间 * @returns 人性化的时间字符串 */ export function humanizedDate( date: dayjs.ConfigType, oppositeDate: dayjs.ConfigType = undefined ): string { if (!date || !dateUtil(date).isValid()) { return ''; } const now = oppositeDate ? dateUtil(oppositeDate) : dateUtil(); const diffSeconds = now.diff(date, 'second'); const diffMinutes = now.diff(date, 'minute'); const diffHours = now.diff(date, 'hour'); const diffDays = now.diff(date, 'day'); if (diffSeconds < 60) { return `${diffSeconds}秒前`; } else if (diffMinutes < 60) { return `${diffMinutes}分钟前`; } else if (diffHours < 24) { return `${diffHours}小时前`; } else if (diffDays < 7) { return `${diffDays}天前`; } else { return formatToDatetime(date); } } /** * 获取时辰问候语 * @returns 根据当前时间返回相应的问候语 */ export function getGreeting(): string { const currentHour = dateUtil().hour(); if (currentHour >= 5 && currentHour < 12) { return '早上好'; } else if (currentHour >= 12 && currentHour < 14) { return '中午好'; } else if (currentHour >= 14 && currentHour < 18) { return '下午好'; } else if (currentHour >= 18 && currentHour < 24) { return '晚上好'; } else { return '深夜了'; } } ``` --- --- url: 'https://unibest.tech/base/5-icons.md' --- # 图标篇 本文主要介绍了 `图标` 的使用方式,通常有以下几种方式使用图标: * `UI 库 Icons` * `UnoCSS Icons` * `iconfont` 下面笔者一一介绍 ## UI 库 Icons 如果您已经引入了 `UI库`,并且正好该 `UI库` 已经有你想要的 `Icons`,那直接用最方便了,无需额外引入其他库,代码也是最少的。 这里介绍几个常用 `UI库` 的图标使用。 ### `uni-ui Icons` > 注意:`uni-ui Icons` 颜色只能通过 `color` 属性设置;使用 `UnoCSS` 设置无效。 ```html ``` ![alt text](./assets/5-1.png) ### `wot-ui Icons` > 注意:`wot-ui icons` 颜色可以通过 `color` 属性设置,也可以通过 `UnoCSS` 设置;同时设置时,`color` 属性优先级高。 ```html ``` ![alt text](./assets/5-2.png) ### `uv-ui Icons` > 注意:跟 `uni-ui Icons` 一样,`uv-ui Icons` 的颜色只能通过 `color` 属性设置;使用 `UnoCSS` 设置无效。 ```html ``` ![alt text](./assets/5-3.png) > 注意,经过检测这 `3个UI库Icons` 都不支持使用 `UnoCSS` 改变大小(优先级低被覆盖),必须使用 `size` 属性来设置大小才有效果(行内样式优先于 css 样式)。 > > 另外,经过检测,都支持动态 `iconName`和动态 `color` ! 即下面这样的写法是生效的: ```ts const iconName = ref('contact'); const colorName = ref('red'); onLoad(() => { setTimeout(() => { iconName.value = 'chat'; colorName.value = 'green'; }, 1000); }); ``` ```html ``` ## `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 想要的图标名 打开网址: * 在里面找到某个库,如 `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 ``` ![alt text](./assets/5-7.png) > 如果图标没有预览效果,请安装 `VSCode` 插件 `antfu.iconify`。 预览效果: ![alt text](./assets/5-8.png) ### 4. 动态图标名 昨天有网友反馈,`UnoCSS Icons` 无法使用动态类名,我来试试:(我先说结论:是支持的!) ```ts const iconName = ref('i-carbon-car'); onLoad(() => { setTimeout(() => { iconName.value = 'i-carbon-user-avatar'; }, 1000); }); ``` ```html ``` 一秒后会由 `i-carbon-car`(一辆车) 变成 `i-carbon-user-avatar`(一个头像),一切都是 OK 的。 ### 5.再说动态图标名 有的时候类名是动态的,比如是 a+b 拼凑的,比如是后端返回的,比如是跨文件的,这时候页面是无法显示出该图标的。因为 `UnoCSS` 还不知道具体的类名是啥,无法得到对应的图标。解决方案有 2 种: * 1. 在代码里写出完整的图标类名,并注释掉。(SFC 的任何位置都可以) * 2. 在 `unocss.config.ts` 的 `safelist` 配置该完整类名。[unocss safelist](https://unocss.dev/config/#safelist) ### 6.class 编写方式提示 尽量用中划线而不是冒号连接类型,即使用 `i-carbon-user-avatar` 这种方式,而不是 `i-carbon:user-avatar`,因为后者在 `微信小程序` 中会被分割成 2 个类名,导致图标无法显示。(群友血的教训 on 2025-08-25) ![alt text](5-1.png) ## iconfont 图标库 `iconfont` 同样有海量免费的图标,同时支持上传自己的图标。公司项目通常会有自己的图标,由专业的 `UI设计师` 设计,这时通常会使用 `iconfont` 方式使用图标。 * 1. 打开`阿里巴巴矢量图标库 iconfont`,地址:,并登录。 * 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. 页面上直接写 `` 即可! ```html iconfont: ``` 预览如下: ![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` 才能兼容多端。 全文完~ --- --- url: 'https://unibest.tech/other/image/image.md' --- # 图片占位图 * 色块占位图 * 真实随机图片 ## 色块占位图 下面是一个 `400x200 - 宽高,3c9cff - 背景颜色,fff - 文本颜色` 的色块占位图。 ![alt text](./assets/image-1.png) 可以通过下面几种方式生成,效果一样: | 官网地址 | 占位图片示例 | | :-------------------------------------------------- | :------------------------------------------------------------------------------------------------------- | | [https://placeholder.com](https://placeholder.com/) | | | [https://dummyimage.com](https://dummyimage.com/) | | | [https://fakeimg.pl](https://fakeimg.pl/) | | 代码编写举例: ```vue ``` ## 真实随机图片 如果想生成某个宽高的随机图片,可以使用 。 格式如:`https://picsum.photos//?random=1` 举例: 生成效果如下: ![alt text](./assets/image-2.png) 代码编写举例: ```vue ``` --- --- url: 'https://unibest.tech/base/10-i18n.md' --- # 多语言篇 `多语言` 是一个常见的需求, `unibest` 专门开发了一个 `i18n`模板,可以直接生成 `多语言模板项目`。 ```sh pnpm create unibest my-project -t i18n ``` `vue组件` 里面使用方式如下: ```html {{ $t('app.name') }} ``` `非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 {{ $t('weight', { heavy: 100 }) }} ``` `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 {{ formatI18n(translate('introduction'), user) }} ``` 用到的函数引入如下: ```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` 使用如下,请使用 `onShow` 钩子包裹: ```js import { t } from '@/locale'; onShow(() => { uni.setNavigationBarTitle({ title: t('i18n.title'), }); }); ``` > `2025-07-19` 日发布了 `3.4.0` 已经处理了模板页面的导航栏标题的多语言问题,用户新增页面需要自行处理。 ## tabbar 标题 同 `导航栏标题`。使用 `uni.setTabBarItem` 来手动处理。(`3.4.0` 版本之前需要用户自己处理) > `2025-07-19` 日发布了 `3.4.0` 已经处理了不同类型的 tabbar 的多语言问题,无需用户处理了。 ## App 端视频 这里给出 `2` 个 `App端` 的视频,加深开发者的认识和印象。 :::details ### `ios模拟器` 多语言直接就是生效的 ### `安卓真机` 会自动重启,重启后界面多语言是生效的 ::: ## 总结 本文介绍了 `unibest` 里面使用 `多语言` 的基本方式,还处理了 `3` 个多端异常的问题: * `多语言传参` 不生效 BUG * `导航栏标题` 切换多语言不生效 BUG * `tabbar标题` 切换多语言不生效 BUG 全文完~ --- --- url: 'https://unibest.tech/other/如何给npm包打补丁.md' --- # 如何给 npm 包打补丁 背景:使用的 `npm` 包有 `BUG`,在某些环境下有兼容性问题,库作者维护不及时,这个时候就需要给 `npm` 包打补丁。 我们使用的包管理工具是 `pnpm`,下面我来介绍如何使用 `pnpm` 给 `npm` 包打补丁。 * 1. 在 `package.json` 文件中找到你要打补丁的 `npm` 包,然后执行 `pnpm patch ` 命令。 * 2. 执行后会有提示,告诉你可以去编辑代码了,还告诉了你如何提交。示例如下 ```sh $ pnpm patch @uni-helper/vite-plugin-uni-layouts Patch: You can now edit the package at: /Users/burtlai/unibest-projects/unibest/node_modules/.pnpm_patches/@uni-helper/vite-plugin-uni-layouts@0.1.11 To commit your changes, run: pnpm patch-commit '/Users/burtlai/unibest-projects/unibest/node_modules/.pnpm_patches/@uni-helper/vite-plugin-uni-layouts@0.1.11' ``` * 3. 在 node\_modules 目录下找到你要打补丁的 `npm` 包,找到您要修改的文件进行修改。 * 4. 执行第二步的 `pnpm patch-commit` 命令(如 `pnpm patch-commit '/Users/burtlai/unibest-projects/unibest/node_modules/.pnpm_patches/@uni-helper/vite-plugin-uni-layouts@0.1.11'`),会生成一个 `patch` 文件。 * 5. 推送到远端,其他用户拉取后执行 `pnpm install` 命令,会自动应用 `patch` 文件。 --- --- url: 'https://unibest.tech/base/16-terminology.md' --- # 小程序的标识 目前有以下 `9` 种小程序标识,对应小程序平台类型如下: | 类型 | 标识 | | ------------ | ----------- | | 微信小程序 | mp-weixin | | 支付宝小程序 | mp-alipay | | 抖音小程序 | mp-toutiao | | 飞书小程序 | mp-lark | | QQ小程序 | mp-qq | | 京东小程序 | mp-jd | | 小红书小程序 | mp-xhs | | 百度小程序 | mp-baidu | | 快手小程序 | mp-kuaishou | > 注意: `mp-toutiao` 就是抖音小程序,其他的都很好辨别。 --- --- url: 'https://unibest.tech/base/14-faq.md' --- # 常见问题 本篇介绍一些常见的问题,会持续更新。 ## 1. 修改 `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` 里面修改。 详情请见[uni 插件篇](/base/3-plugin) ## 2. 如何设置/修改首页? `vue` 文件的 `route-block` 块里面设置 `type="home"` 即可,请确保项目里面 `只有一个页面` 是这个配置。 > 注意:如果有多个,会按照字母顺序排列,第一个是首页。(可能不是您的想要的效果。) ## 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. 启动微信小程序时出现 `timeout` 是什么意思? 这通常不是项目编译失败,也不是业务接口请求超时,而是项目尝试自动打开微信开发者工具时失败或超时。 项目默认会使用下面的微信开发者工具 CLI 路径: * macOS:`/Applications/wechatwebdevtools.app/Contents/MacOS/cli` * Windows:`C:\Program Files (x86)\Tencent\微信web开发者工具\cli.bat` 如果你的微信开发者工具安装位置不同,可以在项目 `env/.env` 中配置 `WECHAT_DEVTOOLS_CLI_PATH` 为实际 CLI 路径,配置一次后后续直接运行 `pnpm dev:mp-weixin` 即可。 ```env # macOS 示例: # WECHAT_DEVTOOLS_CLI_PATH = '/Applications/wechatwebdevtools.app/Contents/MacOS/cli' # Windows 示例: # WECHAT_DEVTOOLS_CLI_PATH = 'C:\Program Files (x86)\Tencent\微信web开发者工具\cli.bat' ``` 如果不想配置,也可以手动打开微信开发者工具,导入项目里的 `dist/dev/mp-weixin` 目录。还需要确认微信开发者工具的服务端口已经开启。 ## 7. 不想要严格的 `git` 提交检测,怎么办? 直接把 `.husky` 这个文件删掉即可。(或者不删除,只把里面的文件内容注释掉。) ## 8. `uni-app` 无法使用 `process.env` 变量,怎么办? 使用 `import.meta.env` 替代! ## 9. 如何跟随 `uni-app` 官方升级? 项目下,执行 `npx @dcloudio/uvm@latest` 即可更新。 ![alt text](./assets/14-1.png) > 注意,上面的命令会自动安装 `vue-i18n`,可以手动删除(`pnpm un vue-i18n`),也可以不理它(没多大影响)。 ## 10. 如何把已经加入 `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` 即可。 ## 11. 支付宝小程序运行报错。 * 默认运行是会报错的,如下图 ![alt text](./assets/14-2.png) * 只需要勾上 `本地开发跳过 ES5 转译` 即可正常运行,如下图 ![alt text](./assets/14-3.png) > 总结:勾上 `本地开发跳过 ES5 转译` 即可。 ## 12. 支持 `uni-app x` 吗? 不支持。但我们一直保持关注。[uni-app x 传送门](https://doc.dcloud.net.cn/uni-app-x/) 目前 `unibest` 已经有 `hbx` 模板,后续接入 `uni-app x` 会很容易,坐等官方发布。 ## 13. 为啥 `package.json` 中 `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) 关键截图如下:(仅支持 `H5端`) ![alt text](./assets/14-4.png) 真实运行报错截图如下:(分别是 `小程序` 和 `APP`, 都会报错 ) ![alt text](./assets/14-5.png) ![alt text](./assets/14-6.png) ## 14. `base` 模板如何接 `uniCloud` ? * 1. 操作方案:直接在原始项目目录上右键(就是导入整个 unibest 项目文件夹),重新识别项目类型,就可以关联 `uniCloud` 了,然后用原始项目直接运行就可以了,不需要再 `pnpm dev:app` 后导入 `dist/dev/app` 再运行了。 * 2. 问:其他模板可以吗?答:其他模板也可以,操作同上。 * 3. 我写的文章链接:[【unibest】可以去掉 hbx 模版了,base 模板一统天下](https://mp.weixin.qq.com/s?__biz=MzUxMzAwNzMwNw==\&mid=2247484792\&idx=1\&sn=b6116198f265384e5a51bd2bd95bea90\&chksm=f95a8edcce2d07caba60782e17e48d766612c0ad85c019379fd5ac37890e31b6ca7049e670f7\&scene=178\&cur_album_id=3438500614009782275#rd) ## 15. 微信小程序编译报错 ```text [ WXSS 文件编译错误] ./app.wxss(61:2204): unexpected `\` at pos 5292(env: macOS,mp,1.06.2412040; lib: 3.7.12) ``` ![alt text](14-2.png) ![alt text](14-1.png) 大概率是因为 `node` 版本比较低(比如 `v18`), 只需要把 `node`版本升级到 `v22+` 就行。(已经有多为同学遇到,可能是因为微信开发者工具升级导致的,升级后就可以了。) 如果上面还不行,则把微信开发者工具版本回退到 `1.06.2503290`。 ![alt text](14-3.png) 还有一个可能性,今天群里反馈的(2025-06-21): > 暂不确定是哪个包小版本有问题,使用 unibest 模板里面的 lock 文件就可以,自己安装就有问题(稳定复现)。 如果还是有问题,建议试试使用我模板里面的 lock 文件,我模板里面的 lock 文件是稳定的。 ## 16. ios 模拟器运行报错 ```text 14:20:36.428 编译器版本:4.66(vue3) 14:20:36.428 正在编译中... 14:20:38.259 ✘ [ERROR] Cannot start service: Host version "0.20.2" does not match binary version "0.25.5" 14:20:38.259 1 error 14:20:38.264 failed to load config from /Users/burtlai/unibest-projects/unibest/vite.config.ts 14:20:38.264 error during build: 14:20:38.264 Error: The service was stopped 14:20:38.264 at /Users/burtlai/unibest-projects/unibest/node_modules/.pnpm/esbuild@0.20.2/node_modules/esbuild/lib/main.js:1084:25 14:20:38.264 at responseCallbacks. (/Users/burtlai/unibest-projects/unibest/node_modules/.pnpm/esbuild@0.20.2/node_modules/esbuild/lib/main.js:704:9) 14:20:38.264 at Socket.afterClose (/Users/burtlai/unibest-projects/unibest/node_modules/.pnpm/esbuild@0.20.2/node_modules/esbuild/lib/main.js:694:28) 14:20:38.265 at Socket.emit (node:events:536:35) 14:20:38.265 at endReadableNT (node:internal/streams/readable:1698:12) 14:20:38.265 at process.processTicksAndRejections (node:internal/process/task_queues:90:21) 14:20:38.276 已停止运行... ``` ![alt text](14-5.png) 把 `package.json` 中的 `esbuild` 版本改为 `0.20.2` 即可。 ## 17. pnpm i 报错 `pnpm 9 + node 18` 目前出现以下问题:`ERR PNPM INVALID WORKSPACE CONFIGURATIoN packages field missing or empty` 群友说:`node 22` 没有问题。原话如下:`我昨天也是这样,pnpm9+node18,今天升级到node22就好了,没有动pnpm`。 > 如果还不行,那就把 pnpm 升级到 `pnpm 10`。 ## 18. unibest 项目的 `main` 分支和 `base` 分支有什么区别? * **`main` 分支** - 包含 CLI 工具代码(`packages/cli/`)和模板源码,是 CLI 开发的主要分支 * **`base` 分支** - 纯净的基础模板,不包含 CLI 代码,是用户创建项目时克隆的模板 **用户创建项目的流程:** ``` pnpm create unibest my-project ↓ 安装 create-unibest 包(来自 main 分支发布到 npm) ↓ 从 Git base 分支克隆模板 ``` ## 19. 如何参与 CLI 开发? CLI 代码在 `packages/cli/` 目录下,发布到 npm 包 `create-unibest`。 ```bash # 进入 unibest 仓库 git clone https://github.com/feige996/unibest.git cd unibest # 开发 CLI cd packages/cli pnpm install pnpm dev # 开发模式 pnpm build # 构建发布 # 测试本地 CLI pnpm start -- my-test-project ``` 详情请查看 [CLI 开发篇](./18-cli)。 全文完~ --- --- url: 'https://unibest.tech/base/15-faq.md' --- # 常见问题 2 ## 1. `wot-ui` 的 `toast` + `message-box` 不生效。 * 1. `layout` 引入 `wot-ui` 的 `toast` + `message-box`。 ```vue [src/layouts/default.vue] ``` > `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 ``` 完整版见下: :::details ```vue { layout: 'demo', style: { navigationBarTitleText: '富文本' }, } ``` ::: ## 3. Vue-Official ( ` vue.volar` ) 使用哪个版本? `2025-05-22` 更新 :经测试,最新可用版本为 `v2.2.8` ,`v2.2.10` 会报错。(可以关闭 vue.volar 的自动更新) ![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` 开始已经加入,不会再出现这个问题。 ## 5.不会 TypeScript 怎么办 不管个人还是团队、产品或者项目,从长远考虑我们都建议你学习 TypeScript,因为它是未来的趋势,而且大部分框架、库、插件都是用 TypeScript 开发的,足以证明它是构建一款成熟稳健产品的基石。 但考虑到实际情况,会各种客观原因存在,如果必须要用传统 JavaScript 进行开发,你可以在 `tsconfig.json` 里将 `allowJs` 设置为 `true` 即可,框架原有的 TypeScript 代码不会受到影响,并且你也可以在项目中使用 JavaScript 编写代码。 ## 6.微信小程序 `INVALID_LOGIN` 微信小程序开发进入登录页时,可能导致如下问题: ```text {errMsg: "navigateTo:fail Error: INVALID_LOGIN, access_token expired [20250103 17:08:03][touristappid]"} ``` > 解答:游客模式会出现该错误,微信扫码登录一下就可以了。 ## 7. unibest 如何运行 在钉钉小程序 package.json 中添加如下脚本: ```json { "uni-app": { "scripts": { "mp-dingtalk": { "title": "钉钉小程序", "env": { "UNI_PLATFORM": "mp-alipay" }, "define": { "MP-DINGTALK": true } } } } } ``` scripts 中添加如下脚本: ```json { "scripts": { "dev:mp-dingtalk": "uni -p mp-dingtalk" } } ``` --- --- url: 'https://unibest.tech/base/2-start-old.md' --- # 快速开始 * 前置依赖 * **Node.js** - `>=v20` (我的是 `v22.13.0`) * **pnpm** - `>=9+` (我的是 `10.11.0`) * **`VSCode`** - 可选 `WebStorm` * **`HBuilderX`** - `APP` 的运行和发布还是离不开它 ## 创建项目 通过下面的命令可以快速生成项目模板,`pnpm create unibest <项目名称>` ,如果不写 `<项目名称>` 会进入命令行交互模式。 ```bash # 如果没有 pnpm,请先安装: npm i -g pnpm pnpm create unibest # 时不时加一下 @latest 标识,这样可以使用最新版本的 create-unibest pnpm create unibest@latest ``` 实际操作截图如下: ![alt text](image-1.png) 新的 `base` 模板如何切换不同的 tabbar, 见 [tabbar 专题](./2-tabbar.md) ## 安装、运行 ```bash [pnpm] pnpm i pnpm dev # 运行h5 pnpm dev:mp # 运行微信小程序 pnpm dev:app # 运行App ``` `pnpm dev` 之后在浏览器打开 `http://localhost:9000/`。 > 其他平台构建和发布,查看 [运行发布篇](./11-build)。 ## 第一次 `commit` ```bash git add . git commit -m "feat: init project" ``` ## 必看章节 [uni 插件篇](/base/3-plugin) 和 [常见问题](/base/14-faq) ## `v3` 代码块 在 `vue` 文件中,输入 `v3` 按 `tab` 即可快速生成页面模板,可以大大加快页面生成。 > 原理:基于 `VSCode` 代码块生成。 ![alt text](./assets/2-4.gif) ## 注意事项 * 若代码里面自动引入的 `API` 报错,只需要 `pnpm dev` 即可。 * 若代码运行后,`H5端` 浏览器界面底部没有 `tabbar`, 刷新浏览器或者再次 `pnpm dev` 即可。 ## 项目仓库地址 `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 > 未来 `github` 上的仓库都可能迁移到 `unibest-tech` 组织下。 ## 旧的模板生成相关内容 ::: details 下面的在 2025-06-21 发布 v2.0.0 之后过期了 ![unibest templates](https://oss.laf.run/ukw0y1-site/xmind/unibest模板.png) `create unibest` 支持 `-t` 参数选择模板,目前已有两大类 `8` 个模板 * `普通` 模板( `4个` ):分别是 `base`、`tabbar`、`spa`、 `i18n`、`demo`。 * `hbx` 模板(`2个` ):分别是 `hbx-base`、`hbx-demo`。 不带 `-t` 参数时会默认生成 `base` 模板。 `base` 模板是最基本的模板,更新最及时,推荐使用 `base` 模板创建新项目。其他几个模板也是基于 `base` 模板得到的。 `demo` 模板则作为参考用。 `base` 模板的改动会自动同步到其他几个分支,通过 `github actions` 实现。 ```sh # VS Code 模板 pnpm create unibest # 默认用 base 模板 pnpm create unibest -t base # 基础模板 pnpm create unibest -t tabbar # 自定义 tabbar 模板 pnpm create unibest -t spa # 单页应用 模板(使用一个组件模拟tabbar) pnpm create unibest -t i18n # 多语言模板 pnpm create unibest -t demo # 所有demo的模板(包括i18n) ``` > 2024-12-29<周日> 发表了一篇文章:[【unibest】可以去掉 hbx 模版了,base 模板一统天下](https://mp.weixin.qq.com/s/ybunFNkjKfV5yVLOMvqscg?token=1696234630\&lang=zh_CN) > > 就是说 hbx 模板可以退出历史舞台了。 ::: --- --- url: 'https://unibest.tech/base/2-start.md' --- # 快速开始 ## 前置依赖 * **`Node.js`** - `>=v20` (我的是 `v22.13.0`) * **`Pnpm`** - `>=9` (我的是 `10.11.0`) * **`VSCode`** - 可选其他 `IDE` :`Trae`、`Cursor` 、`WebStorm` 等 * **`HBuilderX`** - `APP` 的运行和发布离不开它 * **`Git`** - 必须有 `git`,否则 `husky` 会报错 ## 使用方式 ### 方式一:通过 CLI 创建新项目(推荐) 通过 CLI 创建项目是**推荐**的方式,可以选择平台、UI 库、登录策略、多语言等配置。 ```bash # 全局安装 CLI pnpm add -g create-unibest # 创建项目 pnpm create unibest my-project cd my-project pnpm install pnpm dev ``` CLI 会从 Git `base` 分支克隆基础模板。 ### 方式二:创建时选择 Feature ```bash # 创建项目并选择功能 pnpm create unibest my-project # 或通过命令行参数直接指定 pnpm create unibest my-project --i18n --login --lime-echart --ucharts ``` ### 方式三:创建后添加 Feature ```bash cd my-project # 添加多语言 pnpm create unibest add i18n # 添加登录策略 pnpm create unibest add login # 添加图表库 pnpm create unibest add lime-echart pnpm create unibest add ucharts # 同时添加多个 pnpm create unibest add i18n login lime-echart ucharts ``` ## 安装、运行 ```bash [pnpm] pnpm i pnpm dev # 运行h5 pnpm dev:mp # 运行微信小程序 pnpm dev:app # 运行App ``` `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` 即可。 ## 项目仓库地址 `github` 和 `gitee` 实时同步,代码一致。 * https://github.com/feige996/unibest * https://gitee.com/feige996/unibest --- --- url: 'https://unibest.tech/other/files/files.md' --- # 文件资源展示优化 > 本功能由 `⑤群` 群友 `Collapsar` 提供,感谢 `Collapsar` 的贡献。 **未配置前的默认效果:** ![alt text](image-1.png) **配置后效果:** ![alt text](image-2.png) **相关代码:** ![alt text](image-3.png) > 如果觉得不需要这种查看方式,可以删除 or 注释掉 `.vscode/setting.json` 里面 `explorer.fileNesting.patterns` 配置。 --- --- url: 'https://unibest.tech/base/4-style.md' --- # 样式篇 本篇主要介绍 `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, 使用 `