uni-app
uni-app
uni-app
是一个使用 Vue.js 开发所有前端应用的框架,开发者编写一套代码,可发布到 iOS、Android、Web(响应式)、以及各种小程序(微信/支付宝/百度/头条/飞书/QQ/快手/钉钉/淘宝)、快应用等多个平台。
DCloud
公司拥有 900 万开发者、数百万应用、12 亿手机端月活用户、数千款 uni-app 插件、70+ 微信/qq 群。阿里小程序工具官方内置 uni-app(详见),腾讯课堂官方为 uni-app 录制培训课程(详见),开发者可以放心选择。
uni-app
在手,做啥都不愁。即使不跨端,uni-app
也是更好的小程序开发框架(详见)、更好的 App 跨平台框架、更方便的 H5 开发框架。不管领导安排什么样的项目,你都可以快速交付,不需要转换开发思维、不需要更改开发习惯。
看视频,10 分钟了解 uni-app
为什么要选择 uni-app?
uni-app
在开发者数量、案例、跨端抹平度、扩展灵活性、性能体验、周边生态、学习成本、开发成本等 8 大关键指标上拥有更强的优势。
功能框架图
一套代码编到 14 个平台,这不是梦想。眼见为实,扫描 14 个二维码,亲自体验最全面的跨平台效果!
一套代码,运行到多个平台
uni-app
实现了一套代码,同时运行到多个平台;如下图所示,一套代码,同时运行到 iOS 模拟器、Android 模拟器、Web、微信开发者工具、支付宝小程序 Studio、百度开发者工具、字节跳动开发者工具、QQ 开发者工具(底部每个终端选项卡,代表 1 个终端模拟器):
快速上手
在 manifest.jon 文件中填写你自己注册下来小程序 AppID
HBuilderX 与微信开发者工具联动
目录结构
目录名 | 功能描述 |
---|---|
pages 目录 | 存放页面文件 |
static 目录 | 存放静态文件 (图片) |
App.vue 文件 | 所有小程序页面都被引用到该文件运行 |
main.js 文件 | 项目入口文件,用来初始化 VUE 对象,定义全局组件等 |
manifest.json 文件 | 工程配置文件,声明应用的名称、图标、权限等 |
pages.json 文件 | 页面注册文件,配置页面路径、窗口样式、标题文字等 |
uni.scss 文件 | 全局样式文件 |
什么是 uniapp 框架
使用 Vue.js 开发所有前端应用的框架,开发者编写一套代码,可发布到 iOS、Android、Web、以及各种小程序(微信/支付宝/百度/头条/飞书/QQ/快手/钉钉/淘宝)、快应用等多个平台
官网地址:https://uniapp.dcloud.net.cn/
VScode 插件安装
通过 uni-app 框架创建项目
HBuilderX 可视化方式(只能在 XBuild 中运行)
HBuilderX工具下载
https://www.dcloud.io/hbuilderx.html
vue-cli 命令行方式(可以再 VS code 中运行)
1### 环境安装
2# 查看是否安装有@vue/cli
3vue -V
4
5# 设置镜像源
6npm config set registry https://registry.npmmirror.com
7
8# 无则执行命令安装
9npm install -g @vue/cli
10
11### 安装 Vue3/vite/typescript 项目模板
12npx degit dcloudio/uni-preset-vue#vite-ts my-vue3-project
13
14### 直接访问官网提供的gitee地址下载
15https://gitee.com/dcloud/uni-preset-vue/repository/archive/vite-ts.zip
16
17
18
19### pmpm下载项目依赖
20# powershell超级管理员运行
21PS C:\WINDOWS\system32> set-ExecutionPolicy RemoteSigned(默认值为“N”): y
22
23# 查看是否安装pnpm
24pnpm -v
25
26# 无则安装
27npm install -g pnpm
28
29# 设置淘宝镜像源
30pnpm config set registry https://registry.npmmirror.com/
31
32# 下载依赖
33pnpm i
34
35# 运行
36pnpm dev:h5
目录结构
名称 | 描述 |
---|---|
node_modules 目录 | 放置项目的依赖文件 |
src 目录 | 放置开发的代码文件 |
pages 目录 | 放置页面文件 |
static 目录 | 放置静态文件 |
App.vue | 页面入口文件 |
env.d.ts | vue 文件的类型说明文件 |
main.ts | 程序的入口文件,加载各种公共组件 |
manifest.json | 5+App 拓展文件,打包 app 时要使用 |
pages.json | 全局配置文件,配置页面文件的路径、窗口样式、原生的导航栏、底部的原生 tabbar 等等 |
uni.scss | uniapp 的默认 CSS 样式 |
.gitignore | Git 忽略文件 |
index.html | 项目总的入口文件 |
package.json | 项目依赖的描述文件 |
pnpm-lock.yaml | 锁定项目的依赖包版本 |
tsconfig.json | TS 的语法识别和执行配置文件 |
vite.config.ts | 编译工具 vite 的配置文件 |
uni-app 项目运行在微信小程序调试
uni-app 框架的生命周期
生命周期函数
- 在项目运行过程中,各个阶段执行的回调函数成为生命周期钩子函数
- 在合适的时机做合适的任务,也就是对应的回调函数执行
- 在之前的 vue 项目中是 vue 实例的生命周期
- uni-app 不止支持 vue 实例的生命周期,还新增了其他的生命周期
uni-app 生命周期分类
- 应用生命周期
- 页面生命周期
- 组件生命周期
应用生命周期
- 官网文档地址
- 应用生命周期仅可在 App.vue 中监听,在页面监听无效
- App.vue 是 uni-app 的主组件,所有页面都是在 App.vue 下进行切换的,是页面入口文件。但 App.vue 本身不是页面,这里不能编写视图元素,也就是没有
页面生命周期
- 官网文档地址
- 支持 vue 标准的生命周期函数,同时新增了很多其他的生命周期函数
- 在 page 目录下配置的页面文件才能生效
- uni-app 会将 pages.json ==> pages 配置项中的第一个页面,作为当前工程的首页(启动页)
组件生命周期
- 官网文档地址
- 与 vue 标准组件的生命周期函数相同
- 没有页面级新增的 onLoad 等生命周期函数
路由配置使用和页面跳转传参
组件式路由跳转传参
组件式路由跳转
1<navigator url="/pages/about/index" open-type="navigate" hover-class="navigator-hover">
2 去个人中心
3</navigator>
路由传参
1### 传递参数
2<navigator url="/pages/mine/index?title=小滴课堂" open-type="navigate" hover-class="navigator-hover">
3 去个人中心
4</navigator>
5
6### 接受参数
7onLoad((option)=>{
8 console.log(option?.title)
9})
函数式路由跳转传参
函数式路由跳转
自动补全的插件:uni-app-snippets
1uni.navigateTo({
2 url: '/pages/index/index'
3})
路由传参
1### 传递参数
2uni.navigateTo({
3 url: '/pages/index/index?title=xdclass.net'
4})
5
6### 接受参数
7onLoad((option)=>{
8 console.log(option?.title)
9})
传参的问题
- url 值有长度限制,太长的字符串会传递失败
- 解决
- 通过 uniapp 的全局自定义事件
- 通过全局状态管理库处理
- pinia
- vuex
不同路由跳转配置的使用
pages.json 文件用来对 uni-app 进行全局配置,决定页面文件的路径、窗口样式、原生的导航栏、底部的原生 tabbar 等。
它类似微信小程序中 app.json 的页面管理部分。注意定位权限申请等原属于 app.json 的内容,在 uni-app 中是在 manifest 中配置。
属性 | 类型 | 必填 | 描述 | 平台兼容 |
---|---|---|---|---|
globalStyle | Object | 否 | 设置默认页面的窗口表现 | |
pages | Object Array | 是 | 设置页面路径及窗口表现 | |
easycom | Object | 否 | 组件自动引入规则 | 2.5.5+ |
tabBar | Object | 否 | 设置底部 tab 的表现 | |
condition | Object | 否 | 启动模式配置 | |
subPackages | Object Array | 否 | 分包加载配置 | H5 不支持 |
preloadRule | Object | 否 | 分包预下载规则 | 微信小程序 |
workers | String | 否 | Worker 代码放置的目录 |
微信小程序 |
leftWindow | Object | 否 | 大屏左侧窗口 | H5 |
topWindow | Object | 否 | 大屏顶部窗口 | H5 |
rightWindow | Object | 否 | 大屏右侧窗口 | H5 |
uniIdRouter | Object | 否 | 自动跳转相关配置,新增于 HBuilderX 3.5.0 | |
entryPagePath | String | 否 | 默认启动首页,新增于 HBuilderX 3.7.0 | 微信小程序、支付宝小程序 |
配置 2 个一级导航页面(tabBar)
- pages 目录新建 vue 文件
- pages.json 配置 tabBar
1"tabBar": {
2 "list": [
3 {
4 "pagePath": "pages/index/index",
5 "text": "首页"
6 },
7 {
8 "pagePath": "pages/mine/index",
9 "text": "我的"
10 }
11 ]
12}
路由配置分类
跳转方法 | 说明 |
---|---|
uni.navigateTo() | 保留当前页面,跳转到应用内的某个页面,使用 uni.navigateBack 可以返回到原页面 |
uni.redirectTo() | 关闭当前页面,跳转到应用内的某个页面 |
uni.reLaunch() | 关闭所有页面,打开到应用内的某个页面 |
uni.switchTab() | 跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面 |
uni.navigateBack() | 关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages() 获取当前的页面栈,决定需要返回几层 |
navigateTo
,redirectTo
只能打开非 tabBar 页面。switchTab
只能打开tabBar
页面。reLaunch
可以打开任意页面- 字节跳动小程序与飞书小程序不支持
总结
- 一般进行页面的跳转使用 uni.navigateTo
- tabbar 页面的跳转使用 uni.switchTab 或者 uni.reLaunch
1<view @click="toMinePage">去我的页面</view>
2<view @click="toTabbarPage">去tabBar页面</view>
3<view @click="toAllPage">reLaunch可以去任意类型的页面
4<view @click="back">返回</view>
5
6const toMinePage = () => {
7 uni.navigateTo({url: '/pages/common/index'})
8}
9const toTabbarPage = () => {
10 uni.switchTab({url: '/pages/mine/index'})
11}
12const toAllPage = () => {
13 uni.reLaunch({url: '/pages/mine/index'})
14}
15const back = () => { //返回上上级页面
16 uni.navigateBack({ delta: 2 })
17}
详解 uni.navigateTo()
参数 | 说明 |
---|---|
url | 需要跳转的应用内非 tabBar 的页面的路径 , 路径后可以带参数。参数与路径之间使用?分隔,参数键与参数值用=相连,不同参数用&分隔;如 'path?key=value&key2=value2',path 为下一个页面的路径,下一个页面的 onLoad 函数可得到传递的参数 |
animationType | 窗口显示的动画效果,详见:窗口动画 |
animationDuration | 窗口动画持续时间,单位为 ms |
events | 页面间通信接口,用于监听被打开页面发送到当前页面的数据。2.8.9+ 开始支持。 |
success | 接口调用成功的回调函数 |
fail | 接口调用失败的回调函数 |
complete | 接口调用结束的回调函数(调用成功、失败都会执行) |
1### 首页
2const toMinePage = () => {
3 uni.navigateTo({
4 url: '/pages/common/index',
5 animationType: 'pop-in',
6 animationDuration: 300,
7 events: {
8 //为指定时间添加一个监听器,获取被打开页面传送到当前页面的数据
9 acceptDataFromOpenedPage: function (data: string) {
10 console.log(data)
11 }
12 },
13 success: function (res){
14 // 通过evenChannel向被打开页面传送数据
15 res.eventChannel.emit('acceptDataFromOpenerPage', {data : '路由成功success回调函数传入的数据'})
16 }
17 })
18}
19
20### common页面
21import { onLoad } from '@dcloudio/uni-app'
22import { getCurrentInstance } from 'vue'
23
24onLoad(() => {
25 const instance = getCurrentInstance()?.proxy
26 // @ts-expect-error-error
27 const eventChannel = instance.getOpenerEventChannel()
28 eventChannel.emit('acceptDataFromOpenedPage', { data: '从about页面传回的数据'})
29 eventChannel.on('acceptDataFromOpenerPage', function (data: any){
30 console.log(data)
31 })
32})
getCurrentPages() 使用
获取当前的页面栈,以数组形式按栈的顺序给出,第一个元素为起首页,最后一个元素为当前页面 。
1# 获取当前页面栈信息
2onLoad(() => {
3 const pages = getCurrentPages()
4 // @ts-expect-error-error
5 console.log(pages[pages.length - 1].$page);
6})
7
8# 获取起始页栈信息
9onLoad(() => {
10 const pages = getCurrentPages()
11 // @ts-expect-error-error
12 console.log(pages[0].$page);
13})
14
15# 当前页栈信息
16{
17 "id": 5,
18 "path": "/pages/common/index",
19 "route": "pages/common/index",
20 "fullPath": "/pages/common/index",
21 "options": {},
22 "meta": {
23 "id": 5,
24 "backgroundColor": "#F8F8F8",
25 "navigationBar": {
26 "backgroundColor": "#F8F8F8",
27 "titleText": "普通页面",
28 "type": "default",
29 "titleColor": "#000000",
30 "titleSize": "16px"
31 },
32 "isNVue": false,
33 "route": "pages/common/index",
34 "pullToRefresh": {}
35 },
36 "openType": "navigateTo",
37 "statusBarStyle": "dark"
38}
39
40# 起始页栈信息
41{
42 "id": 4,
43 "path": "/pages/index/index",
44 "route": "pages/index/index",
45 "fullPath": "/pages/index/index",
46 "options": {},
47 "meta": {
48 "id": 4,
49 "backgroundColor": "#F8F8F8",
50 "navigationBar": {
51 "backgroundColor": "#F8F8F8",
52 "titleText": "首页",
53 "type": "default",
54 "titleColor": "#000000",
55 "titleSize": "16px"
56 },
57 "isNVue": false,
58 "isQuit": true,
59 "isEntry": true,
60 "isTabBar": true,
61 "tabBarIndex": 0,
62 "route": "pages/index/index",
63 "pullToRefresh": {}
64 },
65 "openType": "navigateTo",
66 "statusBarStyle": "dark"
67}
uniapp 常用的组件使用
名称 | 描述 |
---|---|
view | 它类似于传统 HTML 中的 div,用于包裹各种元素内容 |
scroll-view | 可滚动视图区域,用于区域滚动 |
swiper | 滑块视图容器,banner 轮播图 |
match-media | 适配不同屏幕的基本视图组件 |
movable-area | 可拖动区域 |
movable-view | 可移动的视图容器,在页面中可以拖拽滑动或双指缩放 |
名称 | 描述 |
---|---|
icon | 图标 |
text | 文本组件,用于包裹文本内容;组件内只支持嵌套 |
progress | 进度条 |
表单组件(Form)
标签名 | 说明 |
---|---|
button | 按钮 |
checkbox | 多项选择器 |
editor | 富文本输入框 |
form | 表单 |
input | 输入框 |
label | 标签 |
picker | 弹出式列表选择器 |
picker-view | 窗体内嵌式列表选择器 |
radio | 单项选择器 |
slider | 滑动选择器 |
switch | 开关选择器 |
textarea | 多行文本输入框 |
媒体组件(Media)
组件名 | 说明 |
---|---|
audio | 音频 |
camera | 相机 |
image | 图片 |
video | 视频 |
live-player | 直播播放 |
live-pusher | 实时音视频录制,也称直播推流 |
uniapp 常用的 API 使用
发起网络请求 uni.request
在各个小程序平台运行时,网络相关的 API 在使用前需要配置域名白名单。
1onLoad(() => {
2 //uni.request
3 uni.request({ url: 'https://api-v2.xdclass.net/api/card/v1/list'}).then((res) => {
4 console.log(res)
5 })
6})
OBJECT 参数说明
参数名 | 类型 | 必填 | 默认值 | 说明 | 平台差异说明 |
---|---|---|---|---|---|
url | String | 是 | 开发者服务器接口地址 | ||
data | Object/String/ArrayBuffer | 否 | 请求的参数 | App 3.3.7 以下不支持 ArrayBuffer 类型 | |
header | Object | 否 | 设置请求的 header,header 中不能设置 Referer | App、H5 端会自动带上 cookie,且 H5 端不可手动修改 | |
method | String | 否 | GET | 有效值详见下方说明 | |
timeout | Number | 否 | 60000 | 超时时间,单位 ms | H5(HBuilderX 2.9.9+)、APP(HBuilderX 2.9.9+)、微信小程序(2.10.0)、支付宝小程序 |
dataType | String | 否 | JSON | 如果设为 JSON,会对返回的数据进行一次 JSON.parse,非 JSON 不会进行 JSON.parse | |
responseType | String | 否 | text | 设置响应的数据类型。合法值:text、arraybuffer | 支付宝小程序不支持 |
sslVerify | Boolean | 否 | true | 验证 ssl 证书 | 仅 App 安卓端支持(HBuilderX 2.3.3+),不支持离线打包 |
withCredentials | Boolean | 否 | false | 跨域请求时是否携带凭证(cookies) | 仅 H5 支持(HBuilderX 2.6.15+) |
firstIpv4 | Boolean | 否 | false | DNS 解析时优先使用 ipv4 | 仅 App-Android 支持 (HBuilderX 2.8.0+) |
enableHttp2 | Boolean | 否 | false | 开启 http2 | 微信小程序 |
enableQuic | Boolean | 否 | false | 开启 quic | 微信小程序 |
enableCache | Boolean | 否 | false | 开启 cache | 微信小程序、抖音小程序 2.31.0+ |
enableHttpDNS | Boolean | 否 | false | 是否开启 HttpDNS 服务。如开启,需要同时填入 httpDNSServiceId 。 HttpDNS 用法详见 移动解析 HttpDNS | 微信小程序 |
httpDNSServiceId | String | 否 | HttpDNS 服务商 Id。 HttpDNS 用法详见 移动解析 HttpDNS | 微信小程序 | |
enableChunked | Boolean | 否 | false | 开启 transfer-encoding chunked | 微信小程序 |
forceCellularNetwork | Boolean | 否 | false | wifi 下使用移动网络发送请求 | 微信小程序 |
enableCookie | Boolean | 否 | false | 开启后可在 headers 中编辑 cookie | 支付宝小程序 10.2.33+ |
cloudCache | Object/Boolean | 否 | false | 是否开启云加速(详见云加速服务) | 百度小程序 3.310.11+ |
defer | Boolean | 否 | false | 控制当前请求是否延时至首屏内容渲染后发送 | 百度小程序 3.310.11+ |
success | Function | 否 | 收到开发者服务器成功返回的回调函数 | ||
fail | Function | 否 | 接口调用失败的回调函数 | ||
complete | Function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
数据缓存 uni.setStorage
1onLoad(() => {
2 //setStorageSync
3 uni.setStorageSync('token', 'soulboy')
4 console.log(uni.getStorageSync('token'))
5 uni.clearStorageSync()
6 setTimeout(() => {
7 uni.removeStorageSync('token')
8 },5000)
9})
异步方法 | 同步方法 | |
---|---|---|
设置 | uni.setStorage | uni.setStorageSync |
获取 | uni.getStorage | uni.getStorageSync |
删除指定 key | uni.removeStorage | uni.removeStorageSync |
清理缓存 | uni.clearStorage | uni.clearStorageSync |
界面 API
API | 功能描述 |
---|---|
uni.showToast | 显示消息提示框 |
uni.setNavigationBarTitle | 动态设置当前页面的标题 |
uni.setTabBarItem | 动态设置 tabBar 某一项的内容 |
uni.pageScrollTo | 将页面滚动到目标位置 |
uni.onWindowResize | 监听窗口尺寸变化事件 |
第三方 API
API | 功能描述 |
---|---|
uni.login | 显示消息提示框 |
uni.requestPayment | 统一各平台的客户端支付 API,不管是在某家小程序还是在 App 中,客户端均使用本 API 调用支付 |
项目初始化
1### 初始化代码
2# 安装 Vue3/vite/typescript 项目模板
3npx degit dcloudio/uni-preset-vue#vite-ts my-vue3-project
4
5# 也可以直接访问官网提供的gitee地址下载
6https://gitee.com/dcloud/uni-preset-vue/repository/archive/vite-ts.zip
7
8### Gitee代码仓库管理
9git init
10touch README.md
11git add README.md
12git commit -m "first commit"
13git remote add origin https://gitee.com/wang-chao1990/uniapp-xdclass.git
14git push -u origin "master"
15git push -f origin "master"
16
17
18### unocss配置
19# unocss.config.ts
20import presetWeapp from 'unocss-preset-weapp'
21import { defineConfig } from 'unocss'
22import { transformerAttributify, transformerClass } from 'unocss-preset-weapp/transformer'
23
24export default defineConfig({
25 presets: [
26 presetWeapp(), // 工具预设
27 ],
28 transformers: [
29 transformerAttributify(), // 支持属性化模式
30 transformerClass(), // 转换转义类名,支持class写法
31 ],
32 shortcuts: [
33 { center: 'flex items-center justify-center' },
34 { around: 'flex items-center justify-around' },
35 { between: 'flex items-center justify-between' },
36 ]
37})
38
39# main.ts
40import 'uno.css'
41
42# vite.config.ts
43import { defineConfig } from "vite";
44import uni from "@dcloudio/vite-plugin-uni";
45import Unocss from 'unocss/vite'
46
47export default defineConfig({
48 plugins: [uni(),Unocss()],
49});
50
51
52# 安装插件
53PS D:\Project\my-vue3-project> pnpm i unocss-preset-weapp unocss
54
55
56### 响应式语法糖和自动引入插件配置
57# 下载插件
58pnpm i unplugin-auto-import
59
60# vite.config.ts
61import { defineConfig } from "vite";
62import uni from "@dcloudio/vite-plugin-uni";
63import Unocss from 'unocss/vite'
64import AutoImport from 'unplugin-auto-import/vite'
65
66// https://vitejs.dev/config/
67export default defineConfig({
68 plugins: [
69 uni({
70 vueOptions: {
71 reactivityTransform: true
72 }
73 }),
74 Unocss(),
75 AutoImport({
76 dts: 'src/typings/auto-imports.d.ts',
77 imports: ['vue', 'uni-app', 'pinia'],
78 dirs: ['src/composables']
79 }),
80 ],
81});
82
83
84### Pinia状态管理的配置
85# 安装插件
86pnpm i pinia@2.0.30 pinia-plugin-persistedstate@3.0.2 -S
87
88# 引入Pinia // main.ts
89import { createSSRApp } from "vue";
90import App from "./App.vue";
91import { createPinia } from 'pinia';
92import { createPersistedState } from 'pinia-plugin-persistedstate';
93import 'uno.css'
94
95# 测试Pinia配置成功与否 引入Pinia和持久缓存的设置
96const pinia = createPinia().use(
97 createPersistedState({
98 storage: {
99 getItem(key: string) {
100 return uni.getStorageSync(key);
101 },
102 setItem(key: string, value: string) {
103 uni.setStorageSync(key, value);
104 },
105 },
106 })
107);
108
109export function createApp() {
110 const app = createSSRApp(App).use(pinia);
111 return {
112 app,
113 };
114}
115
116# index.vue页面中进行测试
117const { isLogin} = $(useUser())
118console.log('isLogin:',isLogin)