uni-app 官网教程
uni 读you ni,是统一的意思。uni-app 即 统一 app,写一次代码,在各个平台都可以运行。uni-app 是由 DCloud 团队推出的使用Vue.js开发跨平台应用的前端框架。开发者编写一套代码,可发布到 iOS、Android、Web(响应式)、以及各种小程序(微信/支付宝/百度/头条/飞书/QQ/快手/钉钉/淘宝)、快应用等多个平台。
api 帮助 (直接搜索 关键字) :https://uniapp.dcloud.net.cn/api/
官网:https://uniapp.dcloud.net.cn/
github :https://github.com/dcloudio/uni-app
在线 即使设计 工具:https://js.design/
uni-app 设计资源:https://uniapp.dcloud.io/component/uniui/resource.html
uniapp从入门到精通 (保姆式教程):https://blog.csdn.net/YuanFudao/article/details/132384692
Uni-App从入门到实战-黑马程序员:https://www.bilibili.com/video/BV1Bp4y1379L/
小兔鲜儿-vue3+ts-uniapp:https://gitee.com/Megasu/uniapp-shop-vue3-ts
项目文档:https://megasu.atomgit.net/uni-app-shop-note/rabbit-shop/
uniapp商城实战项目
:https://www.bilibili.com/video/BV1np421174L
:https://www.bilibili.com/video/BV1Fk4y1v7U6
:https://blog.csdn.net/m0_51607907/article/details/125164150
:https://github.com/gooking/uni-app-mall
:https://github.com/gooking/uni-app--mini-mall
1、uni-app 介绍
介绍
uni 读 you ni,是统一的意思。uni-app 即 统一 app,写一次代码,在各个平台都可以运行。uni-app 是由 DCloud 团队推出的使用 Vue.js 开发跨平台应用的前端框架。开发者编写一套代码,可发布到 iOS、Android、Web(响应式)、以及各种小程序(微信/支付宝/百度/头条/飞书/QQ/快手/钉钉/淘宝)、快应用等多个平台。
功能框架图
一套代码,运行到多个平台。uni-app
实现了一套代码,同时运行到多个平台;如下图所示,一套代码,同时运行到iOS模拟器、Android模拟器、web、微信开发者工具、支付宝小程序Studio、百度开发者工具、抖音开发者工具、QQ开发者工具(底部每个终端选项卡,代表1个终端模拟器):
实际运行效果如下(点击图片可放大):
uni-app 是免费并且属于Apache2.0开源协议的产品。DCloud 官方承诺 HBuilderX、uni-app 面向全球程序员永久免费。HBuilderX 是 uni-app 的官方 ide
uni-app 遵循 Vue.js 语法规范,组件和API遵循微信小程序命名,这些都属于通用技术栈,有一定 Vue.js 和微信小程序开发经验的开发者可快速上手 uni-app 。没学过 vue 的同学,也不用掌握 vue 的全部,只需了解 vue 基础语法、虚拟 dom、数据绑定、组件、vuex,其他如路由、loader 不用学,cli、node.js、webpack 也不需要学。
uni-app、uni-app x 区别
uni-app x 是什么:https://doc.dcloud.net.cn/uni-app-x/
- uni-app x,是下一代 uni-app,是一个跨平台应用开发引擎。
- uni-app x 是一个庞大的工程,它包括uts语言、uvue渲染引擎、uni的组件和API、以及扩展机制。在 Android 平台,uni-app x 的工程被整体编译为kotlin代码,本质上是换了 vue 写法的原生 kotlin 应用,在性能上与原生 kotlin 一致。可以体验打包后的 hello uni-app x
关于 uts 语言:https://doc.dcloud.net.cn/uni-app-x/uts/
- uts 全称 uni type script,是一门类 ts 、跨平台的、高性能的、强类型的现代编程语言。它在不同平台,会被编译为不同平台的native语言,如:
web / 小程序,编译为 JavaScript
Android 平台,编译为 Kotlin
iOS 平台,编译为 Swift - 在 uni-app x 中,需使用 uts 而不是 js。尤其是 Android端不自带js引擎,无法运行js代码。
- uts 和 ts 很相似,但为了跨端,uts 进行了一些约束和特定平台的增补。详见 uts语言介绍
uvue 渲染引擎
- uts替代的是js,而uvue替代的就是html和css。或者如果你了解flutter的话,也可以理解为uts类似dart,而uvue类似flutter。uvue是一套基于uts的、兼容vue语法的、跨平台的、原生渲染引擎。
- uvue 渲染引擎包括uts版的vue框架(组件、数据绑定...)、跨平台基础ui、css引擎。有了uvue,开发者就可以使用vue语法、css来快速编写页面,编译为不同平台的、高性能的纯原生界面。
- uvue支持的是vue3语法,支持组合式API和选项式API。详见vue语法
如何学习
- 建议第一步,看完uni-app官网 (opens new window)的首页介绍。
- 建议第二步,通过快速上手 (opens new window),亲身体验下uni-app。
- 建议第三步,看完《uni-app官方教程》 (opens new window),
如果你熟悉h5,但不熟悉vue和小程序
- 看完这篇白话uni-app(opens new window)
- DCloud与vue合作,在vue.js官网 (opens new window)提供了免费视频教程,也可以直达教程地址:https://learning.dcloud.io(opens new window)
- 不需要去专门学习小程序的语法,uni-app 使用的是 vue 的语法,不是小程序自定义的语法。
如果熟悉小程序,但不熟悉 vue,参考三方总结https://segmentfault.com/a/1190000015684864(opens new window)
第三方培训机构视频
目前各大视频学习网站都有不少 uni-app 的学习资源:
- bilibili的uni-app相关视频(opens new window)
- 腾讯课堂的uni-app相关课程(opens new window)
- 网易课堂的uni-app相关课程(opens new window)
- 慕课网uni-app相关课程(opens new window)
如下是三方专业培训机构的视频教程
- 《uni-app 商业级应用实战》 (opens new window),出品人:腾讯课堂NEXT学院。亮点:腾讯课堂官方出品;不懂 vue 的工程师也可快速学习;从入门到实战都包括。
- 《uni-app 跨平台应用开发教程》 (opens new window),出品人:hcoder 刘海君,课时:共25节。亮点:讲师经验丰富,也是graceui框架作者。
- 《uni-app 实战教程 - “悦读”项目实战》 (opens new window),出品人:hcoder 刘海君
- 《uni-app实战社区交友类app开发》 (opens new window),出品人:帝莎IT学院。适用人群:具备Html+Css+Javascript基础知识。
- 《uni-app仿小米商城实战》 (opens new window),出品人:帝莎IT学院。首页使用nvue开发,目前支持app端和小程序端。
- 《uni-app多端调试环境配置》 (opens new window),出品人:帝莎IT学院。
- 《uni-app实战仿微信app全栈开发》 (opens new window),出品人:帝莎IT学院。
- 《uni-app实战视频点播app小程序》 (opens new window),出品人:帝莎IT学院。
- 《uni-app 5小时快速入门》 (opens new window),出品人:meHaoTian
- 《uni-app实战直播app全栈开发》 (opens new window),出品人:帝莎IT学院
- 《uni-app博客实战开发教程》 (opens new window),出品人:卢小兵
- 《uni-app快速入门到社区论坛项目多端开发实战》 (opens new window),出品人:千锋教育
- 《uni-app新手入门》 (opens new window),出品人:蓝桥云课
- 《uniapp 原生插件开发-android》 (opens new window),出品人:朱哲
- 《uniapp 原生插件开发-iOS》 (opens new window),出品人:朱哲
uni-app 相关书籍
如果你是线下培训机构,想开课合作,联系bd@dcloud.io
欢迎更多人分享学习经验,可转载到社区 (opens new window),优秀的文章我们会收录在本文中。
#uniCloud的学习资料
掌握uniCloud,进阶全栈,详见:https://uniapp.dcloud.io/uniCloud/learning(opens new window)
#关于各端的管理规则需要耐心学习
uni-app并不难学,但我们注意到很多新人在适应各个平台的规则限制时比较急躁。
每个端,有每个端的管理规则,这不是uni-app在技术层面上可以抹平的:
- 比如H5端的浏览器有跨域限制;
- 比如微信小程序会强制要求https链接,并且所有要联网的服务器域名都要配到微信的白名单中;
- 比如App端,iOS对隐私控制和虚拟支付控制非常严格;
- 比如App端,Android、国产rom各种兼容性差异,尤其是因为谷歌服务被墙,导致的push、定位等开发混乱的坑;
遇事耐心,不急不躁,虽然这不是成功的唯一要素,但它是你技术路上长远走下去的基础。
#uni-app的底层框架实现原理及优化策略(高级)
通过评测对比 (opens new window),我们知道uni-app的性能比其他小程序开发框架好,但底层原理是什么? 这篇视频就是讲解uni-app框架底层的实现思路和优化策略:《uni-app框架如何实现高性能》
跨端 问题
每个端有每个端的特点,有的能被抹平,有的不可能被抹平。注意:跨端,不是把web的习惯迁移到全平台。而是按照uni的写法,然后全平台使用。
:https://uniapp.dcloud.net.cn/matter.html
2、uni-app 教程
官网教程:https://uniapp.dcloud.net.cn/tutorial/
概念 简介
基本语言和开发规范
uni-app代码编写,基本语言包括js、vue、css。以及ts、scss等css预编译器。
在app端,还支持原生渲染的nvue,以及可以编译为kotlin和swift的uts。
DCloud还提供了使用js编写服务器代码的uniCloud云引擎。所以只需掌握js,你可以开发web、Android、iOS、各家小程序以及服务器等全栈应用。
为了实现多端兼容,综合考虑编译速度、运行性能等因素,
uni-app
约定了如下开发规范:
- 页面文件遵循 Vue 单文件组件 (SFC) 规范,即每个页面是一个.vue文件
- 组件标签靠近小程序规范,详见uni-app 组件规范
- 接口能力(JS API)靠近小程序规范,但需将前缀
wx
、my
等替换为uni
,详见uni-app接口规范- 数据绑定及事件处理同
Vue.js
规范,同时补充了应用生命周期及页面的生命周期- 如需兼容app-nvue平台,建议使用flex布局进行开发
uni-app分
编译器
和运行时(runtime)
。uni-app能实现一套代码、多端运行,是通过这2部分配合完成的。编译器将开发者的代码进行编译,编译的输出物由各个终端的runtime进行解析,每个平台(Web、Android App、iOS App、各家小程序)都有各自的runtime。
编译器
更多编译器介绍参见:编译器
- 编译器运行在电脑开发环境。一般是内置在HBuilderX工具中,也可以使用独立的cli版。
- 开发者按uni-app规范编写代码,由编译器将开发者的代码编译生成每个平台支持的特有代码
- 在web平台,将.vue文件编译为js代码。与普通的vue cli项目类似
- 在微信小程序平台,编译器将.vue文件拆分生成wxml、wxss、js等代码
- 在app平台,将.vue文件编译为js代码。进一步,如果涉及uts代码:
- 在Android平台,将.uts文件编译为kotlin代码
- 在iOS平台,将.uts文件编译为swift代码
- 编译器分vue2版和vue3版
- vue2版:基于
webpack
实现- vue3版:基于
Vite
实现,性能更快- 编译器支持条件编译,即可以指定某部分代码只编译到特定的终端平台。从而将公用和个性化融合在一个工程中。
// #ifdef App
console.log("这段代码只有在App平台才会被编译进去。非App平台编译后没有这段代码")
// #endif
运行时(runtime)
runtime不是运行在电脑开发环境,而是运行在真正的终端上。uni-app在每个平台(Web、Android App、iOS App、各家小程序)都有各自的runtime。这是一个比较庞大的工程。
- 在小程序端,uni-app的runtime,主要是一个小程序版的vue runtime,页面路由、组件、api等方面基本都是转义。
- 在web端,uni-app的runtime相比普通的vue项目,多了一套ui库、页面路由框架、和uni对象(即常见API封装)
- 在App端,uni-app的runtime更复杂,可以先简单理解为DCloud也有一套小程序引擎,打包app时将开发者的代码和DCloud的小程序打包成了apk或ipa。当然,事实上DCloud确实有小程序引擎产品,供原生应用实现小程序化,详见
uni-app runtime包括3部分:基础框架、组件、API。DCloud还提供了插件市场,大多数用得着的组件和API都已经有现成的插件。
- 基础框架:
- 包括语法、数据驱动、全局文件、应用管理、页面管理、js引擎、渲染和排版引擎等
- 在web和小程序上,不需要uni-app提供js引擎和排版引擎,直接使用浏览器和小程序的即可。但app上需要uni-app提供
- App的js引擎:App-Android上,uni-app的js引擎是v8,App-iOS是jscore
- App的渲染引擎:同时提供了2套渲染引擎,
.vue
页面文件由webview渲染,原理与小程序相同;.nvue
页面文件由原生渲染,原理与react native相同。开发者可以根据需要自主选择渲染引擎。
- 组件:
- runtime中包括的组件只有基础组件,如
<view>
、<button>
等。扩展组件不包含在uni-app的runtime中,而是下载到用户的项目代码中。(这些组件都是vue组件) - 为了降低开发者的学习成本,uni-app的内置基础组件命名规范与小程序基本相同。
- 这几十个组件不管在哪个平台,已被处理为均有一致表现。
- 在小程序端,uni-app基础组件会直接转义为小程序自己的内置组件。在小程序的runtime中不占体积。
- 在web和android、iOS端,这几十个组件都在uni-app的runtime中,会占用一定体积,相当于内置了一套ui库。
- 组件的扩展:
- 有了几十个基础组件,大多数扩展组件也都是基于这些基础组件封装的。比如官方提供的扩展ui库
uni ui
。 - 在web平台,for web的各种ui库(如elementUI)也可以使用,但这些库由于操作了dom,无法跨端在app和小程序中使用。
- 在App平台,uni-app也支持使用原生编程语言来自行扩展原生组件,比如原生的地图、ar等。
- uni-app同时支持将微信自定义组件运行到微信小程序、web、app这3个平台。注意微信自定义组件不是vue组件。
- 有了几十个基础组件,大多数扩展组件也都是基于这些基础组件封装的。比如官方提供的扩展ui库
- runtime中包括的组件只有基础组件,如
- API:
- uni-app runtime内置了大量常见的、跨端的 API,比如联网(uni.request)、读取存储(uni.getStorage)
- 同时uni-app不限制各端原生平台的API调用。开发者可以在uni-app框架中无限制的调用该平台所有能使用的API。即,在小程序平台,小程序的所有API都可以使用;在web平台,浏览器的所有API都可使用;在iOS和Android平台,os的所有API都可以使用。
- 也就是说,使用uni-app的标准API,可以跨端使用。但对于不跨端的部分,仍可以调用该端的专有API。由于常见的API都已经被封装内置,所以日常开发时,开发者只需关注uni标准API,当需要调用特色端能力时在条件编译里编写特色API调用代码。
- ext API:web和app的runtime体积不小,如果把小程序的所有API等内置进去会让开发者的最终应用体积变大。所以有部分不常用的API被剥离为ext API。虽然仍然是uni.开头,但需要单独下载插件到项目下
- 小程序平台:uni对象会转为小程序的自有对象,比如在微信小程序平台,编写uni.request等同于wx.request。那么所有wx.的API都可以这样使用。
- web平台:window、dom等浏览器专用API仍可以使用
- app平台:除了uni.的API,还可以使用plus.的API、Native.js,以及通过uts编写原生插件,或者使用java和objectC编写原生插件。这些原生插件调用os的API并封装给js使用。
- 由于历史沿革,DCloud在开发app时有:5+App、wap2app、uni-app等3种模式。这3种方式的runtime在底层能力上是公用的,所有uni-app可以调用5+(也就是plus.xxx)的API。虽然都可以使用5+的系统能力,但uni-app的逻辑层运行在js层,渲染层是webview和原生nvue双选。而5+不区分逻辑层和渲染层,全部运行在webview里,在性能上5+不及uni-app。
逻辑层和渲染层分离
在web平台,逻辑层(js)和渲染层(html、css),都运行在统一的webview里。
但在小程序和app端,逻辑层和渲染层被分离了。
分离的核心原因是性能。过去很多开发者吐槽基于webview的app性能不佳,很大原因是js运算和界面渲染抢资源导致的卡顿。
不管小程序还是app,逻辑层都独立为了单独的js引擎,渲染层仍然是webview(app上也支持纯原生渲染)。
所以注意小程序和app的逻辑层都不支持浏览器专用的window、dom等API。app只能在渲染层操作window、dom,即renderjs。
关于逻辑层和渲染层分离带来的注意事项,请详读
uni-app 工程
一个 uni-app 工程,就是一个 Vue 项目,你可以通过 HBuilderX 或 cli 方式快速创建 uni-app 工程,详见:快速上手。
一个uni-app工程,默认包含如下目录及文件:
┌─uniCloud 云空间目录
│─components 符合vue组件规范的 uni-app 组件目录
│ └─comp-a.vue 可复用的a组件
├─utssdk 存放uts文件
├─pages 业务页面文件存放的目录
│ ├─index
│ │ └─index.vue index页面
│ └─list
│ └─list.vue list页面
├─static 存放应用引用的本地静态资源(如图片、视频等)的目录
├─uni_modules 存放uni_module 详见
├─platforms 存放各平台专用页面的目录,详见
├─nativeplugins App原生语言插件 详见
├─nativeResources App端原生资源目录
│ ├─android Android原生资源目录 详见
│ └─ios iOS原生资源目录 详见
├─hybrid App端存放本地html文件的目录,详见
├─wxcomponents 存放小程序组件的目录,详见
├─unpackage 非工程代码,一般存放运行或发行的编译结果
├─main.js Vue 初始化入口文件
├─App.vue 应用配置,用来配置App全局样式以及 监听 应用生命周期
├─pages.json 配置页面路由、导航条、选项卡(tabbar) 等页面类信息,详见
├─manifest.json 配置应用名称、appid、logo、版本等打包信息,详见
├─AndroidManifest.xml Android原生应用清单文件 详见
├─Info.plist iOS原生应用配置文件 详见
└─uni.scss 内置的常用样式变量
提示:HbuilderX 1.9.0+ 支持在根目录创建 ext.json
、sitemap.json
等小程序需要的文件。
static 目录
- 为什么需要static这样的目录?
uni-app 编译器根据pages.json扫描需要编译的页面,并根据页面引入的js、css合并打包文件。
对于本地的图片、字体、视频、文件等资源,如果可以直接识别,那么也会把这些资源文件打包进去,但如果这些资源以变量的方式引用, 比如:<image :src="url"></image>
,甚至可能有更复杂的函数计算,此时编译器无法分析。那么有了static目录,编译器就会把这个目录整体复制到最终编译包内。这样只要运行时确实能获取到这个图片,就可以显示。
当然这也带来一个注意事项,如果static里有一些没有使用的废文件,也会被打包到编译包里,造成体积变大。
另外注意,static目录支持特殊的平台子目录,比如web、app、mp-weixin等,这些目录存放专有平台的文件,这些平台的文件在打包其他平台时不会被包含。详见条件编译
非
static
目录下的文件(vue组件、js、css 等)只有被引用时,才会被打包编译。
css
、less/scss
等资源不要放在static
目录下,建议这些公用的资源放在自建的common
目录下。
- static目录和App原生资源目录有关系吗?
uni-app支持App原生资源目录nativeResources,下面有assets、res等目录,详见。但和static目录没有关系。
static目录下的文件,在app第一次启动时,解压到了app的外部存储目录(external-path)。(uni-app x 从3.99+不再解压)
所以注意控制static目录的大小,太大的static目录和太多文件,会造成App安装后第一次启动变慢。
开发:小程序、app
首先开发者需先下载安装 HBuilder X ( https://hx.dcloud.net.cn/Tutorial/install/windows )
微信小程序会用到 "微信开发者工具" ( 指南、框架、组件、API、平台能力、服务端、工具 :https://developers.weixin.qq.com/miniprogram/dev/reference/ )。第一次运行需要在 HBuilderX 中配置微信开发者工具的安装路径才能调用。还要配置端口。
使用 HBuilder X 新建项目,选择 uni-app,输入工程名,如:shop,点击创建,即可成功创建 uni-app
新建项目的目录说明
有了初始框架模板之后,运行到浏览器 chrome 就可以打开初始 app hello uni-app
新建页面。
然后在 pages.json 中配置 path 路径,一般新建页面之后会自动添加路径
然后配置全局样式,配置tabbar
运行 到 "h5、微信小程序、app"
访问本机 http://localhost:8081/#/ 网页查看app
运行微信小程序
页面内容直接调用 python 开发好的接口来实现轮播图、商品列表、社区图片等功能。
使用 vs code 开发 uni-app
vscode安装插件、ts校验、允许json文件注释:https://blog.csdn.net/weixin_44171757/article/details/137749176
为什么使用 vs code
- HbuilderX 对 TS 类型支持不完善
- vs code 对 TS 类型友好,也是最好用的编辑器
安装支持 uni-app 开发的插件。可以把下载次数比较多的全部安装,也没几个
uni-create-view 快速创建 uni-app 页面
uni-helper uni-app 代码提示
uniapp小程序扩展 鼠标悬停查看文档
如果嫌 vs code 默认图标不好看,也可以搜索 icon 插件。这里选择 JetBrains Icon Theme
ts 类型检查(校验)、类型提示
配置 tsconfig.json,types中加入,添加 vueCompilerOptions
"types": [
"@dcloudio/types", // uni-app API 类型
"miniprogram-api-typings", // 原生微信小程序类型
"@uni-helper/uni-app-types" // uni-app 组件类型
]
},
// vue 编译器类型,校验标签类型
"vueCompilerOptions": {
// 原配置 `experimentalRuntimeMode` 现调整为 `nativeTags`
"nativeTags": ["block", "component", "template", "slot"], // [!code ++]
"experimentalRuntimeMode": "runtime-uni-app" // [!code --]
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"]
安装:pnpm i -D @uni-helper/uni-ui-types,添加类型声明的包
json 文件中注释问题:uni-app 允许 json文件中进行注释,但是 vs code 默认不允许注释,可以在设置中设置文件关联,让 vs code 允许注释。
uni-app 中只有 manifest.json、pages.json 这两个文件允许注释。
运行、调试
- 运行,指将项目运行起来,可以一边修改代码、一边立即看到修改结果,同时可以打log日志(console.log)。
- 而调试,也称之为
debug
,在运行的基础之上,进一步可以打断点、单步跟踪、看堆栈信息。
uni-app可以用cli项目的npm命令运行,如果使用cli项目,在非HBuilder环境下运行uni-app,那就执行普通的 npm run dev:%platform%
命令即可,使用外部工具运行。详见
也可以使用 uni-app 的专用开发工具HBuilder,可以更好的开发uni-app。HBuilder为uni-app提供了内置的web浏览器、web端调试环境、App的真机运行环境、App调试环境、uniCloud运行环境、uniCloud调试环境。
运行、调试
在HBuilder中,有顶部菜单、toolbar运行按钮、快捷键三种运行入口。
方法 1:顶部运行菜单
方法 2:toolbar工具栏上的运行按钮
toolbar 的运行按钮点击后会展开一个菜单。这个菜单可配置,通过`自定义菜单`将不常用的运行项目折叠起来。
方法 3:快捷键。
运行快捷键是【Ctrl+r】弹出的菜单还支持键盘快捷选择:按回车可以选中菜单的第一项;按数字可以快捷选中菜单项开头数字对应的菜单项。如果你不能看到相关菜单,那么HBuilder当前打开的文件可能不是uni-app项目下的文件。
调试入口
uni-app一般是先运行后调试。debug的入口在运行之后的控制台上。
运行后的控制台,右上角会有一个红色虫子图标或调试的checkbox。
线上平台排错
应用上线后,各种用户环境下可能会有报错,需要开发者统计和分析。但三方统计系统(如友盟、阿拉丁、百度),对运行端的报错采集,提示的是uni-app编译器编译后的代码报错的行数,相当于乱码,无法告知开发者是uni-app的vue或js的哪一行代码报错。
为了解决这个问题,DCloud提供了uni统计的sourceMap功能,在uni统计后台可以清晰的看到报错的环境和准确的报错代码,是uni-app编译前的vue或js的具体信息。详见
web、App、小程序、uni-vue-devtools 调试
工程化
uni-app
项目支持 uni cli
和 HBuilderX cli
两种脚手架工具:
uni cli
:面向非HBuilderX的用户(如习惯使用vscode/webstorm的开发者),提供创建项目、编译发行等能力;在App平台,仅支持生成离线打包的wgt资源包,不支持云端打包生成apk/ipa;若需云端打包,依然需要安装HBuilderX,使用HBuilderX cli
;HBuilderX cli
:面向HBuilderX用户的自动化工具,提供uni-app
项目的持续集成能力;支持通过HBuilderX cli
进行web打包、小程序打包、App云端打包、部署uniCloud等;但注意HBuilderX暂不支持linux平台。另外注意HBuilderX cli
不基于npm,它是HBuilderX安装目录下的cli.exe
。
提供有完整的cli
脚手架,可以通过 vue-cli
创建、运行、发行 uni-app
项目。
uni cli
HBuilderX cli
通过 cli 命令行操作 HBuilderX 进行启动、打包、登录等。详情参考:HBuilderX 文档
高效开发技巧
为提升开发效率,HBuilderX将 uni-app
常用代码封装成了以 u
开头的代码块,如在 template
标签内输入 ulist
回车,会自动生成如下代码:
<uni-list>
<uni-list-item title="" note=""></uni-list-item>
<uni-list-item title="" note=""></uni-list-item>
</uni-list>
注意:需确保uni-list
组件已保存在项目的components
目录下。比较简单的方式,是新建项目时,选uni-ui
项目模板,在里面即可随便敲所有u开头的代码块。如果你的项目不是uni-ui
项目模板,那么你需要去插件市场手动把uni ui组件下载到工程里。
代码块分为Tag
代码块、JS
代码块,如在 script
标签内输入 uShowToast
回车,会自动生成如下代码:
uni.showToast({
title: '',
mask: false,
duration: 1500
});
uni-app
已支持代码块见下方列表。
Tag 代码块
- uButton
- uCheckbox
- uGrid:宫格,需引用uni ui
- uList:列表,需引用uni ui
- uListMedia
- uRadio
- uSwiper
- ......
几乎各种组件不管是内置组件还是uni-ui
的组件,均已封装为代码块;使用HBuilderX
打开uni-app
项目中的.vue
文件,在template
区域敲u
,代码助手会提示所有可见代码块列表。
你也可以在HBuilderX菜单-工具-代码块设置-vue代码块的左侧列表查阅所有已支持的代码块。
除组件外,其他常用代码块包括:
- viewfor:生成一段带有v-for循环结构的视图代码块
- vbase:生成一段基本的vue代码结构
JS 代码块
uni api代码块
- uRequest
- uGetLocation
- uShowToast
- uShowLoading
- uHideLoading
- uShowModal
- uShowActionSheet
- uNavigateTo
- uNavigateBack
- uRedirectTo
- uStartPullDownRefresh
- uStopPullDownRefresh
- uLogin
- uShare
- uPay
- ......
几乎各种常用js api,均已封装为代码块,在HBuilderX的js代码中敲u,代码助手会提示所有可见列表。也可在HBuilderX菜单-工具-代码块设置-js代码块的左侧列表查阅所有。
vue js代码块
- vImport:导入文件
- ed:export default
- vData:输出 data(){return{}}
- vMethod:输出 methods:{}
- vComponents:输出 components: {}
其他常用 js 代码块
- iff:简单if
- forr:for循环结构体
- fori:for循环结构体并包含i
- funn:函数
- funa:匿名函数
- rt:return true
- clog:输出:"console.log()"
- clogvar:增强的日志输出,可同时把变量的名字打印出来
- varcw:输出:"var currentWebview = this.$scope.page.$getAppWebview()"
- ifios:iOS的平台判断
- ifAndroid:Android的平台判断
预置代码块不满足需求时可以自定义代码块,参考:https://ask.dcloud.net.cn/article/35924
HBuilderx 快捷键
HBuilderx快捷键大全(2023版)
设置 双击 打开 目录:菜单【工具】--->【设置】--->【常用配置】
项目管理器
重命名文件(焦点在项目管理器中) f2
复制文件(焦点在项目管理器中) ctrl + c
粘贴文件(焦点在项目管理器中) ctrl + v
删除文件到回收站(焦点在项目管理器中) delete
标签卡
新建标签卡(默认 md) ctrl + t
关闭当前标签卡 ctrl + w
关闭当前标签卡 ctrl + f4
关闭所有标签卡 ctrl + shift + w
关闭其他文件 ctrl + q
显示左边的标签卡 ctrl + PgUp
显示右边的标签卡 ctrl + PgDown
重开已关闭标签卡 ctrl + shift + t
切换最近的标签卡 ctrl + tab
切换到第 1 个标签卡 alt + 1
切换到第 2 个标签卡 alt + 2
切换到第 3 个标签卡 alt + 3
切换到第 4 个标签卡 alt + 4
切换到第 5 个标签卡 alt + 5
切换到第 6 个标签卡 alt + 6
切换到第 7 个标签卡 alt + 7
切换到第 8 个标签卡 alt + 8
切换到第 9 个标签卡 alt + 9
切换到最末尾的标签卡 alt + 0
往左移动一个标签卡 ctrl + shift + PgUp
往右移动一个标签卡 ctrl + shift + PgDown
文件
新建 ctrl + n
打开外部文件 ctrl + o
打开收藏菜单 alt + shift + f
保存 ctrl + s
另存为 ctrl + shift + s
全部保存 ctrl + alt + s
行操作
向下插入行 ctrl + enter
向下插入行 ctrl + return
向上插入行 ctrl + shift + enter
向上插入行 ctrl + shift + return
反回车,即把光标前内容移到下一行 shift + enter
反回车,即把光标前内容移到下一行 shift + return
上移一行 ctrl + up
下移一行 ctrl + down
删除
向左删除 backspace
向右删除 delete
向左删除词 ctrl + backspace
向右删除词 ctrl + delete
删到行首 shift + backspace
删到行尾 shift + delete
删除行 ctrl + d
列表符操作
插入 - 无序列表符 ctrl + alt + -
插入 * 无序列表符 ctrl + alt + 8
插入 + 无序列表符 ctrl + alt + =
插入>引用列表符 ctrl + alt + shift + .
插入有序列表符 ctrl + alt + 1
插入任务列表符 ctrl + alt + [
插入已完成任务列表符 ctrl + alt + ]
剪贴板
复制 ctrl + c
复制文件路径 ctrl + shift + c
重复插入选区或当前行 ctrl + insert
重复插入选区或当前行(备份用于没有 insert 键的键盘) ctrl + shift + r
剪切 ctrl + x
粘贴 ctrl + v
粘贴为 HTML ctrl + shift + v
从历史粘贴板粘贴(注意解除 evernote 的快捷键占用) ctrl + alt + v
交换字符、选区或行。2 个选区或 2 行是彼此交换;不是 2 个选区时是交换光标前后的字母 ctrl + shift + x
撤销
撤销 ctrl + z
重做 ctrl + y、ctrl + shift + z
撤销一个新光标或选区 alt +shift + z
语言
格式化 ctrl + k
格式化(兼容老版 HBuilder 快捷键,注意解除搜狗输入法全局快捷键) ctrl + shift + f
合并行(反格式化) ctrl + shift + k
合并行(兼容老版 HBuilder 快捷键) ctrl + alt + j
注释/反注释 ctrl + /
块注释 ctrl + shift + /
注释菜单 (含条件编译注释) ctrl + alt + /
包围
包围 ctrl + ]
反包围 ctrl + shift + ]
加粗(html、md 生效) ctrl + b
全部字母大写 alt + shift + u
全部字母小写 alt + shift + l
首字母大写 alt + shift + t
激活代码助手 alt + /
激活方法参数提示 alt + shift + /
缩进 tab
反缩进 shift + tab
选择
全选 ctrl + a
向左选字 shift + left
向右选字 shift + right
向上选行 shift + up
向下选行 shift + down
向左选词 ctrl + shift + left
向右选词 ctrl + shift + right
选至软行首(连续按依次切换自动换行的行首、缩进后的行首、真行首) shift + home
选至软行尾(连续按依次切换自动换行的行尾、真行尾) shift + end
选至上一页 shift + PgUp
选至下一页 shift + PgDown
选至文档首 ctrl + shift + home
选至文档尾 ctrl + shift + end
选择当前词或下一个相同词 ctrl + e
选择所有相同词 ctrl + alt + e、alt + f3
跳过当前选择,选中下一个相同词 alt + shift + e
选择相同语法词(注意解除搜狗输入法全局占用) ctrl + shift + e
选择括号内字符。可用双击括号替代 ctrl + [
选择行。也可单击行号或三击行 ctrl + l
选择行 (不含首尾空白字符)。也可双击行尾 ctrl + shift + l
放大选区 ctrl + =
向 2 侧扩大选择 alt + shift + right
由 2 侧向内减少选择 alt + shift + left
向上列选择 ctrl + alt + up
向下列选择 ctrl + alt + down
每个选区前后设置光标 ctrl +
每行行首设置光标 ctrl + shift +
查找
查找文件 ctrl + p
本文档内查找字符串 ctrl + f
目录内查找字符串 ctrl + alt + f
替换 ctrl + h
查找下一个字符串 f3
查找上一个字符串 shift + f3
跳转
光标向左 alt + h、left
光标向下 alt + j、down
光标向上 alt + k、up
光标向右 alt + l、right
光标向左一词 ctrl + left
光标向右一词 ctrl + right
光标向左一个驼峰单词 ctrl + alt + left
光标向右一个驼峰单词 ctrl + alt + right
光标到软行首(连续按依次切换自动换行的行首、缩进后的行首、真行首) home
光标到软行尾(连续按依次切换自动换行的行尾、真行尾) end
光标到上个段落(空行为分割段落) ctrl + alt + PgUp
光标到下个段落(空行为分割段落) ctrl + alt + PgDown
光标到上一页 PgUp
光标到下一页 PgDown
光标到页首 ctrl + home
光标到页尾 ctrl + end
转到定义 alt + d、f12
分栏转到定义 alt + shift + d、shift + f12
跳转到行 ctrl + g
跳转到配对的括号 alt + [
光标后退 alt + left
光标前进 alt + right
设置/取消书签 ctrl + f2
下一个书签(光标在编辑器区域) f2
上一个书签(光标在编辑器区域) shift + f2
清除所有书签 ctrl + shift + f2
下一个验证错误 f4
上一个验证错误 shift + f4
折叠单行 alt + -
展开单行 alt + =
折叠子行 alt + shift + -
展开子行 alt + shift + =
折叠所有行 alt + ctrl + shift + -
展开所有行 alt + ctrl + shift + =
折叠其他区域 alt + shift + o
视图
置焦到编辑器区域 alt + n
置焦到项目管理器 alt + shift + q
显示/隐藏项目管理器 alt + q
显示/隐藏控制台 alt + x
显示/控制台 alt + c
显示/隐藏工具栏 alt + o
显示/隐藏内置浏览器 alt + p
显示/隐藏大纲 alt + w
增大字体【ctrl+ 鼠标滚动向上】 ctrl + shift + =
减小字体【ctrl+ 鼠标滚动向下】 ctrl + shift + -
单栏 alt + shift + 1
左右 2 栏 alt + shift + 2
左右 3 栏 alt + shift + 3
置焦到下一个分栏 alt + .
置焦到上一个分栏 alt + ,
新建 HBuilder 窗体 ctrl + shift + n
多窗口切换快捷键 1 ctrl + f6
多窗口切换快捷键 2 alt + `
运行
运行 ctrl + r
重新运行 ctrl + f5
停止运行 ctrl + shift + f5
鼠标配合快捷键
添加多光标 ctrl + 左键单击
删除多光标 ctrl + 右键单击
添加多选区 ctrl + 左键拖选
如果点击到了智能双击区域比如 if 块,会添加到选区里 ctrl + 左键双击
转到定义/打开链接 alt + 左键单击
分栏转到定义/打开链接 alt + ctrl + 左键单击
列选择 alt + 左键拖选
缩放字体 ctrl + 滚轮
横向滚动 alt + 滚轮
垂直滚动一屏 shift + 滚轮
横向滚动一屏 ctrl + alt + 滚轮
其他高效极客技巧
HBuilderX - 高效极客技巧 :https://ask.dcloud.net.cn/article/13191
组合式、选项式
参考:Vue2 组合式 API 使用文档 和 Vue3 组合式 API 使用文档。
在单文件组件中,组合式 API 通常会与 <script setup>
搭配使用。这个 setup 属性是一个标识,就是告诉 Vue 需要在编译时进行一些处理从而可以更简洁地使用组合式 API。比如,<script setup>
中的导入和顶层变量/函数都能够在模板中直接使用。
页 面
uni-app项目中,一个页面就是一个符合Vue SFC规范
的 vue 文件。
-
在 uni-app js 引擎版中,后缀名是
.vue
文件或.nvue
文件。 这些页面均全平台支持,差异在于当 uni-app 发行到App平台时,.vue
文件会使用webview进行渲染,.nvue
会使用原生进行渲染,详见:nvue原生渲染。
一个页面可以同时存在vue和nvue,在pages.json的路由注册中不包含页面文件名后缀,同一个页面可以对应2个文件名。重名时优先级如下:
在非app平台,先使用vue,忽略nvue
在app平台,使用nvue,忽略vue -
在 uni-app x 中,后缀名是
.uvue
文件
uni-app x 中没有js引擎和webview,不支持和vue页面并存。
uni-app x 在app-android上,每个页面都是一个全屏 activity,不支持透明。
新建 页面
uni-app
中的页面,默认保存在工程根目录下的pages
目录下。
每次新建页面,均需在pages.json
中配置pages
列表;未在pages.json -> pages
中注册的页面,uni-app
会在编译阶段进行忽略。pages.json的完整配置参考:页面配置。
通过HBuilderX开发 uni-app
项目时,在 uni-app
项目上右键“新建页面”,HBuilderX会自动在pages.json
中完成页面注册,开发更方便。
同时,HBuilderX 还内置了常用的页面模板(如图文列表、商品列表等),选择这些模板,可以大幅提升你的开发效率。
新建页面时,可以选择是否创建同名目录
。创建目录的意义在于:
- 如果你的页面较复杂,需要拆分多个附属的js、css、组件等文件,则使用目录归纳比较合适。
- 如果只有一个页面文件,大可不必多放一层目录。
删除 页面
删除页面时,需做两件工作:
- 删除
.vue
文件、.nvue
、.uvue
文件- 删除
pages.json -> pages
列表项中的配置 (如使用HBuilderX删除页面,会在状态栏提醒删除pages.json对应内容,点击后会打开pages.json并定位到相关配置项)
页面 改名
操作和删除页面同理,依次修改文件和
pages.json
。
pages.json
pages.json 是工程的页面管理配置文件,包括:页面路由注册、页面参数配置(原生标题栏、下拉刷新...)、首页tabbar等众多功能。
其篇幅较长,另见 pages.json
设置 应用 首页
pages.json -> pages
配置项中的第一个页面,作为当前工程的首页(启动页)。
{
"pages": [
{
"path": "pages/index/index", //名字叫不叫index无所谓,位置在第一个,就是首页
"style": {
"navigationBarTitleText": "首页" //页面标题
}
},
{
"path": "pages/my",
"style": {
"navigationBarTitleText": "我的"
}
},
]
}
页面构成:template、script、style
uni-app 页面基于 vue 规范。一个页面内,有3个根节点标签:
- 模板组件区
<template>
- 脚本区
<script>
- 样式区
<style>
<template>
<view class="content">
<button @click="buttonClick">{{title}}</button>
</view>
</template>
<script>
export default {
data() {
return {
title: "Hello world", // 定义绑定在页面上的data数据
}
},
onLoad() {
// 页面启动的生命周期,这里编写页面加载时的逻辑
},
methods: {
buttonClick: function () {
console.log("按钮被点了")
},
}
}
</script>
<style>
.content {
width: 750rpx;
background-color: white;
}
</style>
template 模板区
template 中文名为模板
,它类似html的标签。但有2个区别:
- html中
script
和style
是 html 的二级节点。但在 vue 文件中,template
、script
、style
这3个是平级关系。 - html 中写的是 web 标签,但 vue 的
template
中写的全都是 vue 组件,每个组件支持属性、事件、 vue 指令,还可以绑定 vue 的 data 数据。
在vue2中,template
的二级节点只能有一个节点,一般是在一个根 view
下继续写页面组件(如上示例代码)。
但在vue3中,template可以有多个二级节点,省去一个层级,如下:
<template>
<view>
<text>标题</text>
</view>
<scroll-view>
</scroll-view>
</template>
可以在 manifest
中切换使用 Vue2 还是 Vue3。注意:uni-app x
中只支持 Vue3。
script 脚本区
script 中编写脚本,可以通过 lang 属性指定脚本语言。
- 在vue和nvue中,默认是js,可以指定ts。
- 在uvue中,仅支持uts,不管script的lang属性写成什么,都按uts编译。
<script lang="ts">
</script>
在vue的选项式(option)规范中,script下包含 export default {}
。除了选项式,还有 组合式 写法。页面级的代码大多写在 export default {}
中。写在里面的代码,会随着页面关闭而关闭。
export default 外的代码
写在 export default {}
外面的代码,一般有几种情况:
- 引入第三方 js/ts 模块
- 引入非 easycom 的组件(一般组件推荐使用easycom,无需导入注册)
- 在 ts/uts 中,对 data 进行类型定义
- 定义作用域更大的变量
<script lang="ts">
const TAB_OFFSET = 1; // 外层静态变量不会跟随页面关闭而回收
import charts from 'charts.ts'; // 导入外部js/ts模块
import swiperPage from 'swiper-page.vue'; //导入非easycom的组件
type GroupType = {
id : number,
title : string
} // 在ts中,为下面data数据的 groupList 定义类型
export default {
components: {
swiperPage
}, // 注册非easycom组件
data() {
return {
groupList: [
{ id: 1, title: "第一组" },
{ id: 2, title: "第二组" },
] as GroupType[], // 为数据groupList定义ts类型
}
},
onLoad() {},
methods: {}
}
</script>
开发者应谨慎编写 export default {}
外面的代码,这里的代码有2个注意事项:
- 影响应用性能。这部分代码在应用启动时执行,而不是页面加载。如果这里的代码写的太复杂,会影响应用启动速度,占用更多内存。
- 不跟随组件、页面关闭而回收。在外层的静态变量不会跟随页面关闭而回收。如果必要你需要手动处理。比如
beforeDestroy
或destroyed
生命周期进行处理。
export default 里的代码
export default {}
里的内容,是页面的主要逻辑代码。包括几部分:
如下页面代码的逻辑是:
- 在data中定义了
title
,初始值是"点我" - 在页面中放置了一个button组件,按钮文字区使用
{{}}
模板写法,里面写title
,把data里的title
绑定到按钮的文字区,即按钮的初始文字是"点我" - 按钮的点击事件
@click
,指向了methods里的一个方法buttonClick
,点击按钮即触发这个方法的执行 - buttonClick方法里通过
this.title
的方式,访问data数据,并重新赋值为"被点了"。由于vue中data和界面是双向绑定,修改data中的title
后,因为按钮文字绑定了title
,会自动更新按钮的文字。
整体效果就是,刚开始按钮文字是"点我",点一下后按钮文字变成了"被点了"
<template>
<view>
<button @click="buttonClick">{{title}}</button>
</view>
</template>
<script>
export default {
data() {
return {
title: "点我", // 定义绑定在页面上的data数据
// 多个data在这里继续定义。逗号分隔
}
},
onLoad() {
// 页面启动的生命周期,这里编写页面加载时的逻辑
},
// 多个页面生命周期监听,在这里继续写。逗号分隔
methods: {
buttonClick: function () {
this.title = "被点了"
},
// 多个方法,在这里继续写。逗号分隔
}
}
</script>
了解data数据需详见
style 样式区
style的写法与web的css基本相同。如果页面是nvue或uvue,使用原生渲染而不是webview渲染,那么它们支持的css是有限的。详见css文档
页面 生命周期
:https://zh.uniapp.dcloud.io/tutorial/page.html#lifecycle
uni-app
页面除支持 Vue 组件生命周期外还支持下方页面生命周期函数,当以组合式 API 使用时,在 Vue2 和 Vue3 中存在一定区别,请分别参考:Vue2 组合式 API 使用文档 和 Vue3 组合式 API 使用文档。
函数名 | 说明 | 平台差异说明 | 最低版本 |
---|---|---|---|
onInit | 监听页面初始化,其参数同 onLoad 参数,为上个页面传递的数据,参数类型为 Object(用于页面传参),触发时机早于 onLoad | 百度小程序 | 3.1.0+ |
onLoad | 监听页面加载,该钩子被调用时,响应式数据、计算属性、方法、侦听器、props、slots 已设置完成,其参数为上个页面传递的数据,参数类型为 Object(用于页面传参),参考示例。 | ||
onShow | 监听页面显示,页面每次出现在屏幕上都触发,包括从下级页面点返回露出当前页面 | ||
onReady | 监听页面初次渲染完成,此时组件已挂载完成,DOM 树($el)已可用,注意如果渲染速度快,会在页面进入动画完成前触发 | ||
onHide | 监听页面隐藏 | ||
onUnload | 监听页面卸载 | ||
onResize | 监听窗口尺寸变化 | App、微信小程序、快手小程序 | |
onPullDownRefresh | 监听用户下拉动作,一般用于下拉刷新,参考示例 | ||
onReachBottom | 页面滚动到底部的事件(不是scroll-view滚到底),常用于下拉下一页数据。具体见下方注意事项 | ||
onTabItemTap | 点击 tab 时触发,参数为Object,具体见下方注意事项 | 微信小程序、QQ小程序、支付宝小程序、百度小程序、H5、App、快手小程序、京东小程序 | |
onShareAppMessage | 用户点击右上角分享 | 微信小程序、QQ小程序、支付宝小程序、抖音小程序、飞书小程序、快手小程序、京东小程序 | |
onPageScroll | 监听页面滚动,参数为Object | nvue不支持 | |
onNavigationBarButtonTap | 监听原生标题栏按钮点击事件,参数为Object | App、H5 | |
onBackPress | 监听页面返回,返回 event = {from:backbutton、 navigateBack} ,backbutton 表示来源是左上角返回按钮或 android 返回键;navigateBack表示来源是 uni.navigateBack;详见 | app、H5、支付宝小程序 | |
onNavigationBarSearchInputChanged | 监听原生标题栏搜索输入框输入内容变化事件 | App、H5 | 1.6.0 |
onNavigationBarSearchInputConfirmed | 监听原生标题栏搜索输入框搜索事件,用户点击软键盘上的“搜索”按钮时触发。 | App、H5 | 1.6.0 |
onNavigationBarSearchInputClicked | 监听原生标题栏搜索输入框点击事件(pages.json 中的 searchInput 配置 disabled 为 true 时才会触发) | App、H5 | 1.6.0 |
onShareTimeline | 监听用户点击右上角转发到朋友圈 | 微信小程序 | 2.8.1+ |
onAddToFavorites | 监听用户点击右上角收藏 | 微信小程序、QQ小程序 | 2.8.1+ |
页面 加载 顺序
- uni-app 框架,首先根据pages.json的配置,创建页面。所以原生导航栏是最快显示的。页面背景色也应该在这里配置。
- 根据页面 template 里的组件,创建dom。这里的dom创建仅包含第一批处理的静态dom。对于通过js/uts更新data然后通过v-for再创建的列表数据,不在第一批处理。要注意一个页面静态dom元素过多,会影响页面加载速度。在uni-app x Android版本上,可能会阻碍页面进入的转场动画。 因为此时,页面转场动画还没有启动。
- 触发 onLoad。此时页面还未显示,没有开始进入的转场动画,页面dom还不存在。所以这里不能直接操作dom(可以修改data,因为vue框架会等待dom准备后再更新界面);在 app-uvue 中获取当前的activity拿到的是老页面的activity,只能通过页面栈获取activity。onLoad比较适合的操作是:接受上页的参数,联网取数据,更新 data。手机都是多核的,uni.request或云开发联网,在子线程运行,不会干扰UI线程的入场动画,并行处理可以更快的拿到数据、渲染界面。但 onLoad里不适合进行大量同步耗时运算,因为此时转场动画还没开始。尤其uni-app x 在 Android上,onLoad里的代码(除了联网和加载图片)默认是在UI线程运行的,大量同步耗时计算很容易卡住页面动画不启动。除非开发者显式指定在其他线程运行。
- 转场动画开始。新页面开始进入的转场动画,默认耗时300ms,可以在路由API中调节时长。
- 页面 onReady。第2步创建dom是虚拟dom,dom创建后需要经历一段时间,UI层才能完成了页面上真实元素的创建,即触发了onReady。onReady后,页面元素就可以自由操作了,比如ref获取节点。同时首批界面也渲染了。注意:onReady和转场动画开始、结束之间,没有必然的先后顺序,完全取决于dom的数量和复杂度。
如果元素排版和渲染够快,转场动画刚开始就渲染好了;
大多情况下,转场动画走几格就看到了首批渲染内容;
如果元素排版和渲染过慢,转场动画结束都没有内容,就会造成白屏。
联网进程从onLoad起就在异步获取数据更新data,如果服务器速度够快,第二批数据也可能在转场动画结束前渲染。 - 转场动画结束。再次强调,5和6的先后顺序不一定,取决于首批dom渲染的速度。
了解了页面加载时序原理,就知道如何避免页面加载常见的问题:
- 优化白屏的方法:页面dom太多,注意有的组件写的不好,会拖累整体页面。uni-app x 里减少dom数量的策略,详见 。联网不要在onReady里,那样太慢了,在onLoad里早点联网。在pages.json里配置原生导航栏和背景色。有的页面template内容非常少,整页就是一个需要联网加载的列表,这会造成虽然首批dom飞快渲染了,但页面其实还是白的,联网后才能显示字和图。 此时需要在template里做一些简单占位组件,比如loading组件、骨架屏,让本地先显示一些内容。
- 卡住动画不启动的原因:页面dom太多,注意有的组件写的不好,会拖累整体页面。uni-app x 里减少dom数量的策略,详见 。onLoad里执行了耗时的同步计算
组件 生命周期
应用 生命周期
App.vue/uvue
是uni-app的主组件。uni-app js引擎版是app.vue。uni-app x是app.uvue。以下出现的app.vue
一般泛指包含了app.uvue
所有页面都是在App.vue
下进行切换的,是应用入口文件。但App.vue
本身不是页面,这里不能编写视图元素,也就是没有<template>
。
这个文件的作用包括:监听应用生命周期、配置全局样式、配置全局的存储globalData
应用生命周期仅可在App.vue
中监听,在页面监听无效。
uni-app
支持如下应用生命周期函数:
函数名 | 说明 | 平台兼容 |
---|---|---|
onLaunch | 当uni-app 初始化完成时触发(全局只触发一次),参数为应用启动参数,同 uni.getLaunchOptionsSync 的返回值 | |
onShow | 当 uni-app 启动,或从后台进入前台显示,参数为应用启动参数,同 uni.getLaunchOptionsSync 的返回值 | |
onHide | 当 uni-app 从前台进入后台 | |
onError | 当 uni-app 报错时触发 | app-uvue 不支持 |
onUniNViewMessage | 对 nvue 页面发送的数据进行监听,可参考 nvue 向 vue 通讯 | app-uvue 不支持 |
onUnhandledRejection | 对未处理的 Promise 拒绝事件监听函数(2.8.1+ app-uvue 暂不支持) | app-uvue 不支持 |
onPageNotFound | 页面不存在监听函数 | app-uvue 不支持 |
onThemeChange | 监听系统主题变化 | app-uvue 不支持 |
onLastPageBackPress | 最后一个页面按下Android back键,常用于自定义退出 | app-uvue-android 3.9+ |
onExit | 监听应用退出 | app-uvue-android 3.9+ |
示例
<script>
// 只能在App.vue里监听应用的生命周期
export default {
onLaunch: function(options) {
console.log('App Launch')
console.log('应用启动路径:', options.path)
},
onShow: function(options) {
console.log('App Show')
console.log('应用启动路径:', options.path)
},
onHide: function() {
console.log('App Hide')
}
}
</script>
注意
- 应用生命周期仅可在
App.vue
中监听,在其它页面监听无效。 - 以组合式 API 使用时,在 Vue2 和 Vue3 中存在一定区别,请分别参考:Vue2 组合式 API 使用文档 和 Vue3 组合式 API 使用文档。
- 应用启动参数,可以在API
uni.getLaunchOptionsSync
获取,详见 - onlaunch里进行页面跳转,如遇白屏报错,请参考onlaunch生命周期内navigateto跳转页面注意 - DCloud问答
App.vue
不能写模板- onPageNotFound 页面实际上已经打开了(比如通过分享卡片、小程序码)且发现页面不存在,才会触发,api 跳转不存在的页面不会触发(如 uni.navigateTo)
Vue3 页面、组件
onShow 和 onHide
注意页面显示,是一个会重复触发的事件。
a页面刚进入时,会触发a页面的onShow。
当a跳转到b页面时,a会触发onHide,而b会触发onShow。
但当b被关闭时,b会触发onUnload,此时a再次显示出现,会再次触发onShow。
在tabbar页面(指pages.json里配置的tabbar),不同tab页面互相切换时,会触发各自的onShow和onHide。
onInit
- 仅百度小程序基础库 3.260 以上支持 onInit 生命周期
- 其他版本或平台可以同时使用 onLoad 生命周期进行兼容,注意避免重复执行相同逻辑
- 不依赖页面传参的逻辑可以直接使用 created 生命周期替代
onLoad
uni-app x android
平台,如需获取 activity 实例,此时当前页面的activity 实例
并未创建完成,会获取到上一个页面的activity 实例
(首页会获取应用默认的activity 实例
)。如需获取当前页面的activity 实例
,应在onShow
或onReady
生命周期中获取。
onReachBottom
可在pages.json里定义具体页面底部的触发距离onReachBottomDistance,
比如设为50,那么滚动页面到距离底部50px时,就会触发onReachBottom事件。
如使用scroll-view导致页面没有滚动,则触底事件不会被触发。scroll-view滚动到底部的事件请参考scroll-view的文档。
onPageScroll
属性 | 类型 | 说明 |
---|---|---|
scrollTop | Number | 页面在垂直方向已滚动的距离(单位px) |
onPageScroll : function(e) { //nvue暂不支持滚动监听,可用bindingx代替
console.log("滚动距离为:" + e.scrollTop);
},
onPageScroll
里不要写交互复杂的js,比如频繁修改页面。因为这个生命周期是在渲染层触发的,在非h5端,js是在逻辑层执行的,两层之间通信是有损耗的。如果在滚动过程中,频发触发两层之间的数据交换,可能会造成卡顿。(uvue在app端无此限制)- 在webview渲染时,比如app-vue、微信小程序、H5中,也可以使用wxs监听滚动,参考;在app-nvue中,可以使用bindingx监听滚动,参考。
- 如果想实现滚动时标题栏透明渐变,在App和H5下,可在pages.json中配置titleNView下的type为transparent,参考。(uni-app x不支持)
- 如果需要滚动吸顶固定某些元素,推荐使用css的粘性布局,参考插件市场。插件市场也有其他js实现的吸顶插件,但性能不佳,需要时可自行搜索。(uni-app x可自由在uts中设置固定位置)
onBackPress
属性 | 类型 | 说明 |
---|---|---|
from | String | 触发返回行为的来源:'backbutton'——左上角导航栏按钮及安卓返回键;'navigateBack'——uni.navigateBack() 方法。支付宝小程序端不支持返回此字段 |
export default {
onBackPress(options) {
console.log('from:' + options.from)
}
}
onBackPress
上不可使用async
,会导致无法阻止默认返回- 支付宝小程序只有真机可以监听到非
navigateBack
引发的返回事件(使用小程序开发工具时不会触发onBackPress
),不可以阻止默认返回行为
详细说明及使用:onBackPress 详解
onTabItemTap
属性 | 类型 | 说明 |
---|---|---|
index | Number | 被点击tabItem的序号,从0开始 |
pagePath | String | 被点击tabItem的页面路径 |
text | String | 被点击tabItem的按钮文字 |
onTabItemTap : function(e) {
console.log(e);
// e的返回格式为json对象: {"index":0,"text":"首页","pagePath":"pages/index/index"}
},
- onTabItemTap常用于点击当前tabitem,滚动或刷新当前页面。如果是点击不同的tabitem,一定会触发页面切换。
- 如果想在App端实现点击某个tabitem不跳转页面,不能使用onTabItemTap,可以使用plus.nativeObj.view放一个区块盖住原先的tabitem,并拦截点击事件。
- 支付宝小程序平台onTabItemTap表现为点击非当前tabitem后触发,因此不能用于实现点击返回顶部这种操作
属性 | 类型 | 说明 |
---|---|---|
index | Number | 原生标题栏按钮数组的下标 |
onNavigationBarButtonTap : function (e) {
console.log(e);
// e的返回格式为json对象:{"text":"测试","index":0}
}
注意:nvue 页面weex编译模式支持的生命周期同weex,具体参考:weex生命周期介绍
组件 生命周期
uni-app
组件支持的生命周期,与vue标准组件的生命周期相同。这里没有页面级的onLoad等生命周期:
函数名 | 说明 | 平台差异说明 | 最低版本 |
---|---|---|---|
beforeCreate | 在实例初始化之前被调用。详见 | ||
created | 在实例创建完成后被立即调用。详见 | ||
beforeMount | 在挂载开始之前被调用。详见 | ||
mounted | 挂载到实例上去之后调用。详见 注意:此处并不能确定子组件被全部挂载,如果需要子组件完全挂载之后在执行操作可以使用$nextTick Vue官方文档 | ||
beforeUpdate | 数据更新时调用,发生在虚拟 DOM 打补丁之前。详见 | 仅H5平台支持 | |
updated | 由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。详见 | 仅H5平台支持 | |
beforeDestroy | 实例销毁之前调用。在这一步,实例仍然完全可用。详见 | ||
destroyed | Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。详见 |
页面 调用接口:getApp()、getCurrentPages()
getApp()
getApp()
函数用于获取当前应用实例,一般用于获取 globalData。也可通过应用实例调用App.vue methods
中定义的方法。
const app = getApp()
console.log(app.globalData)
app.doSomething() // 调用 App.vue methods 中的 doSomething 方法
注意:
- 不要在定义于
App()
内的函数中,或调用App
前调用getApp()
,可以通过this.$scope
获取对应的app实例 - 通过
getApp()
获取实例之后,不要私自调用生命周期函数。 - 当在首页
nvue
中使用getApp()
不一定可以获取真正的App
对象。对此提供了const app = getApp({allowDefault: true})
用来获取原始的App
对象,可以用来在首页对globalData
等初始化
getCurrentPages()
getCurrentPages()
函数用于获取当前页面栈的实例,以数组形式按栈的顺序给出,数组中的元素为页面实例,第一个元素为首页,最后一个元素为当前页面。
每个页面实例的方法属性列表:
方法 | 描述 | 平台说明 |
---|---|---|
page.$getAppWebview() | 获取当前页面的webview对象实例 | App |
page.route | 获取当前页面的路由 |
注意:getCurrentPages()
仅用于展示页面栈的情况,请勿修改页面栈,以免造成页面状态错误。
页面关闭时,对应页面实例会在页面栈中删除。
提示:
navigateTo
,redirectTo
只能打开非 tabBar 页面。switchTab
只能打开tabBar
页面。- `reLaunch`` 可以打开任意页面。
- 页面底部的
tabBar
由页面决定,即只要是定义为tabBar
的页面,底部都有tabBar
。 - 不能在首页
onReady
之前进行页面跳转。
$getAppWebview()
uni-app
在 getCurrentPages()
获得的页面里内置了一个方法 $getAppWebview()
可以得到当前webview的对象实例,从而实现对 webview 更强大的控制。在 html5Plus 中,plus.webview具有强大的控制能力,可参考:WebviewObject。
但uni-app
框架有自己的窗口管理机制,请不要自己创建和销毁webview,如有需求覆盖子窗体上去,请使用原生子窗体subNvue。
注意:此方法仅 App 支持
示例:获取当前页面 webview 的对象实例
export default {
data() {
return {
title: 'Hello'
}
},
onLoad() {
// #ifdef APP-PLUS
const currentWebview = this.$scope.$getAppWebview(); //此对象相当于html5plus里的plus.webview.currentWebview()。在uni-app里vue页面直接使用plus.webview.currentWebview()无效
currentWebview.setBounce({position:{top:'100px'},changeoffset:{top:'0px'}}); //动态重设bounce效果
// #endif
}
}
获取指定页面 webview 的对象实例。getCurrentPages()
可以得到所有页面对象,然后根据数组,可以取指定的页面webview对象
var pages = getCurrentPages();
var page = pages[pages.length - 1];
// #ifdef APP-PLUS
var currentWebview = page.$getAppWebview();
console.log(currentWebview.id);//获得当前webview的id
console.log(currentWebview.isVisible());//查询当前webview是否可见
);
// #endif
uni-app自带的web-view组件,是页面中新插入的一个子webview。获取该对象的方法见:https://ask.dcloud.net.cn/article/35036
页面 通讯
- uni.$emit(eventName,OBJECT):触发全局的自定义事件。附加参数都会传给监听器回调。
属性 | 类型 | 描述 |
---|---|---|
eventName | String | 事件名 |
OBJECT | Object | 触发事件携带的附加参数 |
uni.$emit('update',{msg:'页面更新'})
- uni.$on(eventName,callback):监听全局的自定义事件。事件可以由 uni.$emit 触发,回调函数会接收所有传入事件触发函数的额外参数。
属性 | 类型 | 描述 |
---|---|---|
eventName | String | 事件名 |
callback | Function | 事件的回调函数 |
uni.$on('update',function(data){
console.log('监听到事件来自 update ,携带参数 msg 为:' + data.msg);
})
- uni.$once(eventName,callback):监听全局的自定义事件。事件可以由 uni.$emit 触发,但是只触发一次,在第一次触发之后移除监听器。
属性 | 类型 | 描述 |
---|---|---|
eventName | String | 事件名 |
callback | Function | 事件的回调函数 |
uni.$once('update',function(data){
console.log('监听到事件来自 update ,携带参数 msg 为:' + data.msg);
})
- uni.$off([eventName, callback]):移除全局自定义事件监听器。
属性 | 类型 | 描述 |
---|---|---|
eventName | Array<String> | 事件名 |
callback | Function | 事件的回调函数 |
提示:
- 如果没有提供参数,则移除所有的事件监听器;
- 如果只提供了事件,则移除该事件所有的监听器;
- 如果同时提供了事件与回调,则只移除这个回调的监听器;
- 提供的回调必须跟$on的回调为同一个才能移除这个回调的监听器;
示例:$emit
、$on
、$off
常用于跨页面、跨组件通讯,这里为了方便演示放在同一个页面
<template>
<view class="content">
<view class="data">
<text>{{val}}</text>
</view>
<button type="primary" @click="comunicationOff">结束监听</button>
</view>
</template>
<script>
export default {
data() {
return {
val: 0
}
},
onLoad() {
setInterval(()=>{
uni.$emit('add', {
data: 2
})
},1000)
uni.$on('add', this.add)
},
methods: {
comunicationOff() {
uni.$off('add', this.add)
},
add(e) {
this.val += e.data
}
}
}
</script>
<style>
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.data {
text-align: center;
line-height: 40px;
margin-top: 40px;
}
button {
width: 200px;
margin: 20px 0;
}
</style>
注意事项
- uni.$emit、 uni.$on 、 uni.$once 、uni.$off 触发的事件都是 App 全局级别的,跨任意组件,页面,nvue,vue 等
- 使用时,注意及时销毁事件监听,比如,页面 onLoad 里边 uni.$on 注册监听,onUnload 里边 uni.$off 移除,或者一次性的事件,直接使用 uni.$once 监听
扩展阅读:
路 由
uni-app
页面路由为框架统一管理,开发者需要在pages.json里配置每个路由页面的路径及页面样式。类似小程序在 app.json 中配置页面路由一样。所以 uni-app
的路由用法与 Vue Router
不同,如仍希望采用 Vue Router
方式管理路由,可在插件市场搜索 Vue-Router
路由跳转,uni-app
有两种页面路由跳转方式:
页面返回时会自动关闭 loading 及 toast, modal 及 actionSheet 不会自动关闭。
页面关闭时,只是销毁了页面实例,未完成的网络请求、计时器等副作用需开发者自行处理。
页面 栈
框架以栈的形式管理当前所有页面, 当发生路由切换的时候,页面栈的表现如下:
路由方式 | 页面栈表现 | 触发时机 |
---|---|---|
初始化 | 新页面入栈 | uni-app 打开的第一个页面 |
打开新页面 | 新页面入栈 | 调用 API uni.navigateTo 、使用组件 <navigator open-type="navigate"/> |
页面重定向 | 当前页面出栈,新页面入栈 | 调用 API uni.redirectTo 、使用组件 <navigator open-type="redirectTo"/> |
页面返回 | 页面不断出栈,直到目标返回页 | 调用 API uni.navigateBack 、使用组件 <navigator open-type="navigateBack"/> 、用户按左上角返回按钮、安卓用户点击物理back按键 |
Tab 切换 | 页面全部出栈,只留下新的 Tab 页面 | 调用 API uni.switchTab 、使用组件 <navigator open-type="switchTab"/> 、用户切换 Tab |
重加载 | 页面全部出栈,只留下新的页面 | 调用 API uni.reLaunch 、使用组件 <navigator open-type="reLaunch"/> |
页面代码规范介绍
uni-app
支持在 template 模板中嵌套 <template/>
和 <block/>
,用来进行 条件渲染 和 列表渲染。
<template/>
和 <block/>
并不是一个组件,它们仅仅是一个包装元素,不会在页面中做任何渲染,只接受控制属性。
<block/>
在不同的平台表现存在一定差异,推荐统一使用 <template/>
。
示例
<template>
<view>
<template v-if="test">
<view>test 为 true 时显示</view>
</template>
<template v-else>
<view>test 为 false 时显示</view>
</template>
</view>
</template>
<template>
<view>
<block v-for="(item,index) in list" :key="index">
<view>{{item}} - {{index}}</view>
</block>
</view>
</template>
nvue、vue 开发区别
基于原生引擎的渲染,虽然还是前端技术栈,但和 web 开发肯定是有区别的。
- nvue 页面控制显隐只可以使用
v-if
不可以使用v-show
- nvue 页面只能使用
flex
布局,不支持其他布局方式。页面开发前,首先想清楚这个页面的纵向内容有什么,哪些是要滚动的,然后每个纵向内容的横轴排布有什么,按 flex 布局设计好界面。 - nvue 页面的布局排列方向默认为竖排(
column
),如需改变布局方向,可以在manifest.json
->app-plus
->nvue
->flex-direction
节点下修改,仅在 uni-app 模式下生效。详情。 - nvue 页面编译为 H5、小程序时,会做一件 css 默认值对齐的工作。因为 weex 渲染引擎只支持 flex,并且默认 flex 方向是垂直。而 H5 和小程序端,使用 web 渲染,默认不是 flex,并且设置
display:flex
后,它的 flex 方向默认是水平而不是垂直的。所以 nvue 编译为 H5、小程序时,会自动把页面默认布局设为 flex、方向为垂直。当然开发者手动设置后会覆盖默认设置。 - 文字内容,必须、只能在
<text>
组件下。不能在<div>
、<view>
的text
区域里直接写文字。否则即使渲染了,也无法绑定 js 里的变量。 - 只有
text
标签可以设置字体大小,字体颜色。 - 布局不能使用百分比、没有媒体查询。
- nvue 切换横竖屏时可能导致样式出现问题,建议有 nvue 的页面锁定手机方向。
- 支持的 css 有限,不过并不影响布局出你需要的界面,
flex
还是非常强大的。详见 - 不支持背景图。但可以使用
image
组件和层级来实现类似 web 中的背景效果。因为原生开发本身也没有 web 这种背景图概念 - css 选择器支持的比较少,只能使用 class 选择器。详见
- nvue 的各组件在安卓端默认是透明的,如果不设置
background-color
,可能会导致出现重影的问题。 class
进行绑定时只支持数组语法。- Android 端在一个页面内使用大量圆角边框会造成性能问题,尤其是多个角的样式还不一样的话更耗费性能。应避免这类使用。
- nvue 页面没有
bounce
回弹效果,只有几个列表组件有bounce
效果,包括list
、recycle-list
、waterfall
。 - 原生开发没有页面滚动的概念,页面内容高过屏幕高度并不会自动滚动,只有部分组件可滚动(
list
、waterfall
、scroll-view/scroller
),要滚得内容需要套在可滚动组件下。这不符合前端开发的习惯,所以在 nvue 编译为 uni-app 模式时,给页面外层自动套了一个scroller
,页面内容过高会自动滚动。(组件不会套,页面有recycle-list
时也不会套)。后续会提供配置,可以设置不自动套。 - 在 App.vue 中定义的全局 js 变量不会在 nvue 页面生效。
globalData
和vuex
是生效的。 - App.vue 中定义的全局 css,对 nvue 和 vue 页面同时生效。如果全局 css 中有些 css 在 nvue 下不支持,编译时控制台会报警,建议把这些不支持的 css 包裹在条件编译里,
APP-PLUS-NVUE
- 不能在
style
中引入字体文件,nvue 中字体图标的使用参考:加载自定义字体。如果是本地字体,可以用plus.io
的 API 转换路径。 - 目前不支持在 nvue 页面使用
typescript/ts
。 - nvue 页面关闭原生导航栏时,想要模拟状态栏,可以参考文章。但是,仍然强烈建议在 nvue 页面使用原生导航栏。nvue 的渲染速度再快,也没有原生导航栏快。原生排版引擎解析
json
绘制原生导航栏耗时很少,而解析 nvue 的 js 绘制整个页面的耗时要大的多,尤其在新页面进入动画期间,对于复杂页面,没有原生导航栏会在动画期间产生整个屏幕的白屏或闪屏。
互相引用:js、css、json、静态资源、原生插件
传统vue项目开发,引用组件需要导入 - 注册 - 使用
三个步骤,如下:
<template>
<view>
<!-- 3.使用组件 -->
<uni-rate text="1"></uni-rate>
</view>
</template>
<script>
// 1. 导入组件
import uniRate from '@/components/uni-rate/uni-rate.vue';
export default {
components: { uniRate } // 2. 注册组件
}
</script>
Vue 3.x增加了script setup
特性,将三步优化为两步,无需注册步骤,更为简洁:
<template>
<view>
<!-- 2.使用组件 -->
<uni-rate text="1"></uni-rate>
</view>
</template>
<script setup>
// 1. 导入组件
import uniRate from '@/components/uni-rate/uni-rate.vue';
</script>
uni-app
的easycom
机制,将组件引用进一步优化,开发者只管使用,无需考虑导入和注册,更为高效:
<template>
<view>
<!-- 1.使用组件 -->
<uni-rate text="1"></uni-rate>
</view>
</template>
<script>
</script>
在 uni-app 项目中,页面引用组件和组件引用组件的方式都是一样的(可以理解为:页面是一种特殊的组件),均支持通过 easycom
方式直接引用。
easycom 规范详细介绍,参考:easycom
引用 js
js
文件或script
标签内(包括 renderjs 等)引入js
文件时,可以使用相对路径和绝对路径。形式如下。注意:js 文件不支持使用/
开头的方式引入
// 绝对路径,@指向项目根目录,在cli项目中@指向src目录
import add from '@/common/add.js';
// 相对路径
import add from '../../common/add.js';
uni-app支持使用npm安装第三方包。如若之前未接触过npm,请翻阅NPM官方文档进行学习。
初始化 npm 工程
若项目之前未使用npm管理依赖(项目根目录下无package.json文件),先在项目根目录执行命令初始化npm工程:npm init -y
cli项目默认已经有package.json了。HBuilderX创建的项目默认没有,需要通过初始化命令来创建。
安装依赖。在项目根目录执行命令安装npm包:npm install packageName --save
安装完即可使用npm包,js中引入npm包:
import package from 'packageName'
const package = require('packageName')
注意
- 为多端兼容考虑,建议优先从 uni-app插件市场 获取插件。直接从 npm 下载库很容易只兼容H5端。
- 非 H5 端不支持使用含有 dom、window 等操作的 vue 组件和 js 模块,安装的模块及其依赖的模块使用的 API 必须是 uni-app 已有的 API(兼容小程序 API),比如:支持高德地图微信小程序 SDK。类似jQuery 等库只能用于H5端。
- node_modules 目录必须在项目根目录下。不管是cli项目还是HBuilderX创建的项目。
- 关于ui库的获取,详见多端UI库
引用 css
使用@import
语句可以导入外联样式表,@import
后跟需要导入的外联样式表的相对路径,用;
表示语句结束。示例:
<style>
@import "../../common/uni.css";
.uni-card {
box-shadow: none;
}
</style>
引用 json
uni-app vue3
和 uni-app x (HBuilderX 4.25+)
项目支持引入 json
文件。
js | ts | uts
文件或 script
标签内引入 json
文件时,可以使用相对路径或绝对路径,例如:
// 绝对路径,@指向项目根目录,在cli项目中@指向src目录
import pagesJson from '@/pages.json';
// 相对路径
import pagesJson from '../../common/pages.json';
导入 json
文件时支持解构,此时会根据导入内容进行摇树,减小包体积,
例如:import { pages } from '@/pages.json';
导入的 json
文件内部支持条件编译, 导入的结果是根据条件编译规则进行处理后的结果,以如下 json
文件为例:
{
"pages": [{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "index"
}
},
// #ifdef APP
{
"path": "pages/index/app",
"style": {
"navigationBarTitleText": "app"
}
},
// #endif
// #ifdef H5
{
"path": "pages/index/web",
"style": {
"navigationBarTitleText": "web"
}
}
// #endif
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uni-app",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8"
},
"uniIdRouter": {}
}
在 App
平台导入的结果中,pages
下只包含 path
为 pages/index/index
和 pages/index/app
的对象。
在 Web
平台导入的结果中,pages
下只包含 path
为 pages/index/index
和 pages/index/web
的对象。
引入静态资源
template
内引入静态资源,如image
、video
等标签的src
属性时,可以使用相对路径或者绝对路径,形式如下
<!-- 绝对路径,/static指根目录下的static目录,在cli项目中/static指src目录下的static目录 -->
<image class="logo" src="/static/logo.png"></image>
<image class="logo" src="@/static/logo.png"></image>
<!-- 相对路径 -->
<image class="logo" src="../../static/logo.png"></image>
注意
@
开头的绝对路径以及相对路径会经过 base64 转换规则校验- 引入的静态资源在非 web 平台,均不转为 base64。
- web 平台,小于 4kb 的资源会被转换成 base64,其余不转。
- 自
HBuilderX 2.6.6
起template
内支持@
开头路径引入静态资源,旧版本不支持此方式 - App 平台自
HBuilderX 2.6.9
起template
节点中引用静态资源文件时(如:图片),调整查找策略为【基于当前文件的路径搜索】,与其他平台保持一致 - 支付宝小程序组件内 image 标签不可使用相对路径
css 引入静态资源
css
文件或style标签
内引入css
文件时(scss、less 文件同理),可以使用相对路径或绝对路径(HBuilderX 2.6.6
)
/* 绝对路径 */
@import url('/common/uni.css');
@import url('@/common/uni.css');
/* 相对路径 */
@import url('../../common/uni.css');
注意:自HBuilderX 2.6.6
起支持绝对路径引入静态资源,旧版本不支持此方式
css
文件或style标签
内引用的图片路径可以使用相对路径也可以使用绝对路径,需要注意的是,有些小程序端 css 文件不允许引用本地文件(请看注意事项)。
/* 绝对路径 */
background-image: url(/static/logo.png);
background-image: url(@/static/logo.png);
/* 相对路径 */
background-image: url(../../static/logo.png);
提示
- 引入字体图标请参考,字体图标
@
开头的绝对路径以及相对路径会经过 base64 转换规则校验- 不支持本地图片的平台,小于 40kb,一定会转 base64。(共四个平台 mp-weixin, mp-qq, mp-toutiao, app v2)
- web 平台,小于 4kb 会转 base64,超出 4kb 时不转。
- 其余平台不会转 base64
js/uts 引入静态资源
js/uts中引入静态资源,多用于静态资源存放在非 static
目录中的情况,可以使用 import 引入相对路径或绝对路径
例:有如下目录结构 ,在static 和页面文件夹下分别有静态资源
├── pages
│ └── index
│ │── index.uvue
│ └── icon.png
└── static
└── logo.png
正常情况下,如 image 的 src 中直接引入 static 中 logo.png ,可以使用相对路径或绝对路径
<!-- /pages/index/index.vue -->
<template>
<view class="content">
<image src="../../static/logo.png" />
<image src="/static/logo.png" />
<image src="@static/logo.png" />
</view>
</template>
而引入 index 下的 icon.png 不管是相对还是绝对路径,都无法显示,所以这时候需要在 js/uts 中 使用 import 来引入
<!-- /pages/index/index.vue -->
<template>
<view class="content">
<image :src="src" />
</view>
</template>
<script>
// 使用 import 引入静态资源,并在 data 中赋值引用
import icon_src from './icon.png'
export default {
data() {
return {
src: icon_src
}
},
}
</script>
静态资源引入注意事项
通常项目中规定根目录下的 static 为静态资源文件夹(目前暂不支持修改),资源存放此处后,可在任意文件直接使用相对或者绝对路径引用,具体参考上述模板 css/js/uts
中引入静态资源的说明。
而非 static
目录的静态资源,不支持直接引用,需要在 js/uts
中使用 import
来引入,确保路径正确。
综上所述,我们总结一下静态资源引用的注意事项:
- 在模板或者
css
文件使用static
目录中的静态资源,无需特殊处理,可直接通过相对路径或者绝对路径直接引入。 - 在
js/uts
文件使用静态资源,需要使用import
来引入。 - 不管在任何文件引入非
static
目中的静态资源,均需在js/uts
文件使用import
来引入。
静态资源编译规则
项目 static
目录下的静态资源,会被直接拷贝到编译后目录的 static
目录下。
非static
目录下的静态资源在vue3
下,被引用的资源会编译到 assets
目录下,并重新命名为 原始名称+内容hash
,如:logo.png
会编译为类似 logo.cfd8fa94.png
的名称。如果该静态资源未被引用,则不会被编译器处理。
非static
目录下的静态资源在vue2
不同平台下,编译规则有些不同:
自
HBuilderX 4.0
起已和vue3
保持一致
- web: 静态资源将会编译到
static -> img
下, 如小于 4k 则转为base64 - 小程序:静态资源将会编译到资源同名文件下,如小于 40kb 则转base64
- app: 静态资源将会编译到资源同名文件下
引入 原生插件
:https://uniapp.dcloud.net.cn/plugin/native-plugin.html
uni.requireNativePlugin(PluginName)
js 语法
uni-app
的js API由标准ECMAScript的js API 和 uni 扩展 API 这两部分组成。
标准ECMAScript的js仅是最基础的js。浏览器基于它扩展了window、document、navigator等对象。小程序也基于标准js扩展了各种wx.xx、my.xx、swan.xx的API。node也扩展了fs等模块。
uni-app基于ECMAScript扩展了uni对象,并且API命名与小程序保持兼容。
uni-app
的js代码,h5端运行于浏览器中。非h5端(包含小程序和App),Android平台运行在v8引擎中,iOS平台运行在iOS自带的jscore引擎中,都没有运行在浏览器或webview里。
非H5端,虽然不支持window、document、navigator等浏览器的js API,但也支持标准ECMAScript。
请注意不要把浏览器里的js扩展对象等价于标准js。
所以uni-app的非H5端,一样支持标准js,支持if、for等语法,支持字符串、数字、时间、布尔值、数组、自定义对象等变量类型及各种处理方法。仅仅是不支持window、document、navigator等浏览器专用对象。
uni-app 布局
可视化 自动生成代码,组件、模板拖拽布局,并保存设计:https://ask.dcloud.net.cn/article/39812
体验地址:https://we7.diyhey.com/admin/index
uni-app Flex布局:https://blog.csdn.net/qq_42322103/article/details/92843806
flex盒模型与布局:https://blog.csdn.net/steve95/article/details/116014510
FLEX 弹性布局:https://www.cnblogs.com/mindzone/p/13652132.html
xml 生成 uni-app 布局
盒子模型
所有HTML元素可以看作盒子,在CSS中,"box model"这一术语是用来设计和布局时使用。CSS盒模型本质上是一个盒子,封装周围的HTML元素,它包括:边距,边框,填充,和实际内容。
:https://www.runoob.com/css/css-boxmodel.html
下面的图片说明了盒子模型(Box Model):
不同部分的说明:
- Margin(外边距) - 清除边框外的区域,外边距是透明的。
- Border(边框) - 围绕在内边距和内容外的边框。
- Padding(内边距) - 清除内容周围的区域,内边距是透明的。
- Content(内容) - 盒子的内容,显示文本和图像。
为了正确设置元素在所有浏览器中的宽度和高度,你需要知道的盒模型是如何工作的。
元素的宽度和高度
当指定一个 CSS 元素的宽度和高度属性时,只是设置内容区域的宽度和高度。要知道,完整大小的元素,你还必须添加内边距,边框和外边距。
下面的例子中的元素的总宽度为 450px:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
<style>
div {
background-color: lightgrey;
width: 300px;
border: 25px solid green;
padding: 25px;
margin: 25px;
}
</style>
</head>
<body>
<h2>盒子模型演示</h2>
<p>CSS盒模型本质上是一个盒子,封装周围的HTML元素,它包括:边距,边框,填充,和实际内容。</p>
<div>这里是盒子内的实际内容。有 25px 内间距,25px 外间距、25px 绿色边框。</div>
</body>
</html>
效果图
现在计算下:
300px (宽)
+ 50px (左 + 右填充)
+ 50px (左 + 右边框)
+ 50px (左 + 右边距)
= 450px
试想一下,你只有 250 像素的空间。让我们设置总宽度为 250 像素的元素:
div {
width: 220px;
padding: 10px;
border: 5px solid gray;
margin: 0;
}
- 元素的总宽度计算公式:总元素的宽度=宽度+左填充+右填充+左边框+右边框+左边距+右边距
- 元素的总高度计算公式:总元素的高度=高度+顶部填充+底部填充+上边框+下边框+上边距+下边距
页面样式与布局 (css 语法)
uni-app 有 vue 页面、nvue 页面、uvue页面。
- vue 页面是 webview 渲染的
- app-nvue 页面是原生渲染的,其样式比 web 会限制更多,另见nvue的css
- app-uvue 页面是原生渲染的,是 web 的css子集,另见uvue的css
uni-app 的 css 与 web 的 css 基本一致。uni-app 支持less、sass、scss、stylus等预处理器。
参考: css预处理器
尺寸单位
uni-app
支持的通用 css 单位包括 px、rpx
- px 即屏幕像素
- rpx 即响应式 px,一种根据屏幕宽度自适应的动态单位。以 750 宽的屏幕为基准,750rpx 恰好为屏幕宽度。屏幕变宽,rpx 实际显示效果会等比放大,但在 App(vue2 不含 nvue) 端和 H5(vue2) 端屏幕宽度达到 960px 时,默认将按照 375px 的屏幕宽度进行计算,具体配置参考:rpx 计算配置 。
vue 页面支持下面这些普通 H5 单位,但在 nvue 里不支持:
- rem 根字体大小可以通过 page-meta 配置抖音小程序和飞书小程序:屏幕宽度/20、百度小程序:16px、支付宝小程序:50px
- vh viewpoint height,视窗高度,1vh 等于视窗高度的 1%
- vw viewpoint width,视窗宽度,1vw 等于视窗宽度的 1%
nvue 还不支持百分比单位。
App 端,在 pages.json 里的 titleNView 或页面里写的 plus api 中涉及的单位,只支持 px。注意此时不支持 rpx
nvue 中,uni-app 模式(nvue 不同编译模式介绍)可以使用 px 、rpx,表现与 vue 中基本一致,另外启用 dynamicRpx 后可以适配屏幕大小动态变化。weex 模式目前遵循 weex 的单位,它的单位比较特殊:
- px:,以 750 宽的屏幕为基准动态计算的长度单位,与 vue 页面中的 rpx 理念相同。(一定要注意 weex 模式的 px,和 vue 里的 px 逻辑不一样。)
- wx:与设备屏幕宽度无关的长度单位,与 vue 页面中的 px 理念相同
下面对 rpx
详细说明:
设计师在提供设计图时,一般只提供一个分辨率的图。
严格按设计图标注的 px 做开发,在不同宽度的手机上界面很容易变形。
而且主要是宽度变形。高度一般因为有滚动条,不容易出问题。由此,引发了较强的动态宽度单位需求。
微信小程序设计了 rpx 解决这个问题。uni-app
在 App 端、H5 端都支持了 rpx
,并且可以配置不同屏幕宽度的计算方式,具体参考:rpx 计算配置。
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。
Tips
- 注意 rpx 是和宽度相关的单位,屏幕越宽,该值实际像素越大。如不想根据屏幕宽度缩放,则应该使用 px 单位。
- 如果开发者在字体或高度中也使用了 rpx ,那么需注意这样的写法意味着随着屏幕变宽,字体会变大、高度会变大。如果你需要固定高度,则应该使用 px 。
- rpx 不支持动态横竖屏切换计算,使用 rpx 建议锁定屏幕方向
- 设计师可以用 iPhone6 作为视觉稿的标准。
- 如果设计稿不是 750px,HBuilderX 提供了自动换算的工具,详见:HBuilderX中自动转换px为upx。
- App 端,在 pages.json 里的 titleNView 或页面里写的 plus api 中涉及的单位,只支持 px,不支持 rpx。
- 早期 uni-app 提供了 upx ,目前已经推荐统一改为 rpx 了,详见
样式导入
使用@import
语句可以导入外联样式表,@import
后跟需要导入的外联样式表的相对路径,用;
表示语句结束。示例代码:
<style>
@import "../../common/uni.css";
.uni-card {
box-shadow: none;
}
</style>
内联样式
框架组件上支持使用 style、class 属性来控制组件的样式。
- style:静态的样式统一写到 class 中。style 接收动态的样式,在运行时会进行解析,请尽量避免将静态的样式写进 style 中,以免影响渲染速度。
<view :style="{color:color}" /> - class:用于指定样式规则,其属性值是样式规则中类选择器名(样式类名)的集合,样式类名不需要带上.,样式类名之间用空格分隔。<view class="normal_view" />
选择器
目前支持的选择器有:
选择器 | 样例 | 样例描述 |
---|---|---|
.class | .intro | 选择所有拥有 class="intro" 的组件 |
#id | #firstname | 选择拥有 id="firstname" 的组件 |
element | view | 选择所有 view 组件 |
element, element | view, checkbox | 选择所有文档的 view 组件和所有的 checkbox 组件 |
::after | view::after | 在 view 组件后边插入内容,仅 vue 页面生效 |
::before | view::before | 在 view 组件前边插入内容,仅 vue 页面生效 |
注意:
-
在
uni-app
中不能使用*
选择器。 -
微信小程序自定义组件中仅支持 class 选择器
-
page
相当于body
节点,例如:<!-- 设置页面背景颜色,使用 scoped 会导致失效 -- > page { background-color: #ccc; }
-
web端可以使用
html
、body
、:root
等选择器。由于页面的css样式隔离,且html节点并未添加data-xxx属性,html
、:root
写在页面style内无效,只能写在App.vue内。
全局样式、局部样式
定义在 App.vue 中的样式为全局样式,作用于每一个页面。在 pages 目录下 的 vue 文件中定义的样式为局部样式,只作用在对应的页面,并会覆盖 App.vue 中相同的选择器。
注意:
- App.vue 中通过
@import
语句可以导入外联样式,一样作用于每一个页面。 - nvue 页面暂不支持全局样式
CSS 变量
uni-app 提供内置 CSS 变量
CSS 变量 | 描述 | App | 小程序 | H5 |
---|---|---|---|---|
--status-bar-height | 系统状态栏高度 | 系统状态栏高度、nvue 注意见下 | 25px | 0 |
--window-top | 内容区域距离顶部的距离 | 0 | 0 | NavigationBar 的高度 |
--window-bottom | 内容区域距离底部的距离 | 0 | 0 | TabBar 的高度 |
注意:
var(--status-bar-height)
此变量在微信小程序环境为固定25px
,在 App 里为手机实际状态栏高度。- 当设置
"navigationStyle":"custom"
取消原生导航栏后,由于窗体为沉浸式,占据了状态栏位置。此时可以使用一个高度为var(--status-bar-height)
的 view 放在页面顶部,避免页面内容出现在状态栏。 - 由于在 H5 端,不存在原生导航栏和 tabbar,也是前端 div 模拟。如果设置了一个固定位置的居底 view,在小程序和 App 端是在 tabbar 上方,但在 H5 端会与 tabbar 重叠。此时可使用
--window-bottom
,不管在哪个端,都是固定在 tabbar 上方。 - 目前 nvue 在 App 端,还不支持
--status-bar-height
变量,替代方案是在页面 onLoad 时通过 uni.getSystemInfoSync().statusBarHeight 获取状态栏高度,然后通过 style 绑定方式给占位 view 设定高度。下方提供了示例代码
代码块
快速书写 css 变量的方法是:在 css 中敲 hei,在候选助手中即可看到 3 个 css 变量。(HBuilderX 1.9.6 以上支持)
示例 1 - 普通页面使用 css 变量:
<template>
<!-- HBuilderX 2.6.3+ 新增 page-meta, 详情:https://uniapp.dcloud.io/component/page-meta -->
<page-meta>
<navigation-bar />
</page-meta>
<view>
<view class="status_bar">
<!-- 这里是状态栏 -->
</view>
<view>状态栏下的文字</view>
</view>
</template>
<style>
.status_bar {
height: var(--status-bar-height);
width: 100%;
}
</style>
<template>
<view>
<view class="toTop">
<!-- 这里可以放一个向上箭头,它距离底部tabbar上浮10px-->
</view>
</view>
</template>
<style>
.toTop {
bottom: calc(var(--window-bottom) + 10px);
}
</style>
示例 2 - nvue 页面获取状态栏高度
<template>
<view class="content">
<view :style="{ height: iStatusBarHeight + 'px'}"></view>
</view>
</template>
<script>
export default {
data() {
return {
iStatusBarHeight: 0,
};
},
onLoad() {
this.iStatusBarHeight = uni.getSystemInfoSync().statusBarHeight;
},
};
</script>
固定值
uni-app
中以下组件的高度是固定的,不可修改:
组件 | 描述 | App | H5 |
---|---|---|---|
NavigationBar | 导航栏 | 44px | 44px |
TabBar | 底部选项卡 | HBuilderX 2.3.4 之前为 56px,2.3.4 起和 H5 调为一致,统一为 50px。(但可以自主更改高度) | 50px |
各小程序平台,包括同小程序平台的 iOS 和 Android 的高度也不一样。
Flex 布局
为支持跨平台,框架建议使用 Flex 布局,关于 Flex 布局可以参考外部文档A Complete Guide to Flexbox、阮一峰的 flex 教程等。
背景图片
uni-app
支持使用在 css 里设置背景图片,使用方式与普通 web
项目大体相同,但需要注意以下几点:
- 支持 base64 格式图片。
- 支持网络路径图片。
- 小程序不支持在 css 中使用本地文件,包括本地的背景图和字体文件。需以 base64 方式方可使用。
使用本地路径背景图片需注意:
- 为方便开发者,在背景图片小于 40kb 时,
uni-app
编译到不支持本地背景图的平台时,会自动将其转化为 base64 格式; - 图片大于等于 40kb,会有性能问题,不建议使用太大的背景图,如开发者必须使用,则需自己将其转换为 base64 格式使用,或将其挪到服务器上,从网络地址引用。
- 本地背景图片的引用路径推荐使用以 ~@ 开头的绝对路径。
.test2 { background-image: url('~@/static/logo.png'); }
注意:微信小程序不支持相对路径(真机不支持,开发工具支持)
字体图标
uni-app
支持使用字体图标,使用方式与普通 web
项目相同,需要注意以下几点:
- 支持 base64 格式字体图标。
- 支持网络路径字体图标。
- 小程序不支持在 css 中使用本地文件,包括本地的背景图和字体文件。需以 base64 方式方可使用。
- 网络路径必须加协议头
https
。 - 从 http://www.iconfont.cn 上拷贝的代码,默认是没加协议头的。
- 从 http://www.iconfont.cn 上下载的字体文件,都是同名字体(字体名都叫 iconfont,安装字体文件时可以看到),在 nvue 内使用时需要注意,此字体名重复可能会显示不正常,可以使用工具修改。
使用本地路径图标字体需注意:
- 为方便开发者,在字体文件小于 40kb 时,
uni-app
会自动将其转化为 base64 格式; - 字体文件大于等于 40kb,仍转换为 base64 方式使用的话可能有性能问题,如开发者必须使用,则需自己将其转换为 base64 格式使用,或将其挪到服务器上,从网络地址引用;
- 字体文件的引用路径推荐使用以 ~@ 开头的绝对路径。
@font-face { font-family: test1-icon; src: url('~@/static/iconfont.ttf'); }
nvue
中不可直接使用 css 的方式引入字体文件,需要使用以下方式在 js 内引入。nvue 内不支持本地路径引入字体,请使用网络链接或者base64
形式。src
字段的url
的括号内一定要使用单引号。
var domModule = weex.requireModule('dom');
domModule.addRule('fontFace', {
fontFamily: 'fontFamilyName',
src: "url('https://...')",
});
示例:
<template>
<view>
<view>
<text class="test"></text>
<text class="test"></text>
<text class="test"></text>
</view>
</view>
</template>
<style>
@font-face {
font-family: 'iconfont';
src: url('https://at.alicdn.com/t/font_865816_17gjspmmrkti.ttf') format('truetype');
}
.test {
font-family: iconfont;
margin-left: 20rpx;
}
</style>
vue3 语法
在传统开发中,用原生的 JavaScript DOM 操作函数对 DOM 进行频繁操作的时候,浏览器要不停的渲染新的 DOM 树,导致页面看起来非常卡顿。
vue 是单页面应用,使页面局部刷新,不用每次跳转页面都要请求所有数据和 DOM ,这样大大加快了访问速度和提升用户体验。
文件 类型 变化
- 以前是.html文件,开发也是html,运行也是html。
- 现在每个页面是一个.vue文件,开发是vue,但经过编译后,运行时已经变成了js文件(如果是uts则可能编译成kotlin、swift)。
- 现代前端开发,很少直接使用HTML,基本都是开发、编译、运行。所以
uni-app
有编译器、运行时的概念。
文件内 代码架构 变化
- 以前一个
html
大节点,里面有script
和style
节点;
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script type="text/javascript">
</script>
<style type="text/css">
</style>
</head>
<body>
</body>
</html>
- 现在
template
是一级节点,用于写tag组件,script
和style
是并列的一级节点,也就是有3个一级节点。这个叫vue单文件组件规范sfc。
<template>
<view>
注意必须有一个view,且只能有一个根view。所有内容写在这个view下面。
</view>
</template>
<script>
export default {
}
</script>
<style>
</style>
引用 外部文件 变化
- 以前通过script src、link href引入外部的js和css;
<script src="js/jquery-1.10.2.js" type="text/javascript"></script>
<link href="css/bootstrap.css" rel="stylesheet" type="text/css"/>
- 现在是es6的写法,
import
引入外部的js模块(注意不是文件)或css;
js要require进来,变成了对象。在hello uni-app的 common
目录有一个工具类 util.js
,可以在hello uni-app中搜索这个例子查看。hello uni-app示例代码可从 github 获取。
<script>
var util = require('../../../common/util.js'); //require这个js模块
var formatedPlayTime = util.formatTime(playTime); //调用js模块的方法
</script>
而在这个 util.js
里,要把之前的 function
封装为模块(module)的方法并导出(exports)。只有被导出的方法和属性才能被外部调用,不导出的属于模块内部函数和变量。这是es6的模块规范。
function formatTime(time) {
return time;//这里没写逻辑
}
module.exports = {
formatTime: formatTime
}
当然还有一些高级的用法,比如在导出时可以重命名
// 直接使用js模块的属性。在hello uni-app有示例
var dateUtils = require('../../../common/util.js').dateUtils;
// 将js导入并重命名为echarts,然后使用echarts.来继续执行方法。在hello uni-app有示例
import * as echarts from '/components/echarts/echarts.simple.min.js';
css外部文件导入。全局样式,在根目录下的 app.vue
里写入,每个页面都会加载 app.vue
里的样式。
<style>
@import "./common/uni.css";
.uni-hello-text{
color:#7A7E83;
}
</style>
另外,vue支持组件导入,可以更方便的封装一个包括界面、js、样式的库。详见
组件/标签的变化
以前是html标签,比如 <div>
,现在是小程序组件,比如 <view>
。
那么标签和组件有什么区别,不都是用尖括号包围起来一段英文吗?
- 其实标签是老的概念,标签属于浏览器内置的东西。
- 但组件,是可以自由扩展的。类似你可以把一段js封装成函数或模块,你也可以把一个ui控件封装成一个组件。
uni-app
参考小程序规范,提供了一批内置组件
js 的变化
- 以前script里随便写js变量和function
<script type="text/javascript">
var a;
function funa () {
}
</script>
现在script里默认有export default,在里面写data、事件和method
- 写在
export default {
前面的变量,是页面内部的全局变量,可以在各种方法里使用。 export default {}
里是一个大json,data、生命周期、method都需要用逗号分隔。- data -> return 里,编写可以绑定在页面template模板里的变量,页面组件的text里绑定data数据使用{{}},比如下面例子中的
textvalue
。而下面的globalvar就不能在模板里绑定使用。在HBuilderX中,敲vdata代码块,可以快捷生成data的代码结构。 - 页面的生命周期/事件,如下面的
onLoad
,和data平级。 - 模板里要调用的方法,都需要写在
methods
下面。每个方法也需要用逗号分隔。不需要再使用function
声明,只要写在methods
下的函数,都可以在template里调用。同样,HBuilderX里敲vmethods
代码块,也可以生成相应结构。
<template>
<view>
<text>{{textvalue}}</text><!-- 这里演示了组件值的绑定 -->
<button :type="buttontype" @click="changetextvalue()">修改为789</button><!-- 这里演示了属性和事件的绑定 -->
</view>
</template>
<script>
var globalvar = 1
function globalfun(){}
export default {
data() {
return {
textvalue:"123",
buttontype:"primary"
};
},
onLoad() {
globalvar = 2
globalfun()
this.textvalue="456"//这里修改textvalue的值
},
methods: {
changetextvalue() {
this.textvalue="789"//这里修改textvalue的值
}
}
}
</script>
在上述例子中,传统写法的定义的变量globalvar和函数globalfun,可以在export default { }
里使用,但无法在模板里直接绑定和调用。模板里只能绑定data里的变量、调用methods里的方法。
- 以前的 DOM 操作,如果你想改变某个 DOM 元素的显示内容,比如一个view的显示文字:给view设id,然后js里通过选择器获取 DOM 元素,进一步通过js进行赋值操作,修改 DOM 元素的属性或值。
<html>
<head>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded",function () {
document.getElementById("spana").innerText="456"
})
function changetextvalue () {
document.getElementById("spana").innerText="789"
}
</script>
</head>
<body>
<span id="spana">123</span>
<button type="button" onclick="changetextvalue()">修改为789</button>
</body>
</html>
现在的做法,是vue的绑定模式,给这个 DOM 元素绑定一个js变量,在script中修改js变量的值,DOM 会自动变化,页面会自动更新渲染。
- 前端改用 MVVM (Model-View-ViewModel的简写)模式,简单来说,Model:代表数据模型,View:只专注视图UI处理,ViewModel:只处理业务和数据。它的核心是 MVVM 中的 VM,也就是 ViewModel。 ViewModel负责连接 View 和 Model,保证视图和数据的一致性,这种轻量级的架构让前端开发更加高效、便捷,大幅减少代码行数,同时差量渲染性能更好。
uni-app
使用vue的数据绑定方式解决js和 DOM 界面交互的问题。
<template>
<view>
<text>{{textvalue}}</text><!-- 这里演示了组件值的绑定 -->
<button :type="buttontype" @click="changetextvalue()">修改为789</button><!-- 这里演示了属性和事件的绑定 -->
</view>
</template>
<script>
export default {
data() {
return {
textvalue:"123",
buttontype:"primary"
};
},
onLoad() {
this.textvalue="456"//这里修改textvalue的值,其实123都来不及显示就变成了456
},
methods: {
changetextvalue() {
this.textvalue="789"//这里修改textvalue的值,页面自动刷新为789
}
}
}
</script>
- 以前在是html的tag里用一个属性
onclick
来写点击事件 - 现在是使用
@click
(其实是v-on:click
的缩写,在uni-app里基本都使用缩写)调用methods里的方法。
在 uni-app 中使用vue的差异
uni-app
在发布到H5时支持所有vue的语法;发布到App和小程序时,由于平台限制,无法实现全部vue语法,但 uni-app
仍是对vue语法支持度最高的跨端框架。
相比Web平台, Vue.js 在 uni-app
中使用差异主要集中在两个方面:
uni-app
项目对 vue 3.0 的支持版本情况如下:
- Web平台:支持。
- 小程序平台:
HBuilderX 3.3.3+
编译器改为vite
,之前版本的编译器为webpack
。 - App 平台:
uni-app 3.2.5+
支持。HBuilderX 3.3.13
起nvue
编译器升级为vite
。
注意事项
- vue3 响应式基于
Proxy
实现,不支持iOS9
和ie11
。 - 暂不支持新增的
Teleport
,Suspense
组件。 - 目前
HBuilderX 3.2
起已预置,之前的版本只能使用cli方式。
插值
指令
Data 选项
Class 与 Style 绑定
条件渲染
列表渲染
事件处理
表单 输入绑定 (v-model)
计算属性和侦听器
组件
- 组件是视图层的基本组成单元。
- 组件是一个单独且可复用的功能模块的封装。
- 一个组件包括开始标签和结束标签,标签上可以写属性,并对属性赋值。内容则写在两个标签之内。
- 根节点为
<template>
,这个<template>
下在App、H5可以有多个根<view>
组件,在小程序只能有一个根<view>
组件。 - 一个组件的 data 选项必须是一个函数。
- 根节点为
下面是一个基本组件示例,在根<view>
组件下再次引入一个<view>
组件,并给组件的text
区绑定一个data
。
<template>
<view>
<text>{{userName}}</text>
</view>
</template>
<script>
export default {
data() {
return {
"userName":"foo"
}
}
}
</script>
基础组件是内置在uni-app
框架中的,包括view
、text
、input
、button
、video
等几十个基础组件,列表详见:uni-app基础组件
但仅有基础组件是不够用的,实际开发中会有很多封装的组件。
比如我们需要一个五角星点击评分的组件,在DCloud的插件市场里可以获取到:uni-rate 评分 - DCloud 插件市场
把这个uni-rate
组件导入到你的uni-app
项目下,在需要的vue页面里引用它,就可以在指定的地方显示出这个五角星组件。
<!-- 在index.vue页面引用 uni-rate 组件-->
<template>
<view>
<uni-rate></uni-rate><!-- 这里会显示一个五角星,并且点击后会自动亮星 -->
</view>
</template>
注册 组件
props
非 Prop 的 Attribute
自定义事件
插槽 (slot)
api
常见问题
组合式 API(Composition API)
通过组合式 API,我们可以使用导入的 API 函数来描述组件逻辑。在单文件组件中,组合式 API 通常会与 <script setup>
搭配使用。这个 setup attribute 是一个标识,告诉 Vue 需要在编译时进行一些处理,让我们可以更简洁地使用组合式 API。比如,<script setup>
中的导入和顶层变量/函数都能够在模板中直接使用。
使用组合式API
从 vue 包内导入并使用基础的组合式API,具体 API 可以参考:Vue 官网。从 @dcloudio/uni-app 包内导入 uni-app 应用生命周期及页面的生命周期。
import { defineComponent, ref } from 'vue'
import { onReady } from '@dcloudio/uni-app'
export default defineComponent({
setup() {
const title = ref('Hello')
onReady(() => {
console.log('onReady')
})
return {
title
}
}
})
使用 Script Setup。改用 Script Setup 写法导入 API
<script setup>
import { ref } from 'vue'
import { onReady } from '@dcloudio/uni-app'
const title = ref('Hello')
onReady(() => {
console.log('onReady')
})
</script>
状态管理 Vuex
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。uni-app 内置了 Vuex
什么是“状态管理模式”?
从一个简单的 Vue 计数应用开始:
<!-- view 视图-->
<template>
<view>
{{count}}
</view>
</template>
<script>
export default {
// state 数据源
data() {
return {
count: 0
}
},
// actions 控制状态变化
methods: {
increment() {
this.count++
}
}
}
</script>
这个状态自管理应用包含以下几个部分:
- state,驱动应用的数据源;
- view,以声明方式将 state 映射到视图;
- actions,响应在 view 上的用户输入导致的状态变化。
以下是一个表示“单向数据流”理念的简单示意:
但是,当我们的应用遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏:
- 多个视图依赖于同一状态。
- 来自不同视图的行为需要变更同一状态。
因此,我们把组件的共享状态抽取出来,以一个全局单例模式管理。在这种模式下,我们的组件树构成了一个巨大的“视图”,不管在树的哪个位置,任何组件都能获取状态或者触发行为!这就是vuex的产生。
通过定义和隔离状态管理中的各种概念并通过强制规则维持视图和状态间的独立性,我们的代码将会变得更结构化且易维护。这就是 Vuex 背后的基本思想。
Vuex 是专门为 Vue.js 设计的状态管理库,以利用 Vue.js 的细粒度数据响应机制来进行高效的状态更新。
如果你想交互式地学习 Vuex,可以看这个 Scrimba 上的 Vuex 课程,它将录屏和代码试验场混合在了一起,你可以随时暂停并尝试。
优势与使用场景
- Vuex的状态存储是响应式的,可跟踪每一个状态变化,一旦它改变,所有关联组件都会自动更新相对应的数据。
- 共享数据,解决了非父子组件的消息传递(将数据存放在state中)。
- 统一状态管理,减少了请求次数,有些情景可以直接从内存中的state获取数据。
Vuex与全局变量区别
vuex | 全局变量 |
---|---|
不能直接改变store里面的变量,由统一的方法修改数据 | 可以任意修改 |
每个组件可以根据自己vuex的变量名引用不受影响 | 全局变量可能操作命名污染 |
解决了多组件之间通信的问题 | 跨页面数据共享 |
适用于多模块、业务关系复杂的中大型项目 | 适用于demo或者小型项目 |
什么时候需要用vuex?
- 当一个组件需要多次派发事件时。例如购物车数量加减。
- 跨组件共享数据、跨页面共享数据。例如订单状态更新。
- 需要持久化的数据。例如登录后用户的信息。
- 当您需要开发中大型应用,适合复杂的多模块多页面的数据交互,考虑如何更好地在组件外部管理状态时。
项目 结构
使用 Vuex 需要遵守的规则:
-
应用层级的状态应该集中到单个
store
对象中。 -
提交
mutation
是更改状态的唯一方法,并且这个过程是同步的。 -
异步逻辑都应该封装到
action
里面。
只要你遵守以上规则,如何组织代码随你便。如果你的 store
文件太大,只需将 action
、mutation
和 getter
分割到单独的文件。
对于大型应用,我们会希望把 Vuex
相关代码分割到模块中。下面是项目结构示例:
├── pages
├── static
└── store
├── index.js # 我们组装模块并导出 store 的地方
├── actions.js # 根级别的 action
├── mutations.js # 根级别的 mutation
└── modules # 模块文件夹
├── cart.js # 购物车模块
└── products.js # 产品模块
├── App.vue
├── main.js
├── manifest.json
├── pages.json
└── uni.scss
核心概念
状态管理 Pinia
uni-app 内置了 Pinia 。Vue 2 项目暂不支持
-
HBuilder X 已内置了 Pinia,无需手动安装,按照下方示例使用即可。App 升级时,如果之前使用
HBuilder X 版本 < 4.14
打包,现在使用HBuilder X 版本 >= 4.14
,更新时需要整包更新不可使用wgt更新(在4.14
时升级了vue
版本,低版本的基座和高版本 wgt 资源包会导致使用 Pinia 时报错) -
使用
CLI
4.14 之前:执行 yarn add pinia@2.0.36 或 npm install pinia@2.0.36 安装,要固定版本
4.14 之后:执行 yarn add pinia 或 npm install pinia 安装,可不指定版本
Pinia 是什么
Pinia(发音为 /piːnjʌ/
,如英语中的 peenya
) 是 Vue 的存储库,它允许您跨组件、页面共享状态。在服务器端以及小型单页应用程序中,您也可以从使用 Pinia 中获得很多好处:
- Devtools 支持
- 追踪 actions、mutations 的时间线
- 在组件中展示它们所用到的 Store
- 让调试更容易的 Time travel
- 热模块更换
- 不必重载页面即可修改 Store
- 开发时可保持当前的 State
- 为 JS 开发者提供适当的 TypeScript 支持以及 自动补全 功能。
├── pages
├── static
└── stores
└── counter.js
├── App.vue
├── main.js
├── manifest.json
├── pages.json
└── uni.scss
基本示例:在 main.js
中编写以下代码:
import App from './App'
import { createSSRApp } from 'vue';
import * as Pinia from 'pinia';
export function createApp() {
const app = createSSRApp(App);
app.use(Pinia.createPinia());
return {
app,
Pinia, // 此处必须将 Pinia 返回
};
}
首先创建一个 Store:
// stores/counter.js
import { defineStore } from 'pinia';
export const useCounterStore = defineStore('counter', {
state: () => {
return { count: 0 };
},
// 也可以这样定义
// state: () => ({ count: 0 })
actions: {
increment() {
this.count++;
},
},
});
然后在组件中使用它:
<script setup>
import { useCounterStore } from '@/stores/counter'
const counter = useCounterStore()
counter.count++
// 自动补全! ✨
counter.$patch({ count: counter.count + 1 })
// 或使用 action 代替
counter.increment()
</script>
<template>
<!-- 直接从 store 中访问 state -->
<div>Current Count: {{ counter.count }}</div>
</template>
为实现更多高级用法,你甚至可以使用一个函数 (与组件 setup()
类似) 来定义一个 Store:
export const useCounterStore = defineStore('counter', () => {
const count = ref(0);
function increment() {
count.value++;
}
return { count, increment };
});
如果你还不熟悉 setup() 函数和组合式 API,Pinia 也提供了一组类似 Vuex 的 映射 state 的辅助函数。
你可以用和之前一样的方式来定义 Store,然后通过 mapStores()、mapState() 或 mapActions() 访问:
const useCounterStore = defineStore('counter', {
state: () => ({ count: 0 }),
getters: {
double: (state) => state.count * 2,
},
actions: {
increment() {
this.count++
},
},
})
const useUserStore = defineStore('user', {
// ...
})
// 使用
import { mapState, mapStores, mapActions } from 'pinia'
export default defineComponent({
computed: {
// 其他计算属性
// ...
// 允许访问 this.counterStore 和 this.userStore
...mapStores(useCounterStore, useUserStore)
// 允许读取 this.count 和 this.double
...mapState(useCounterStore, ['count', 'double']),
},
methods: {
// 允许读取 this.increment()
...mapActions(useCounterStore, ['increment']),
},
})
TypeScript 专题
uni-app 支持使用 ts 开发,可参考 Vue.js TypeScript 支持 说明。
类型定义文件由 @dcloudio/types 模块提供,安装后请注意配置 tsconfig.json 文件中的 compilerOptions > types 部分,如需其他小程序平台类型定义也可以安装,如:miniprogram-api-typings、mini-types。对于缺少或者错误的类型定义,可以自行在本地新增或修改并同时报告给官方请求更新。
JSX / TSX 语法
uniapp 支持 JSX 开发,可参考 Vue.js JSX/TSX 支持 说明
UTS 语法
uts,全称 uni type script,是一门跨平台的、高性能的、强类型的现代编程语言。
它可以被编译为不同平台的编程语言,如:
- web平台/小程序,编译为JavaScript
- Android平台,编译为Kotlin
- iOS平台,编译Swift
- 鸿蒙OS平台,编译为ArkTS(HBuilderX 4.22+)
uts 采用了与 ts 基本一致的语法规范,支持绝大部分 ES6 API。
但为了跨端,uts进行了一些约束和特定平台的增补。
过去在js引擎下运行支持的语法,大部分在uts的处理下也可以平滑的在kotlin和swift中使用。但有一些无法抹平,需要使用条件编译。
和uni-app的条件编译类似,uts也支持条件编译。写在条件编译里的,可以调用平台特有的扩展语法。
编译器 (条件编译)
uni-app
能实现一套代码、多端运行,核心是通过编译器 + 运行时
实现的:
- 编译器:将
uni-app
统一代码编译生成每个平台支持的特有代码;如在小程序平台,编译器将.vue
文件拆分生成wxml
、wxss
、js
等代码。 - 运行时:动态处理数据绑定、事件代理,保证Vue和平台宿主数据的一致性;
uni-app
项目根据所依赖的Vue
版本不同,编译器的实现也不同:
- vue2:
uni-app
编译器基于wepback实现 - vue3:
uni-app
编译器基于Vite实现,编译速度更快,详见:vue3和vite双向加持,uni-app性能再次提升
uni-app
项目根据创建方式的不同,编译器在使用上也有差异:
cli
方式创建的项目,编译器安装在项目下。编译器不会跟随HBuilderX
升级。如需升级编译器,可以参考:更新依赖到指定版本。HBuilderX
可视化界面创建的项目,编译器在HBuilderX
的安装目录下的plugin
目录,随着HBuilderX
的升级会自动升级编译器。- 已经使用
cli
创建的项目,如果想继续在HBuilderX
里使用,可以把工程拖到HBuilderX
中。注意如果是把整个项目拖入HBuilderX
,则编译时走的是项目下的编译器。如果是把src目录拖入到HBuilderX
中,则走的是HBuilderX
安装目录下plugin
目录下的编译器。
条件编译处理多端差异
ni-app 已将常用的组件、API封装到框架中,开发者按照 uni-app 规范开发即可保证多平台兼容,大部分业务均可直接满足。
但每个平台有自己的一些特性,因此会存在一些无法跨平台的情况。
- 大量写 if else,会造成代码执行性能低下和管理混乱。
- 编译到不同的工程后二次修改,会让后续升级变的很麻烦。
- 为每个平台重写,明明主业务逻辑又一样
在 C 语言中,通过 #ifdef
、#ifndef
的方式,为 Windows、Mac 等不同 OS 编译不同的代码。
uni-app
团队参考这个思路,为 uni-app
提供了条件编译手段,在一个工程里优雅的完成了平台个性化实现。
条件编译
环境变量
uni-app 项目中配置环境变量主要有如下三种方式:
- vue-config.js:可以修改 webpack 配置,包括环境变量,具体参考 vue-config.js。
- package.json:在 package.json 文件的 env 节点下配置环境变量,具体参考 package.json
- .env:
HBuilderX
中的uni-app vue3
和uni-app x (4.25+)
项目及CLI
创建的项目中可以在根目录中放置.env
文件来指定环境变量,具体参考:Vue2,Vue3。
编译器 配置
可以通过如下入口,对uni-app
编译器进行配置:
- 在 manifest.json 中可以配置Vue的版本以及发行H5平台路由模式,详见: manifest.json
- 在 vue.config.js 中可以修改 webpack 配置,包括环境变量,具体参考 vue-config.js。
- 在 vite.config.js 中可以修改 Vite 配置,包括环境变量,具体参考 vite.config.js。
- 在自定义条件编译平台时,可以在 package.json 文件的 env 节点下配置环境变量,具体参考 package.json
- .env:CLI 创建的项目中可以在根目录中放置
.env
文件来指定环境变量,具体参考:环境变量。
web 专题
跨域
宽屏适配
1. 页面窗体级适配方案:leftWindow、rightWindow、topWindow
SSR 服务端渲染
前端网页托管
App 专题
App 专题:https://uniapp.dcloud.net.cn/tutorial/nvue-outline.html
nvue 原生渲染
HTML5Plus
Native.js
renderjs
开发鸿蒙应用
原生插件
App的User Agent
App使用高斯模糊
App 打包配置
App 本地打包
App 加固
App 隐私合规检测
App 上架注意
App升级
小程序 专题
小程序 专题 :https://uniapp.dcloud.net.cn/tutorial/miniprogram-subject.html
组件与WXS
使用小程序插件
开发小程序插件
一键上传微信平台
小程序隐私协议
uni 错误规范
性能优化 专题
uni 安全 专题
uni 安全 专题:https://uniapp.dcloud.net.cn/tutorial/safe.html
国际化 专题
国际化开发指南
uni-app的国际化,即多语言,分为应用部分和框架部分。
- 应用部分,即开发者自己的代码里涉及的界面部分
- 框架部分,即uni-app内置组件和API涉及界面的部分
不同端的国际化方案也有差异,uni-app 自 3.1.5起,App 和 H5 支持框架国际化。小程序平台的国际化依赖于小程序平台框架自身。一般而言海外用户更多使用的是App和H5。
可以在HBuilderX新建项目里选择Hello i18n
示例或者插件市场查看hello-i18n 示例工程 - DCloud 插件市场
海外开发者使用指南
因中国法律的要求,开发者使用HBuilderX进行云端打包时,需完成手机号验证,但目前DCloud仅支持中国大陆地区手机号的验证,其它地区的手机号暂不支持。
DCloud为支持海外开发者,特推出“国际区”注册服务,注册在“国际区”的账号,仅需验证邮箱,即可使用云端打包服务。
3、全局文件
pages.json 页面路由
manifest.json 应用配置
AndroidManifest.xml(安卓原生配置)
Info.plist(iOS原生配置)
App.vue/uvue
main.js/uts
uni.scss
package.json
vue.config.js
vite.config.js
4、组件 ( 控件 )
组件使用的入门教程
- 组件是视图层的基本组成单元。
- 组件是一个单独且可复用的功能模块的封装。
每个组件,包括如下几个部分:以组件名称为标记的开始标签和结束标签、组件内容、组件属性、组件属性值。
- 组件名称由尖括号包裹,称为标签,它有开始标签和结束标签。结束标签的
<
后面用/
来表示结束。结束标签也称为闭合标签。如下面示例的<component-name>
是开始标签,</component-name>
是结束标签。 - 在开始标签和结束标签之间,称为组件内容。如下面示例的
content
- 开始标签上可以写属性,属性可以有多个,多个属性之间用空格分割。如下面示例的
property1
和property2
。注意闭合标签上不能写属性。 - 每个属性通过
=
赋值。如下面的示例中,属性property1
的值被设为字符串value
。
注意:所有组件与属性名都是小写,单词之间以连字符
-
连接。
组件概述
内置组件
uni-app 组件
视图容器
基础内容
表单组件
路由与页面跳转
媒体组件
地图
画布
webview
广告
uniCloud-db云数据库:https://doc.dcloud.net.cn/uniCloud/unicloud-db.html
页面属性配置节点
基础组件中原生组件说明:https://uniapp.dcloud.net.cn/component/native-component.html
Vue 组件
NVUE 组件
小程序组件
扩展组件(uni-ui)
uni-ui 是DCloud提供的一个跨端ui库,它是基于vue组件的、flex布局的、无dom的跨全端ui框架。
uni-ui
不包括内置组件,它是内置组件的补充。目前为止,在小程序和混合app领域,uni-ui是性能的标杆。
- 介绍
- 项目中使用 uni-ui 库
- 色彩说明
- uni-sass 辅助样式
- uni-badge 数字角标
- uni-breadcrumb 面包屑
- uni-calendar 日历
- uni-card 卡片
- uni-collapse 折叠面板
- uni-combox 组合框
- uni-countdown 倒计时
- uni-data-checkbox 数据选择器
- uni-data-picker 级联选择器
- uni-data-select 下拉框
- uni-dateformat 日期格式化
- uni-datetime-picker 日期选择器
- uni-drawer 抽屉
- uni-easyinput 增强输入框
- uni-fab 悬浮按钮
- uni-fav 收藏按钮
- uni-file-picker 文件选择上传
- uni-forms 表单
- uni-goods-nav 商品导航
- uni-grid 宫格
- uni-group 分组
- uni-icons 图标
- uni-indexed-list 索引列表
- uni-link 超链接
- uni-list 列表
- uni-load-more 加载更多
- uni-nav-bar 自定义导航栏
- uni-notice-bar 通告栏
- uni-number-box 数字输入框
- uni-pagination 分页器
- uni-popup 弹出层
- uni-rate 评分
- uni-row 布局-行
- uni-search-bar 搜索栏
- uni-section 标题栏
- uni-segmented-control 分段器
- uni-steps 步骤条
- uni-swipe-action 滑动操作
- uni-swiper-dot 轮播图指示点
- uni-table 表格
- uni-tag 标签
- uni-title 章节标题
- uni-tooltip 文字提示
- uni-transition 过渡动画
- 更新日志
- 更多插件市场的组件
ui 设计资源
提供uni-ui组件的Sketch设计资源,您可以根据需要进行下载。
Axure资源正在整理和完善中。
在Sketch中快速调用常用组件,在提升设计效率的同时,保证统一的视觉风格
如果你需要专业美工帮你做设计或UI美化,可以咨询DCloud官方的UI设计及美工服务。
datacom 组件规范
datacom
,全称是data components
,数据驱动的组件。这种组件也是vue组件,是一种子类,是基础组件的再封装。相比于普通的vue组件,datacom
组件的特点是,给它绑定一个data,data中包含一组候选数据,即可自动渲染出结果。比如 uni-data-checkbox 组件,给它绑定一个data,即可直接生成一组选择框。
小程序自定义组件
uni-app
在支持vue组件之外,也实现了对小程序自定义组件的兼容。小程序组件不是vue组件,并且每家小程序都有自己的组件规范,比如微信小程序的组件是wxml格式。小程序组件不是全端可用,支持度最广的微信小程序自定义组件,也只能支持微信小程序、app-vue、web,其他平台无法兼容。如果需求上只需兼容有限平台,也可以使用小程序组件。否则仍然推荐使用vue组件。
要求开发者对各端小程序的自定义组件有一定了解,没接触过小程序自定义组件的可以参考:
组件库选型指南
组件是现代开发的重要里程碑。组件重构了分工模型,让大量的轮子出现,让开发者可以拿来轮子直接用,大幅提升了整个产业的效率。
uni-app是有内置组件的。这和web开发不一样。 web开发基本上不用基础组件,都是找一个三方ui库,全套组件都包含。那是因为html的基础组件默认样式不适配手机风格。 但uni-app体系不是这样,内置组件就是为手机优化的。
但内置组件只能满足基础需求,更多场景,需要扩展组件。 扩展组件是基于内置组件的二次封装,从性能上来讲,扩展组件的性能略低于内置组件,所以开发者切勿抛弃内置组件,直接全套用三方UI组件库。
uni-app的插件市场,有很多扩展组件,有的是单独的,有的是成套的。 有些开发者喜欢成套的组件,但注意成套扩展组件也不可能覆盖所有需求,很多场景还是需要单独下载专业组件。
插件市场,https://ext.dcloud.net.cn,有各种玲琅满目的组件、模板。 其中成套的全端兼容ui库包括:
- uViewUI:整合了非常多组件,功能丰富、文档清晰,但不支持nvue(2.x已支持nvue)
- colorUI css库:颜值很高,css库而非组件
- unify UI:全端支持的组件库,侧重nvue(商城已下架)
- mypUI:全端支持的组件库,侧重nvue
- ThorUI组件库
- graceUI商业库
官方对组件的使用建议是:
- 首先使用内置组件
- 然后使用uni ui扩展组件
- 其他需求依靠插件市场其他组件灵活补充
5、API
uni-app
的 js API 由标准 ECMAScript 的 js API 和 uni 扩展 API 这两部分组成。
标准 ECMAScript 的 js 仅是最基础的 js。浏览器基于它扩展了 window、document、navigator 等对象。小程序也基于标准 js 扩展了各种 wx.xx、my.xx、swan.xx 的 API。node 也扩展了 fs 等模块。
uni-app 基于 ECMAScript 扩展了 uni 对象,并且 API 命名与小程序保持兼容。
标准 js 和浏览器 js 的区别
uni-app
的 js 代码,web 端运行于浏览器中。非 web 端(包含小程序和 App),Android 平台运行在 v8 引擎中,iOS 平台运行在 iOS 自带的 jscore 引擎中,都没有运行在浏览器或 webview 里。非 web 端,虽然不支持 window、document、navigator 等浏览器的 js API,但也支持标准 ECMAScript。
请注意不要把浏览器里的 js 等价于标准 js。
所以 uni-app 的非web端,一样支持标准 js,支持 if、for 等语法,支持字符串、数字、时间、布尔值、数组、自定义对象等变量类型及各种处理方法。仅仅是不支持 window、document、navigator 等浏览器专用对象。
各端特色 API 调用
除了 uni-app 框架内置的跨端 API,各端自己的特色 API 也可通过条件编译自由使用。
各端特色 API 规范参考各端的开发文档。其中 App 端的 JS API 参考html5plus.org;uni-app 也支持通过扩展原生插件来丰富 App 端的开发能力,具体参考插件开发文档
各平台的 API 新增,不需要 uni-app 升级,开发者就可以直接使用。
各平台 API 独有的字段,如快手小程序
ks.pay
的payType
、paymentChannel
字段,开发者在调用 API 时正常传入即可,会透传至快手小程序的 API 上
补充说明
- uni.on 开头的 API 是监听某个事件发生的 API 接口,接受一个 CALLBACK 函数作为参数。当该事件触发时,会调用 CALLBACK 函数。
- 如未特殊约定,其他 API 接口都接受一个 OBJECT 作为参数。
- OBJECT 中可以指定 success,fail,complete 来接收接口调用结果。
- 平台差异说明若无特殊说明,则表示所有平台均支持。
- 异步 API 会返回
errMsg
字段,同步 API 则不会。比如:getSystemInfoSync
在返回结果中不会有errMsg
。
API Promise 化
具体 API Promise 化
的策略:
-
异步的方法,如果不传入 success、fail、complete 等 callback 参数,将以 Promise 返回数据。例如:
uni.getImageInfo()
-
异步的方法,且有返回对象,如果希望获取返回对象,必须至少传入一项 success、fail、complete 等 callback 参数。例如:
// 正常使用
const task = uni.connectSocket({
success(res){
console.log(res)
}
})
// Promise 化
uni.connectSocket().then(res => {
// 此处即为正常使用时 success 回调的 res
// uni.connectSocket() 正常使用时是会返回 task 对象的,如果想获取 task ,则不要使用 Promise 化
console.log(res)
})
不进行 Promise 化
的 API:
- 同步的方法(即以 sync 结束)。例如:
uni.getSystemInfoSync()
- 以 create 开头的方法。例如:
uni.createMapContext()
- 以 manager 结束的方法。例如:
uni.getBackgroundAudioManager()
Vue 2 和 Vue 3 项目中 API Promise 化
返回格式不一致,以下为 不同点
和 返回格式互相转换
不同点
- Vue2 对部分 API 进行了 Promise 封装,返回数据的第一个参数是错误对象,第二个参数是返回数据。此时使用
catch
是拿不到报错信息的,因为内部对错误进行了拦截。 - Vue3 对部分 API 进行了 Promise 封装,调用成功会进入
then 方法
回调。调用失败会进入catch 方法
回调
// 默认方式
uni.request({
url: "https://www.example.com/request",
success: (res) => {
console.log(res.data);
},
fail: (err) => {
console.error(err);
},
});
// Promise
uni
.request({
url: "https://www.example.com/request",
})
.then((data) => {
// data为一个数组
// 数组第一项为错误信息 即为 fail 回调
// 第二项为返回数据
var [err, res] = data;
console.log(res.data);
});
// Await
async function request() {
var [err, res] = await uni.request({
url: "https://www.example.com/request",
});
console.log(res.data);
}
-
返回格式互相转换
// Vue 2 转 Vue 3, 在 main.js 中写入以下代码即可
function isPromise(obj) {
return (
!!obj &&
(typeof obj === "object" || typeof obj === "function") &&
typeof obj.then === "function"
);
}
uni.addInterceptor({
returnValue(res) {
if (!isPromise(res)) {
return res;
}
return new Promise((resolve, reject) => {
res.then((res) => {
if (res[0]) {
reject(res[0]);
} else {
resolve(res[1]);
}
});
});
},
});
API 列表
uniCloud客户端sdk 完整 api:https://doc.dcloud.net.cn/uniCloud/client-sdk.html
基础
网络
官网文档中,请求的 header 中 content-type 默认为 application/json。如果是图片,需要改成 image/jpeg
示例:
使用 aioxs,返回 promise
页面跳转、页面路由
navigator组件类似HTML中的<a>组件,但只能跳转本地页面。目标页面必须在pages.json中注册。除了组件方式,API方式也可以实现页面跳转:uni.navigateTo(OBJECT) | uni-app官网
数据缓存
位置
媒体
设备
Worker ( 多线程 )
目前需分平台编写
键盘
界面
文件
绘画
广告
第三方服务
重要开源库
- uni-config-center 配置中心
- uni-starter
- uni-admin
- uni-upgrade-center App升级中心
uni-pay 统一支付
- uni-cms 内容管理
- uni-ai-chat ai聊天示例
- uni-im 即时通信
- uni-ad-admin
- uSearch 云端一体搜索
- uni-captcha 图形验证码
- uni-sec-check 内容安全
- 统一发行页面
- uni-cloud-router
- uni-open-bridge 微信支付宝等三方凭据管理
- uni-cloud-s2s 传统服务器与uniCloud安全通信
- uni-subscribemsg 订阅消息发送
uni-map 地图
其他
uni ext api
uni ext api,是一种需要下载uni_modules插件才能使用的、uni.开头的js API。
它是uni对象的方法,但不预置在uni-app的runtime中,需要单独下载对应的uni_modules
示例:
uni.getBatteryInfo,这个API就是一个ext api
,需要下载插件才能使用。详见
- 背景1,uni-app runtime越来越大
uni对象的api,如uni.navigateTo,之前都是内置在uni-app的runtime中的,跟随uni-app/HBuilder的升级而变化。
随着各家小程序和uni-app的演进,uni-app的api越来越多,而很多api又不常用,这会增加uni-app的runtime体积,尤其是在web和app平台。
比如很多小程序都内置有getBatteryInfo
获取电量的API,在uni-app中理应拉齐各端实现,但在uni-app的web和app上内置它并不合适。
所以推出了uni ext api
,这些API以uni_modules
的方式出现,从插件市场单独下载。但导入到工程后,仍使用uni.getBatteryInfo
方式来调用。
为此,在这些uni_modules
的package.json
中提供了一种特殊的注册方式,允许插件向uni对象自动挂载api。(只有DCloud官方插件,以uni-
开头的插件,才能使用此机制)
- 背景2,uts将重构uni-app的内部实现
在过去,uni-app的web和小程序端,是github的独立项目,由DCloud的js团队维护。而uni-app的app端,是另2个独立项目,由DCloud的原生团队维护。 每次新加一个api,需要各个团队在不同的工程里开发,尤其是app端,需要先在原生项目里开发,然后在前端项目里封装。还需要再另一个语法提示工程中编写代码提示。
有了uts后,uni-app的实现机制将被重构,大幅的简化。
每个api,都使用uts这门统一的语言来开发,不再使用不同的技术语言。作为一个独立的uni_modules
,独立的工程,有独立的版本。
仍然以uni.getBatteryInfo
电量为例,开发这个api,不再需要在庞大复杂的uni-app的若干个项目里编码,也不需要再关心功能间关联和耦合。
只需要在uni-getBatteryInfo
这个uni_modules
下开发,目录结构如下。
这个目录清晰的列出了这个插件要做的所有事情:在不同的目录下编写uts或js代码、在d.ts里写语法提示。
├── uni_modules
│ ├── uni-getbatteryinfo
│ │ ├── changelog.md
│ │ ├── index.d.ts // 类型声明,需要同时扩展 uni 声明当前注册的 API,将废弃,使用interface.uts代替
│ │ ├── interface.uts // 声明插件对外暴露的API及类型
│ │ ├── package.json
│ │ ├── readme.md
│ │ └── utssdk // 在不同目录实现平台能力
│ │ ├── app-android
│ │ │ └── index.uts
│ │ ├── app-ios
│ │ │ └── index.uts
│ │ ├── mp-weixin
│ │ │ └── index.js
│ │ └── web
│ │ └── index.js
这种模式,还给开发者带来若干好处,比如开放性和灵活性。
- 以往,uni-app内置api如果有bug,普通开发者很难看懂源码,很难参与完善。
现在,在uts的支持下,普通前端也可以review这些api的实现,发现其中的问题和提出改进方案。
- 以往,这些uni api的bug被修复时,需要等待HBuilder发版,由于每次发版都需要发很多功能,可能bug1虽然已经修好,但bug2复测出问题,导致版本不能及时发布。
现在,ext api的uni_modules
脱离HBuilder独立升级,快速解决开发者的问题。并且开发者可以自己修本地工程中ext api的bug。让问题得以更快速的解决。
- 背景3,内置api复写
很多uni的内置api,比如uni.showWaiting
,实现的比较简单,在web端,常见的waiting都有更丰富的样式、使用更多的图片资源。
uni-app的runtime不适合内置很多waiting样式和资源,而使用三方插件,又需要按三方插件的写法调用,之前工程里写好的uni.showWaiting
的代码不得不重改。
有了ext api
,可以实现一个uni-showwaiting
的uni_modules
,在web端提供更丰富的效果,并且开源,可自由裁剪和增补。
导入这个uni_modules
后,之前的uni.showWaiting
的api的功能就被复写。
综上,背景1、2、3的问题,都将使用uni ext api
来解决。uni-app很多新增的、不常用的api将采用ext api
方式。
在uts的发展路线上,uni-app自身也将使用uts实现;使用uts将可以开发完整的uni-app。
目前所有的ext api
,在未来的uts版的uni-app,其内置的uni对象的api中,均会得到复用。也就是说ext api
将大幅推进下一代uni-app(纯uts版)的上线速度。
欢迎广大开发者参与到uni ext api
的开源共建中来。
6、插件
插件 市场
DCloud有活跃的插件市场,DCloud 插件市场,并提供了变现、评价等机制。
DCloud插件市场将插件分为前端组件、JS SDK、uni-app前端模板、App原生插件、uniCloud等7大类、20多个子类,你可以根据需要进行筛选查询。
插件市场 | 一级分类 | 二级分类 |
DCloud市场 | 前端组件 | 通用组件 |
nvue组件 | ||
小程序组件 | ||
DataCom组件 | ||
JS SDK | 通用SDK | |
微信小程序SDK | ||
Navive.js | ||
uts插件 | API插件 | |
组件插件 | ||
uni-app前端模板 | 前端页面模板 | |
nvue页面模板 | ||
uni-app前端项目模板 | ||
App原生插件 | App原生插件 | |
web项目 | web项目模板 | |
uniCloud | 云函数模板 | |
云端一体页面模板 | ||
云端一体项目模板 | ||
Admin插件 | ||
DB Schema及验证函数 | ||
HBuilderX | HBuilderX | |
语言包 |
DCloud的插件市场还提供了优秀作者及热门插件排行榜,欢迎大家客观评价自己使用过的插件,帮助作者完善插件,共同创造正向的插件市场。
除了排行榜这种荣誉激励,DCloud还支持对uniCloud插件、uts/原生插件设置付费销售,对免费插件设置先看广告后下载,帮助插件作者进行技术变现。
插件市场的付费插件支持UTS插件
、App原生插件
、uniCloud
、前端组件
三大分类。
UTS插件
、App原生插件
、前端组件
是客户端插件,UTS插件
和App原生插件
付费插件仅支持购买后提交云端打包,前端组件
还支持发行web,三种分类购买时均需绑定项目appid及包名。
uniCloud
插件是云端插件,绑定uniCloud服务空间的spaceId。
uniCloud
、UTS插件
及前端组件
三个分类的付费模式分为 普通授权版
和 源码授权版
。
提供2个版本是为了给插件交易提供更多选择,在产权保护、插件售价方面取得平衡。
普通授权版的价格相对便宜,其中会有部分或全部源码不可见。uts插件是全部uts代码不可见,uniCloud插件则取决于插件作者的配置那些云函数加密。uniCloud分类会在插件主页会显示哪些云函数被加密了。
版本名称 | 代码保护 | 授权 | 交易方式 |
---|---|---|---|
普通授权版 | 部分源码不可见 | 提供基于该项目和/或该服务空间的使用权、未加密部分的二次开发权 | 买方自助下单,即买即用。买方实名信息对卖方保密 |
开源授权版 | 所有代码源码可见 | 提供基于该项目和/或该服务空间的使用权、完整的二次开发权、完整可控的基于源码审查的安全性 | 签署带数字签名的三方电子协议,各方实名交易,插件作者可拒绝交易,先签协议后买方再付款获取源码 |
上表中可以看出,插件用户支付不同的价格,购买到的授权内容也不一样。并且源码授权版
的购买流程也更复杂一些。
但两个版本的功能是一样的。因为它们实际上是一套代码,只是源码可见还是不可见而已。
插件作者在上传插件时,可以只选择普通授权版
,源码授权版
是可选项。插件作者也可以拒绝与某个潜在买家签订源码授权版
的电子合同。
插件作者可以配置需加密文件的清单,除非插件用户购买源码授权版
,否则看不到加密部分的文件源码。不管是试用还是购买普通授权版,都看不到加密文件的源码。
付费插件均提供试用:
-
UTS插件
针对项目进行申请试用。试用虽然下载了插件,但插件内容对试用者而言不可见。试用的插件只能用于打包自定义基座,不能用于正式发布。试用没有有效期限制。 -
App原生插件
针对项目进行申请试用,插件不下载,试用的插件只能用于云端打包自定义基座,不能用于正式发布。试用没有有效期限制。 -
uniCloud
插件针对服务空间进行申请试用,试用时被加密的云函数对试用者而言不可见。试用期可以加密云函数部署到指定的服务空间进行体验,但试用期结束后这些加密云函数会被自动删除。(试用期一般是7天,具体见试用时界面向导的提示) -
前端组件
针对项目进行申请试用,试用虽然下载了插件,但插件内容对试用者而言不可见。试用的插件只能用于本地运行或打包自定义基座,不能用于正式发布。试用没有有效期限制。
uts插件比App原生插件有更多优势:
- uts插件更小巧
- 插件作者更新uts插件免审核,无需等待DCloud管理员审核上架
- uts插件天然支持多版本,插件作者更新后,使用者可以不更新,可以仍然使用之前下载到本地的老版插件
- uts插件支持源码版计费,使用者可以审查源码,控制安全问题,也可以二开
uni_modules
什么是 uni_modules
主流的语言/平台,都有自己包管理方案,js有npm、yarn或pnpm、Android有仓储、iOS有cocoapods、鸿蒙有ohpm、dart有pub。。。
uni-app是大一统开发,包括客户端和uniCloud服务器。在客户端部分包括web、Android、iOS、各家小程序。
在uni-app中可以调用npm库,可以调用Android仓储里的aar,可以调用iOS的cocoapods里framework,以及鸿蒙的ohpm。
甚至uts语言本身也可以编译为js、kotlin、swift。
那么uni-app的开发者,需要一个大一统的包管理方案,那就是uni_modules
。
uni_modules
是uni-app的包管理方案(HBuilderX 3.1.0+支持),它是一个海纳百川型的设计,
- 不管是js/uts库、组件、页面、uniCloud云函数、公共模块等的封装,甚至是整个项目,都可以封装成一个
uni_modules
。(类似Android的aar) - 不管是npm、Android仓储、iOS的cocoapods、鸿蒙的ohpm,都可以纳入
uni_modules
中。
由于uni-app有自己的项目目录结构规范(uni-app详见、uni-app x详见), 所以你可以简单理解,把一个项目的这些工程目录都挪到了一个uni_modules下,打包成了一个模块,这里面只要符合uni-app规范的文件都可以放。
详细的uni_modules目录结构见下
uni_modules的优势
- uni_modules支持在插件市场计费销售。由DCloud提供商业插件的代码加密和版权保护。
- HBuilderX提供了对
uni_modules
的便捷管理,可以对一个uni_modules
点右键(如果是项目型uni_modules
,是对根目录的package.json点右键),直接上传uni_modules
、更新uni_modules
、安装依赖。版本更新时还会给出新旧代码的详细对比。
与之前插件市场的普通插件相比,uni_modules
有何优势?
- 支持在HBuilderX里直接发布、更新、删除。而无需在web界面操作。
- 支持依赖(在package.json中配置)
- 插件文件位置统一。以往下载一个插件,不知道给工程下多少个目录写入了多少个文件,这种困惑不再存在。删除插件时也可以一处统一删除
有node_modules
了,为何还发明一个uni_modules
的轮子?
node_modules
不满足全平台包管理需求,无法容纳Android仓储、iOS的cocoapods、鸿蒙的ohpm。node_modules
不满足云端一体的需求。uniCloud的云函数、公共模块、schema和前端部分,无法在node_modules
模式下有效融合。很多组件是云端一体组件,即有客户端又有服务器,需要按uni-app的目录规范放置。uni_modules
有付费和商业的插件,DCloud插件市场提供了版权保护。而node_modules
不支持付费和版权保护。node_modules
层层嵌套node_modules
,造成数量惊人的文件数目。uni_modules
支持依赖但不支持module嵌套,鼓励开发者优化包体积。当然这算差异,并非uni_modules
的优势uni_modules
在js支持的平台,也容纳了node_modules
,没有排斥。
除了发布插件,uni_modules
同时也是一种大型工程的模块分割方案。比如一个旅游应用,可以把机票、酒店、火车票、自由行等模块分拆成不同的uni_modules
,由不同的部门来开发。
uts 插件
原生语言插件
uni-app在App侧的原生扩展插件,支持使用java、object-c等原生语言编写。
从HBuilderX 3.6起,新增支持了使用uts来开发原生插件。文档另见uts插件
为了和uts插件区别,之前的App原生插件
,改名为App原生语言插件
。
本文为App原生语言插件
的开发文档。
插件发布、变现
更多推荐
所有评论(0)