Appearance
UniApp 页面
1. 页面简介
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,不支持透明。
2. 页面管理
2.1. 新建页面
uni-app 中的页面,默认保存在工程根目录下的 pages 目录下。
每次新建页面,均需在 pages.json 中配置 pages 列表;未在 pages.json -> pages 中注册的页面,uni-app 会在编译阶段进行忽略。pages.json 的完整配置参考:页面配置。
通过 HBuilderX 开发 uni-app 项目时,在 uni-app 项目上右键 “新建页面”,HBuilderX 会自动在 pages.json 中完成页面注册,开发更方便。
同时,HBuilderX 还内置了常用的页面模板(如图文列表、商品列表等),选择这些模板,可以大幅提升你的开发效率。

新建页面时,可以选择是否创建同名目录。创建目录的意义在于:
- 如果你的页面较复杂,需要拆分多个附属的 js、css、组件等文件,则使用目录归纳比较合适;
- 如果只有一个页面文件,大可不必多放一层目录;
2.2. 删除页面
删除页面时,需做两件工作:
删除
.vue、.nvue和.uvue文件。删除
pages.json->pages列表项中的配置(如使用 HBuilderX 删除页面,会在状态栏提醒删除pages.json对应内容,点击后会打开pages.json并定位到相关配置项)。
2.3. 页面改名
操作和删除页面同理,依次修改文件和 pages.json。
2.4. pages.json
pages.json 是工程的页面管理配置文件,包括:页面路由注册、页面参数配置(原生标题栏、下拉刷新 …)、首页 tabbar 等众多功能。
其篇幅较长,另见 pages.json。
2.5. 设置应用首页
pages.json -> pages 配置项中的第一个页面,作为当前工程的首页(启动页)。
JSON
{
"pages": [
{
"path": "pages/index/index", // 名字叫不叫 index 无所谓,位置在第一个,就是首页
"style": {
"navigationBarTitleText": "首页" // 页面标题
}
},
{
"path": "pages/my",
"style": {
"navigationBarTitleText": "我的"
}
}
]
}3. 页面内容构成
uni-app 页面基于 vue 规范。一个页面内,有 3 个根节点标签:
- 模板组件区
<template>; - 脚本区
<script>; - 样式区
<style>;
HTML
<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>3.1. 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 可以有多个二级节点,省去一个层级,如下:
HTML
<template>
<view>
<text>标题</text>
</view>
<scroll-view> </scroll-view>
</template>可以在 manifest 中切换使用 Vue2 还是 Vue3。
提示
uni-app x 中只支持 Vue3。
3.2. script 脚本区
script 中编写脚本,可以通过 lang 属性指定脚本语言。
- 在 vue 和 nvue 中,默认是 js,可以指定 ts;
- 在 uvue 中,仅支持 uts,不管
script的lang属性写成什么,都按 uts 编译;
HTML
<script lang="ts">
</script>在 vue 的选项式(option)规范中,script 下包含 export default {}。除了选项式,还有组合式写法。
页面级的代码大多写在 export default {} 中。写在里面的代码,会随着页面关闭而关闭。
3.2.1. export default 外的代码
写在 export default {} 外面的代码,一般有几种情况:
- 引入第三方 js/ts 模块;
- 引入非 easycom 的组件(一般组件推荐使用 easycom,无需导入注册);
- 在 ts/uts 中,对
data进行类型定义; - 定义作用域更大的变量;
HTML
<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生命周期进行处理。
3.2.2. export default 里的代码
export default {} 里的内容,是页面的主要逻辑代码。包括几部分:
如下页面代码的逻辑是:
在
data中定义了title,初始值是"点我"。在页面中放置了一个
button组件,按钮文字区使用{{}}模板写法,里面写title,把data里的title绑定到按钮的文字区,即按钮的初始文字是"点我"。按钮的点击事件
@click,指向了methods里的一个方法buttonClick,点击按钮即触发这个方法的执行。buttonClick方法里通过this.title的方式,访问data数据,并重新赋值为"被点了"。由于 vue 中data和界面是双向绑定,修改data中的title后,因为按钮文字绑定了title,会自动更新按钮的文字。
整体效果就是,刚开始按钮文字是 "点我",点一下后按钮文字变成了 "被点了"。
HTML
<template>
<view>
<button @click="buttonClick">{{ title }}</button>
</view>
</template>
<script>
export default {
data() {
return {
title: "点我", // 定义绑定在页面上的 data 数据
// 多个 data 在这里继续定义。逗号分隔
};
},
onLoad() {
// 页面启动的生命周期,这里编写页面加载时的逻辑
},
// 多个页面生命周期监听,在这里继续写。逗号分隔
methods: {
buttonClick: function () {
this.title = "被点了";
},
// 多个方法,在这里继续写。逗号分隔
},
};
</script>本章节为页面代码介绍,并非 vue 教程,了解 data 数据需详见。
3.3. style 样式区
style 的写法与 web 的 css 基本相同。
如果页面是 nvue 或 uvue,使用原生渲染而不是 webview 渲染,那么它们支持的 css 是有限的。
详见 css 文档。
4. 页面生命周期
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+ |
4.1. Vue2 页面及组件生命周期流程图

4.2. Vue3 页面及组件生命周期流程图

4.3. 页面加载时序介绍
接下来我们介绍 onLoad、onReady、onShow 的先后关系,页面加载的详细流程。
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 渲染的速度。
4.4. 页面加载常见问题
了解了页面加载时序原理,我们就知道如何避免页面加载常见的问题:
优化白屏的方法:
页面 dom 太多,注意有的组件写的不好,会拖累整体页面。uni-app x 里减少 dom 数量的策略,详见。
联网不要在
onReady里,那样太慢了,在onLoad里早点联网。在
pages.json里配置原生导航栏和背景色。有的页面
template内容非常少,整页就是一个需要联网加载的列表,这会造成虽然首批 dom 飞快渲染了,但页面其实还是白的,联网后才能显示字和图。此时需要在template里做一些简单占位组件,比如loading组件、骨架屏,让本地先显示一些内容。
卡住动画不启动的原因:
页面 dom 太多,注意有的组件写的不好,会拖累整体页面。uni-app x 里减少 dom 数量的策略,详见。
onLoad里执行了耗时的同步计算。
4.5. onShow 和 onHide
注意页面显示,是一个会重复触发的事件。
a 页面刚进入时,会触发 a 页面的 onShow。
当 a 跳转到 b 页面时,a 会触发 onHide,而 b 会触发 onShow。
但当 b 被关闭时,b 会触发 onUnload,此时 a 再次显示出现,会再次触发 onShow。
在 tabbar 页面(指 pages.json 里配置的 tabbar),不同 tab 页面互相切换时,会触发各自的 onShow 和 onHide。
4.6. onInit
注意:
- 仅百度小程序基础库 3.260 以上支持
onInit生命周期; - 其他版本或平台可以同时使用
onLoad生命周期进行兼容,注意避免重复执行相同逻辑; - 不依赖页面传参的逻辑可以直接使用
created生命周期替代;
4.7. onLoad
uni-app x android 平台,如需获取 activity 实例,此时当前页面的 activity 实例并未创建完成,会获取到上一个页面的 activity 实例(首页会获取应用默认的 activity 实例)。如需获取当前页面的 activity 实例,应在 onShow 或 onReady 生命周期中获取。
4.8. onReachBottom
可在 pages.json 里定义具体页面底部的触发距离 onReachBottomDistance。
比如设为 50,那么滚动页面到距离底部 50px 时,就会触发 onReachBottom 事件。
如使用 scroll-view 导致页面没有滚动,则触底事件不会被触发。scroll-view 滚动到底部的事件请参考 scroll-view 的文档。
4.9. onPageScroll
参数说明:
| 属性 | 类型 | 说明 |
|---|---|---|
scrollTop | Number | 页面在垂直方向已滚动的距离(单位 px) |
JavaScript
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 中设置固定位置)
4.10. onBackPress
参数说明:
| 属性 | 类型 | 说明 |
|---|---|---|
from | String | 触发返回行为的来源:backbutton - 左上角导航栏按钮及安卓返回键;navigateBack - uni.navigateBack() 方法。(支付宝小程序端不支持返回此字段) |
JavaScript
export default {
onBackPress(options) {
console.log("from:" + options.from);
},
};注意:
onBackPress上不可使用async,会导致无法阻止默认返回;iOS 端侧滑返回不会触发
onBackPress;支付宝小程序只有真机可以监听到非
navigateBack引发的返回事件(使用小程序开发工具时不会触发onBackPress),不可以阻止默认返回行为;
详细说明及使用:onBackPress 详解。
4.11. onTabItemTap
参数说明:
| 属性 | 类型 | 说明 |
|---|---|---|
index | Number | 被点击 tabItem 的序号,从 0 开始 |
pagePath | String | 被点击 tabItem 的页面路径 |
text | String | 被点击 tabItem 的按钮文字 |
JavaScript
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后触发,因此不能用于实现点击返回顶部这种操作。
4.12. onNavigationBarButtonTap
参数说明:
| 属性 | 类型 | 说明 |
|---|---|---|
index | Number | 原生标题栏按钮数组的下标 |
JavaScript
onNavigationBarButtonTap: function (e) {
console.log(e);
// e 的返回格式为 json 对象:{"text":"测试","index":0}
}注意:
- nvue 页面 weex 编译模式支持的生命周期同 weex,具体参考:weex 生命周期介绍。
5. 组件生命周期
uni-app 组件支持的生命周期,与 vue 标准组件的生命周期相同。这里没有页面级的 onLoad 等生命周期:
| 函数名 | 说明 | 平台差异说明 | 最低版本 |
|---|---|---|---|
beforeCreate | 在实例初始化之前被调用。详见 | ||
created | 在实例创建完成后被立即调用。详见 | ||
beforeMount | 在挂载开始之前被调用。详见 | ||
mounted | 挂载到实例上去之后调用。详见 注意:此处并不能确定子组件被全部挂载,如果需要子组件完全挂载之后在执行操作可以使用 $nextTick Vue 官方文档 | ||
beforeUpdate | 数据更新时调用,发生在虚拟 DOM 打补丁之前。详见 | 仅 H5 平台支持 | |
updated | 由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。详见 | 仅 H5 平台支持 | |
beforeDestroy | 实例销毁之前调用。在这一步,实例仍然完全可用。详见 | ||
destroyed | Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。详见 |
6. 页面调用接口
6.1. getApp()
getApp() 函数用于获取当前应用实例,一般用于获取 globalData。也可通过应用实例调用 App.vue methods 中定义的方法。
实例:
JavaScript
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等初始化。
6.2. getCurrentPages()
getCurrentPages() 函数用于获取当前页面栈的实例,以数组形式按栈的顺序给出,数组中的元素为页面实例,第一个元素为首页,最后一个元素为当前页面。
每个页面实例的方法属性列表:
| 方法 | 描述 | 平台说明 |
|---|---|---|
page.$getAppWebview() | 获取当前页面的 webview 对象实例 | App |
page.route | 获取当前页面的路由 |
注意:
getCurrentPages() 仅用于展示页面栈的情况,请勿修改页面栈,以免造成页面状态错误。
页面关闭时,对应页面实例会在页面栈中删除。
Tips:
navigateTo、redirectTo只能打开非tabBar页面;switchTab只能打开tabBar页面;reLaunch可以打开任意页面;- 页面底部的
tabBar由页面决定,即只要是定义为tabBar的页面,底部都有tabBar; - 不能在首页
onReady之前进行页面跳转;
6.3. $getAppWebview()
uni-app 在 getCurrentPages() 获得的页面里内置了一个方法 $getAppWebview() 可以得到当前 webview 的对象实例,从而实现对 webview 更强大的控制。在 html5Plus 中,plus.webview 具有强大的控制能力,可参考:WebviewObject。
但 uni-app 框架有自己的窗口管理机制,请不要自己创建和销毁 webview,如有需求覆盖子窗体上去,请使用原生子窗体 subNvue。
提示
此方法仅 App 支持。
示例:
获取当前页面
webview的对象实例:JavaScriptexport 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对象:JavaScriptvar 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。
7. 页面通讯
7.1. uni.$emit(eventName,OBJECT)
触发全局的自定义事件。附加参数都会传给监听器回调。
| 属性 | 类型 | 描述 |
|---|---|---|
eventName | String | 事件名 |
OBJECT | Object | 触发事件携带的附加参数 |
代码示例:
JavaScript
uni.$emit('update',{msg:'页面更新'})7.2. uni.$on(eventName,callback)
监听全局的自定义事件。事件可以由 uni.$emit 触发,回调函数会接收所有传入事件触发函数的额外参数。
| 属性 | 类型 | 描述 |
|---|---|---|
eventName | String | 事件名 |
callback | Function | 事件的回调函数 |
代码示例:
JavaScript
uni.$on("update", function (data) {
console.log("监听到事件来自 update,携带参数 msg 为:" + data.msg);
});7.3. uni.$once(eventName,callback)
监听全局的自定义事件。事件可以由 uni.$emit 触发,但是只触发一次,在第一次触发之后移除监听器。
| 属性 | 类型 | 描述 |
|---|---|---|
eventName | String | 事件名 |
callback | Function | 事件的回调函数 |
代码示例:
JavaScript
uni.$once("update", function (data) {
console.log("监听到事件来自 update,携带参数 msg 为:" + data.msg);
});7.4. uni.$off(eventName, callback)
移除全局自定义事件监听器。
| 属性 | 类型 | 描述 |
|---|---|---|
eventName | String | 事件名 |
callback | Function | 事件的回调函数 |
Tips:
- 如果没有提供参数,则移除所有的事件监听器;
- 如果只提供了事件,则移除该事件所有的监听器;
- 如果同时提供了事件与回调,则只移除这个回调的监听器;
- 提供的回调必须跟
$on的回调为同一个才能移除这个回调的监听器;
代码示例:
$emit、$on、$off 常用于跨页面、跨组件通讯,这里为了方便演示放在同一个页面:
HTML
<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监听。
8. 路由
uni-app 页面路由为框架统一管理,开发者需要在 pages.json 里配置每个路由页面的路径及页面样式。类似小程序在 app.json 中配置页面路由一样。所以 uni-app 的路由用法与 Vue Router 不同,如仍希望采用 Vue Router 方式管理路由,可在插件市场搜索 Vue-Router。
8.1. 路由跳转
uni-app 有两种页面路由跳转方式:使用 navigator 组件跳转、调用 API 跳转。
注意:
- 页面返回时会自动关闭
loading及toast。modal及actionSheet不会自动关闭; - 页面关闭时,只是销毁了页面实例,未完成的网络请求、计时器等副作用需开发者自行处理;
9. 页面栈
框架以栈的形式管理当前所有页面,当发生路由切换的时候,页面栈的表现如下:
| 路由方式 | 页面栈表现 | 触发时机 |
|---|---|---|
| 初始化 | 新页面入栈 | 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"/> |
10. 页面代码规范介绍
uni-app 支持在 template 模板中嵌套 <template/> 和 <block/>,用来进行条件渲染和列表渲染。
<template/> 和 <block/> 并不是一个组件,它们仅仅是一个包装元素,不会在页面中做任何渲染,只接受控制属性。
<block/> 在不同的平台表现存在一定差异,推荐统一使用 <template/>。
代码示例:
HTML
<template>
<view>
<template v-if="test">
<view>test 为 true 时显示</view>
</template>
<template v-else>
<view>test 为 false 时显示</view>
</template>
</view>
</template>HTML
<template>
<view>
<block v-for="(item,index) in list" :key="index">
<view>{{item}} - {{index}}</view>
</block>
</view>
</template>11. 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 绘制整个页面的耗时要大的多,尤其在新页面进入动画期间,对于复杂页面,没有原生导航栏会在动画期间产生整个屏幕的白屏或闪屏。