Uniapp
前期准备
运行环境 | 要求版本 | 推荐版本 |
---|---|---|
node | >=18.0.0 | 18.14.2 |
npm | >=9.0.0 | 9.5.0 |
HBuilder X | >=3.7 | >=3.7 |
目录结构
├─📂 server
│ ├─📂 dist # 打包目录
│ │ ├─ 📂 dev # 开发包
│ │ └──📂 build # 生成包
│ │
│ ├─📂 node_modules Node依赖
│ │ └──📂 ...
│ │
│ ├─📂 src # 源代码
│ ├──📂 api # 所有请求
│ ├──📂 components # 全局公用组件
│ ├──📂 enums # 全局枚举
│ ├──📂 hooks # 全局hook
│ ├──📂 pages # 所有页面
│ ├──📂 static # 静态资源文件
│ ├──📂 stores # 全局状态管理
│ ├──📂 styles # 全局样式
│ ├──📂 uni_modules # uniapp插件市场引入的包
│ ├──📂 utils # 全局公用方法
│ ├── App.vue # 入口页面
│ ├── main.ts # 入口文件 初始化,组册插件等
│ ├── manifest.json # uniapp各端相关配置
│ ├── pages.json # 页面配置
│ └── uni.scss # 全局scss变量
│
├── .env.development # 开发环境变量
├── .env.production # 生产环境变量
├── .eslintrc.js # Eslint规范配置
├── .gitignore # Git忽略文件配置
├── .stylelintrc.js # CSS规范配置
├── index.html # H5网页
├── jsconfig.json # jsconfig.json
├── package.json # package.json
└── vite.config.ts # vite 配置项
代码规范
- 采用了 Eslint 控制vue和js等代码规范
- 采用了 Stylelint 控制css的代码规范
- 规范配置文件所在位置:
- Eslint:
src/.eslintrc.js
- Stylelint:
src/.stylelinttc.js
- Eslint:
开发工具
【Visual Studio Code】开发
- 打开项目终端:
- 使用vscode打开uniapp目录,在vscode左上角菜单中点击
终端 > 新建终端
- 使用vscode打开uniapp目录,在vscode左上角菜单中点击
- 复制env文件:
- 1、复制.env.development.example,将复制的文件名修改为.env.development
- 2、复制.env.production.example,将复制的文件名修改为.env.production
- 3、打开.env.development文件,修改VITE_APP_BASE_URL变量的值为项目安装部署的服务端地址
- 安装并运行:
# 1、安装依赖 (仅需要安装一次)
npm install
# 2、运行到H5 (在终端运行命令)
npm run dev:h5
# 【其它运行命令】
npm run dev:mp-weixin # 运行到微信小程序
npm run build:h5 # 发行到H5
- 最终效果如下:
vite v2.9.18 dev server runing at:
> Local: http://localhost:3001/
> Local: http://192.168.0.23:3001/
read in 1628ms,
- Vscode配置建议:
- 安装 Eslint 插件
- 安装 Stylelint 插件
{
// 菜单缩进的设置
"workbench.tree.indent": 18,
// 设网页缩放级别
"window.zoomLevel": 1,
// 编辑器字体大小
"editor.fontSize": 16,
// 关闭类型切TabSize
"editor.detectIndentation": false,
// 重设定缩进TabSize
"editor.tabSize": 4,
// 每保存时自动格式化
"editor.formatOnSave": true,
// 启用Eslint规范校验
"eslint.enable": true,
// 启用Styles规范校验
"stylelint.enable": true,
// 每保存时Eslint修复
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true,
"source.fixAll.stylelint": true
},
// 每保存时Styles修复
"stylelint.validate": [
"css",
"less",
"postcss",
"scss",
"vue",
"sass"
],
// 确定校验准则ES
"eslint.validate": [
"javascript",
"javascriptreact"
]
}
【HBuilderX】开发
- 导入项目:
- 点击HBuilderX 左上角 菜单文件 > 导入 > 从本地目录导入,目录选择uniapp
- 复制env文件:
- 1、复制.env.development.example,将复制的文件名修改为.env.development
- 2、复制.env.production.example,将复制的文件名修改为.env.production
- 3、打开.env.development文件,修改VITE_APP_BASE_URL变量的值为项目安装部署的服务端地址
- 安装并运行:
- 选中当前项目,点击HBuilderX左上角菜单工具 > 外部命令 >
npm install
安装依赖 - 运行到H5,点击HBuilderX左上角菜单
运行
>运行到浏览器
>Chrome
- 运行到微信小程序,点击HBuilderX左上角菜单
运行
>运行到小程序模拟器
>微信开发者工具
-(uniapp)
- 选中当前项目,点击HBuilderX左上角菜单工具 > 外部命令 >
注意
运行到微信小程序前,先配置好小程序的appid:
- 点击uniapp/src/manifest.json,选择微信小程序配置>微信小程序AppID,输入appid即可
一般运行到微信小程序,会自动打开微信开发者工具,(如打开失败):
- 手动打开工具 -> 设置 -> 安全设置,将服务端口开启。
- 也有可能是你配置的小程序appid中,你登录的账号不是这个小程序的开发者。
- 只需要去微信小程序后台将该账号添加到开发者,重新运行即可。
M1/M2电脑编译报以下错误:
- [ERROR] Cannot start service: Host version "0.18.20" does not match binary version "0.17.19"
- 原因: 可能是你升级了vite的版本导致的兼容问题
- 解决: 把vite的版本改为(4.3.9) => "vite": "4.3.9"
【苹果(M)】芯片报错
- Apple M系列芯片在Uniapp下编译的报错处理:
警告
- 1、首先你要正常的安装依赖
npm install
- 2、在运行编译前你需要这样操作:
- 2.1、在
node_modules
找到@esbuild
目录进入到里面 - 2.2、这时候你看到目录里面只有一个
darwin-arm64
- 2.3、我们把
darwin-arm64
拷贝一份, 并且把拷贝出来的那份 重命名为darwin-x64
- 2.4、这时候你这个文件夹就存在两份文件了,分别是
darwin-arm64
和darwin-x64
- 2.5、到这里就可以了,重新运行编译,可以正常运行。
- 2.1、在
环境变量
变量命名规则:需要以VITE_为前缀的
如何使用说明:i
更多细节常见:https://vitejs.cn/guide/env-and-mode.html#env-variables
- .env.development (开发环境适用)
NODE_ENV = 'development'
# 请求域名
VITE_APP_BASE_URL='https://dev.waitadmin.cn'
- .env.production (生产环境适用)
NODE_ENV = 'production'
# 请求域名
VITE_APP_BASE_URL='https://www.waitadmin.cn'
页面配置
页面配置文件位置:uniapp/src/pages.json
如何配置请参考此:https://uniapp.dcloud.net.cn/collocation/pages.html
{
"auth": true,
"path": "pages/user/home",
"style": {
"navigationBarTitleText": "个人中心",
"navigationBarTextStyle": "white",
"navigationBarBackgroundColor": "#2979ff"
}
}
名称 | 类型 | 默认 | 说明 |
---|---|---|---|
auth | boolean | false | 自定义参数,控制是否需要登录才可访问 |
vary | boolean | false | 自定义参数,是否关闭渲染主题颜色 |
path | string | null | uni官方参数,页面的路径,"必须存在" |
style | object | null | uni官方参数,配置页面的样式 |
- | - | - | 更多参数请看uni官方文档,自定就两个 |
接口请求
基本描述
- 系统中使用uview提供的方法发起请求,并对其进行了更深一步的封装,位于src/utils/request
- 如果你需要调整http请求时的一些参数,你可以在config.js中调整
- 如果你需要对响应回来的数据进行统一处理,你可以在http.js中调整
├──📂 request
│ ├── config.js # 封装请求的配置参数
│ ├── http.js # 封装Http请求和拦截
│ ├── route.js # 页面路由跳转等拦截
│
默认配置
export const config = {
// 请求的本域名
baseUrl: `${import.meta.env.VITE_APP_BASE_URL || ''}/api`,
// 设置为JSON
dataType: 'json',
// 显示请求中
showLoading: false,
// 加载提示文
loadingText: '请求中...',
// 在此时间内请求中就显示加载中的动画
loadingTime: 800,
// 是否在拦截器中返回服务端的原始数据
originalData: true,
// 展示加载时候给透明蒙层防止触摸穿透
loadingMask: true,
// 配置网络发起的请求头信息
header: {
'content-type': 'application/json;charset=UTF-8'
}
}
请求拦截
Vue.config.globalProperties.$u.http.interceptor.request = (config) => {
const userStore = useUserStore()
config.header.token = userStore.$state.token
config.header.terminal = clientUtil.fetchClient()
return config
}
响应拦截
Vue.config.globalProperties.$u.http.interceptor.response = (response) => {
const result = response.data
const { logout } = useUserStore()
const isStructure = response.header.structure || response.header.Structure
switch (result.code) {
case errorEnum.SUCCESS:
return isStructure ? result : result.data
case errorEnum.SYSTEM_ERROR:
case errorEnum.PARAMS_ERROR:
case errorEnum.METHOD_ERROR:
case errorEnum.CONTROL_ERROR:
case errorEnum.REQUEST_ERROR:
case errorEnum.OPERATE_ERROR:
case errorEnum.UPLOADS_ERROR:
case errorEnum.PURVIEW_ERROR:
uni.$u.toast(result.msg)
return Promise.reject(result)
case errorEnum.LOGIN_EMPTY_ERROR:
case errorEnum.LOGIN_EXPIRE_ERROR:
logout()
uni.navigateTo({ url: '/pages/login/enroll' })
return Promise.reject(result)
default:
return result
}
}
接口配置
- 我们对所有请求接口进行了统一管理, 统一放在
src/api/..
目录下面 - 以下我们以文章管理的接口作为示例子展开说明一下
articleApi.js
// articleApi.js 文件的内容
export default class {
/**
* 分类类别
*/
static category() {
return uni.$u.http.get('article/category')
}
/**
* 文章列表
*/
static lists(params) {
const param = {
cid: params.cid || 0,
pageNo: params.pageNo || 1,
pageSize: params.pageSize || 10
}
return uni.$u.http.get('article/lists', param)
}
/**
* 文章详情
*/
static detail({ id }) {
return uni.$u.http.get('article/detail', { id })
}
}
- uni.$u.http 方法的参数说明
uni.$u.http.get(
'article/detail', // 请求的api地址
{ id: 1 }, // 请求携带的参数
{ Structure: true } // 请求header头参数
)
// PS: 注意上面请求头中的, Structure 参数
// 此参数的意思是,是否返回数据结构,默认是 false 即不返回结构
// 没有特殊情况,不用填写 Structure这个参数
// 问: 那到底是怎么一个结构呢?
// 默认返回的结构如下:
{
"id": 1,
"title": "风起东方日日新",
"content": ""
}
// 如果开启返回数据结构,返回如下:
{
"code": 0,
"msg": "success",
"data": [
{
"id": 1,
"title": "风起东方日日新",
"content": ""
}
]
}
主题样式
基础样式
- 我们定义了一些比较常用的css样式,放在了
src/styles/basis.scss
/* 字体大小 */
.font-xs { font-size: 24rpx; }
.font-sm { font-size: 26rpx; }
.font-bm { font-size: 28rpx; }
.font-lg { font-size: 30rpx; }
.font-xl { font-size: 32rpx; }
.font-2xl { font-size: 34rpx; }
.font-3xl { font-size: 36rpx; }
.font-4xl { font-size: 38rpx; }
.font-5xl { font-size: 40rpx; }
.font-6xl { font-size: 42rpx; }
.font-7xl { font-size: 44rpx; }
.font-8xl { font-size: 46rpx; }
.font-9xl { font-size: 48rpx; }
.font-xxl { font-size: 60rpx; }
/* 字体粗细 */
.font-weight-thin { font-weight: 100; }
.font-weight-fine { font-weight: 200; }
.font-weight-light { font-weight: 300; }
.font-weight-normal { font-weight: 400; }
.font-weight-medium { font-weight: 500; }
.font-weight-semi { font-weight: 600; }
.font-weight-bold { font-weight: 700; }
.font-weight-extra { font-weight: 800; }
.font-weight-black { font-weight: 900; }
// PS: 更多样式请自行在代码里面查看
// 怎么使用呢? 直接在页面标签里面使用就可以了,例如:
<template>
<div class="font-lg font-weight-bold">
WaitAdmin
</div>
</template>
样式穿透
- **开启scoped属性后需要如果需要将样式作用到子组件上,可以这样处理:**
<style scoped>
:deep(.el-menu-item) {
// todo
}
</style>
主题配置
- 主题的css样式统一配置在以下文件中
src/styles/theme.scss
- 目前提供3种主题颜色,您也可以扩展自己的主题色
- 如果你扩展了别的主题色,别忘记在后台也加上哦
// 天空蓝主题
.default-theme,
.blue-theme {
--theme-color: #2979ff;
--theme-background: #2979ff;
.color-theme { color: #2b85e4; }
.u-btn--theme {
color: #ffffff;
border-color: #2979ff;
background-color: #2979ff;
}
.u-btn--theme--plain {
color: #2979ff;
border-color: #a0cfff;
background-color: #ecf5ff;
}
}
// 热情红主题
.red-theme {
--theme-color: #ff5058;
--theme-background: #ff5058;
.color-theme { color: #ff5058; }
.u-btn--theme {
color: #ffffff;
border-color: #ff5058;
background-color: #ff5058;
}
.u-btn--theme--plain {
color: #ff5058;
border-color: #ffa0a0;
background-color: #ffecec;
}
}
// 生鲜绿主题
.green-theme {
--theme-color: #40ca4d;
--theme-background: #40ca4d;
.color-theme { color: #40ca4d; }
.u-btn--theme {
color: #ffffff;
border-color: #40ca4d;
background-color: #40ca4d;
}
.u-btn--theme--plain {
color: #40ca4d;
border-color: #9efba7;
background-color: #eafcec;
}
}
关于主题
- 主题采用
mixins
混入的方式进行控制, 之所以您在后台切换,页面颜色也能跟着边,和它脱不开关系 - 我们定义了一个
appMixin.js
文件进行主题的相关处理。 (具体逻辑自己看代码) - 简单说明: 有了它以后, 每个页面默认有一个 onLoad() 方法, 并且它会处理主题 - 重要的说明:
- 如果您想页面得到主题的控制,那你一定要在页面的根节点设置
:class="themeName"
- 这个很重要,如果你不设置,则表示这个页面不受主题色控制,建议都加上。
- 示例如下: (你也可以看下我代码是怎么写的)
<template>
<view :class="themeName">
<div>页面内容</div>
</view>
</template>
常用工具
- 为了开发更方便快捷,我们编写了一些常用的工具类 都放在以下目录:
src/utils/...
缓存工具 (cacheUtil.js)
import cacheUtil from '@/utils/cacheUtil'
/**
* 设置缓存
*
* @param string k (键)
* @param string v (值)
* @param int t (过期时间)
*/
cacheUtil.set(k, v, t)
/**
* 获取缓存
*
* @param string k (键)
* @param def (默认,如果为null返回这个)
*/
cacheUtil.get(k, def)
/**
* 删除缓存
*
* @param string k (键)
*/
cacheUtil.remove(k)
/**
* 清空缓存
*/
cacheUtil.clear()
验证工具 (checkUtil.js)
import checkUtil from '@/utils/checkUtil'
// PS: 以下验证都是,如果为true=是, false=不是
// 类型验证
checkUtil.is(val, type)
// 开发模式
checkUtil.isDevMode()
// 生产模型
checkUtil.isProdMode()
// Map类型
checkUtil.isMap(val)
// Date类型
checkUtil.isDate(val)
// isNumber
checkUtil.isDate(val)
// String类型
checkUtil.isString(val)
// Boolean类型
checkUtil.isBoolean(val)
// RegExp类型
checkUtil.isRegExp(val)
// Array类型
checkUtil.isArray(val)
// Function类型
checkUtil.isFunction(val)
// Object类型
checkUtil.isObject(val)
// Promise类型
checkUtil.isPromise(val)
// Null类型
checkUtil.isNull(val)
// Empty类型
checkUtil.isNull(val)
// Undefined类型
checkUtil.isNull(val)
// Undefined或Null
checkUtil.isNullOrUndefined(val)
// Window类型
checkUtil.isWindow(val)
// 是否是手机号
checkUtil.isMobile(val)
// 是否是邮箱号
checkUtil.isEmail(val)
客户端工具 (clientUtil.js)
import clientUtil from '@/utils/clientUtil'
// 是否是微信环境 (公众号/微信小程序)
// 用于判断是否在微信内置浏览器打开的
clientUtil.isWeixin()
// 是否为安卓环境 (如果是APP端)
// true=是安卓, false=苹果
clientUtil.isAndroid()
// 返回当前客户端标识
// 1 = 微信小程序
// 2 = 微信公众号
// 3 = H5
// 4 = PC
// 5 = 苹果
// 6 = 安卓
clientUtil.fetchClient()
其它工具 (toolUtil.js)
import toolUtil from '@/utils/toolUtil'
// 提取微信小程序Code
toolUtil.obtainWxCode()
// 提取微信位置(定位坐标)
toolUtil.obtainWxLocation()
// 获取底部导航
// 那些页面是固定在底部的
// 如果有变动,记得到这里修改一下
toolUtil.tarBarList()
// 获取当前页面
toolUtil.currentPage()
// 上传文件资源
toolUtil.uploadFile()
// 渲染底部导航
// 一般情况,你并不需要动它
toolUtil.setTabBar()
国际化(多语言)
关于多语言
注意
uni-app的国际化,即多语言,分为应用部分和框架部分。
应用部分,即开发者自己的代码里涉及的界面部分 框架部分,即uni-app内置组件和API涉及界面的部分 不同端的国际化方案也有差异,uni-app 自 3.1.5起,App 和 H5 支持框架国际化。小程序平台的国际化依赖于小程序平台框架自身。一般而言海外用户更多使用的是App和H5
看完本文档还不知道怎么使用,请看官方文档
PS: Uniapp关于对语言的文档: https://uniapp.dcloud.net.cn/tutorial/i18n.html#
语言包管理
1、语言包统一放在
src/lang/..
目录下2、我们内置了常用三个语言包(其它的自行扩展),内置的有:
- en.json 英文
- zh-Hans.json 简体中文
- zh-Hant.json 繁体中文
3、UniApp 支持多种语言地区代码,以下是一些常见语言地区代码的示例:
简体中文:zh-Hans
繁体中文:zh-Hant
英文:en
法文:fr
德文:de
日文:ja
韩文:ko
俄文:ru
语言包配置
- 这里说的是语言包要怎么配置
- 我们已简体中文语言包
zh-Hans.json
为示例: - PS: 其它语言包也是一言的,把里面的值换成对应的就行
{
"pages.index.index": "WaitAdmin开源系统",
"pages.login.enroll": "登录"
}
语言包的使用
- 前面一直在在说如何去定义语言包。
- 这里我们说一下怎么去使用语言包。
在页面中的使用
- 页面模板中使用 $t() 获取,并传递国际化json文件中定义的key,js中使用 this.$t('')
- PS: 在vue3中如果使用了 setup 语法糖 是无法直接在 js 中使用 this对象的,下面我再讲怎么用。
<template>
<view class="container">
<view class="title">{{ $t('pages.index.index') }}</view>
</view>
</template>
在Js中的使用
- Vue2 中使用
this.$t('')
- Vue3 中使用:
<script setup>
import {getCurrentInstance } from 'vue'
// 此方法在开发环境以及生产环境下都能放到组件上下文对象
const { proxy } = getCurrentInstance()
// 然后你就可以直接使用 $t 方法了
proxy.$t('pages.index.index')
</script>
在pages.json中使用
- 使用 %% 占位
{
"pages": [
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "%pages.index.index%"
}
}
],
"tabBar": {
"list": [{
"pagePath": "pages/index/index",
"text": "%pages.index.index%"
}
]
}
}
如何切换语言
- 在
src/main.js
文件中进行切换 locale
参数是控制使用什么语言的。- 你要改成别的语言(如英文)你可以这样配置:
locale: 'en'
// 以下是默认的语言: zh-Hans (简体中文)
let i18nConfig = {
locale: uni.getLocale(),
messages:{
'en': en,
'zh-Hans': zhHans,
'zh-Hant': zhHant
}
}
// 切换到英文语言
let i18nConfig = {
locale: 'en', // 这里直接改成对应的语言包就行
messages:{
'en': en,
'zh-Hans': zhHans,
'zh-Hant': zhHant
}
}
// uni.getLocale()
这个是获取语言的
// uni.setLocale()
这个是设置语言的
扩展其它语言
- 1、在lang目录加入语言包如
jp.json
- 2、在
main.js
导入语言包,示例
import App from './App.vue'
import en from './lang/en.json'
import zhHans from './lang/zh-Hans.json'
import zhHant from './lang/zh-Hant.json'
// 1、导入你扩展的语言包
import jp from './lang/jp.json'
// 2、把语言包加入到配置
let i18nConfig = {
locale: 'en',
messages:{
'en': en,
'zh-Hans': zhHans,
'zh-Hant': zhHant,
'jp': jp // 加入到这里
}
}
// 3、到这里你就可以正常使用了
小程序国际化
- 已支持:
- 页面
- 组件
- 不支持:
- pages.json,可以通过调用API来设置,例如更改标题
uni.setNavigationBarTitle()
- tabbar 不支持动态修改内容,但是可以通过自定义tabbar的方式,详情: https://uniapp.dcloud.net.cn/collocation/pages?id=custom-tab-bar
- pages.json,可以通过调用API来设置,例如更改标题
其它
按钮加载
- 如果您想在请求接口的时候,在数据没有返回前,让按钮可以显示loading状态,你可以这么做。
- 这样子操作可以避免用户重复点击按钮,导致重复请求。
<u-button
:loading="loading"
type="theme"
shape="circle"
@click="onSaLogin()"
>登录</u-button>
<script setup>
import { useLock } from '@/hooks/useLock'
import loginApi from '@/api/loginApi'
const { loading, methodAPI:$loginApi } = useLock(loginApi.login)
const onSaLogin = () => {
let params = {...}
$loginApi(params).then(async result => {
// todo 结果返回后处理的逻辑
}).catch(() => {
loading.value = false // 把loading状态关闭
})
}
</script>
小部件
- 我们制作了一些比较常用的小部件(组件),存放在
src/components/widgets/...
- 具体参数看代码吧,暂时没有时间细说这里面的参数
- adv (广告部件)
- button (按钮部件)
- service (服务部件)