English
uni-app项目中,一个页面就是一个符合Vue SFC规范
的 vue 文件。
在 uni-app js 引擎版中,后缀名是.vue
文件或.nvue
文件。
这些页面均全平台支持,差异在于当 uni-app 发行到App平台时,.vue
文件会使用webview进行渲染,.nvue
会使用原生进行渲染,详见:nvue原生渲染。
一个页面可以同时存在vue和nvue,在pages.json的路由注册中不包含页面文件名后缀,同一个页面可以对应2个文件名。重名时优先级如下:
在 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的完整配置参考:页面配置。
When developing a uni-app
project through HBuilderX, right-click on the uni-app
project and "New Page", HBuilderX will automatically complete the page registration in pages.json
, making development more convenient.
At the same time, HBuilderX also has built-in common page templates (such as text lists, product lists, etc.). Choosing these templates can greatly improve your development efficiency.
新建页面时,可以选择是否创建同名目录
。创建目录的意义在于:
删除页面时,需做两件工作:
.vue
文件、.nvue
、.uvue
文件pages.json -> pages
列表项中的配置 (如使用HBuilderX删除页面,会在状态栏提醒删除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": "我的"
}
},
]
}
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中文名为模板
,它类似html的标签。但有2个区别:
script
和 style
是 html 的二级节点。但在 vue 文件中,template
、script
、style
这3个是平级关系。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中编写脚本,可以通过lang属性指定脚本语言。
<script lang="ts">
</script>
在vue的选项式(option)规范中,script下包含 export default {}
。除了选项式,还有 组合式 写法。
页面级的代码大多写在 export default {}
中。写在里面的代码,会随着页面关闭而关闭。
export default
外的代码写在 export default {}
外面的代码,一般有几种情况:
<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 {}
里的内容,是页面的主要逻辑代码。包括几部分:
如下页面代码的逻辑是:
title
,初始值是"点我"{{}}
模板写法,里面写title
,把data里的title
绑定到按钮的文字区,即按钮的初始文字是"点我"@click
,指向了methods里的一个方法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>
本章节为页面代码介绍,并非vue教程,了解data数据需详见
style的写法与web的css基本相同。
如果页面是nvue或uvue,使用原生渲染而不是webview渲染,那么它们支持的css是有限的。
详见css文档
uni-app
页面除支持 Vue 组件生命周期外还支持下方页面生命周期函数,当以组合式 API 使用时,在 Vue2 和 Vue3 中存在一定区别,请分别参考:Vue2 组合式 API 使用文档 和 Vue3 组合式 API 使用文档。
Function name | Instruction | Platform difference description | Minimum version |
---|---|---|---|
onInit | 监听页面初始化,其参数同 onLoad 参数,为上个页面传递的数据,参数类型为 Object(用于页面传参),触发时机早于 onLoad | 百度小程序 | 3.1.0+ |
onLoad | 监听页面加载,该钩子被调用时,响应式数据、计算属性、方法、侦听器、props、slots 已设置完成,其参数为上个页面传递的数据,参数类型为 Object(用于页面传参),参考示例。 | ||
onShow | 监听页面显示,页面每次出现在屏幕上都触发,包括从下级页面点返回露出当前页面 | ||
onReady | 监听页面初次渲染完成,此时组件已挂载完成,DOM 树($el)已可用,注意如果渲染速度快,会在页面进入动画完成前触发 | ||
onHide | listen to page hiding | ||
onUnload | listen to page uninstall | ||
onResize | 监听窗口尺寸变化 | App、微信小程序、快手小程序 | |
onPullDownRefresh | 监听用户下拉动作,一般用于下拉刷新,参考示例 | ||
onReachBottom | The event that a page scrolls to the bottom (not scroll-view to the bottom) is often used to pull down the data on the next page. See the precautions below for details | ||
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 | Listen to the input content change event of search input box of the native title bar | App, H5 | 1.6.0 |
onNavigationBarSearchInputConfirmed | Listen to the search event of search input box of the native title bar, which is triggered when the user clicks the "Search" button on the soft keyboard. | App, H5 | 1.6.0 |
onNavigationBarSearchInputClicked | Listen to the click event of the native title bar search input box (only triggered when the searchInput configuration in pages.json is disabled to true) | App, H5 | 1.6.0 |
onShareTimeline | Monitor users click on the upper right corner to forward to Moments | WeChat MiniApp | 2.8.1+ |
onAddToFavorites | Monitor users click on the upper right corner to save | WeChat MiniApp, QQ MiniApp | 2.8.1+ |
接下来我们介绍onLoad、onReady、onShow的先后关系,页面加载的详细流程。
所以原生导航栏是最快显示的。页面背景色也应该在这里配置。
这里的dom创建仅包含第一批处理的静态dom。对于通过js/uts更新data然后通过v-for再创建的列表数据,不在第一批处理。
要注意一个页面静态dom元素过多,会影响页面加载速度。在uni-app x Android版本上,可能会阻碍页面进入的转场动画。 因为此时,页面转场动画还没有启动。
此时页面还未显示,没有开始进入的转场动画,页面dom还不存在。
所以这里不能直接操作dom(可以修改data,因为vue框架会等待dom准备后再更新界面);在 app-uvue 中获取当前的activity拿到的是老页面的activity,只能通过页面栈获取activity。
onLoad比较适合的操作是:接受上页的参数,联网取数据,更新data。
手机都是多核的,uni.request或云开发联网,在子线程运行,不会干扰UI线程的入场动画,并行处理可以更快的拿到数据、渲染界面。
但onLoad里不适合进行大量同步耗时运算,因为此时转场动画还没开始。
尤其uni-app x 在 Android上,onLoad里的代码(除了联网和加载图片)默认是在UI线程运行的,大量同步耗时计算很容易卡住页面动画不启动。除非开发者显式指定在其他线程运行。
新页面开始进入的转场动画,动画默认耗时300ms,可以在路由API中调节时长。
第2步创建dom是虚拟dom,dom创建后需要经历一段时间,UI层才能完成了页面上真实元素的创建,即触发了onReady。
onReady后,页面元素就可以自由操作了,比如ref获取节点。同时首批界面也渲染了。
注意:onReady和转场动画开始、结束之间,没有必然的先后顺序,完全取决于dom的数量和复杂度。
如果元素排版和渲染够快,转场动画刚开始就渲染好了;
大多情况下,转场动画走几格就看到了首批渲染内容;
如果元素排版和渲染过慢,转场动画结束都没有内容,就会造成白屏。
联网进程从onLoad起就在异步获取数据更新data,如果服务器速度够快,第二批数据也可能在转场动画结束前渲染。
再次强调,5和6的先后顺序不一定,取决于首批dom渲染的速度。
了解了页面加载时序原理,我们就知道如何避免页面加载常见的问题:
注意页面显示,是一个会重复触发的事件。
a页面刚进入时,会触发a页面的onShow。
当a跳转到b页面时,a会触发onHide,而b会触发onShow。
但当b被关闭时,b会触发onUnload,此时a再次显示出现,会再次触发onShow。
在tabbar页面(指pages.json里配置的tabbar),不同tab页面互相切换时,会触发各自的onShow和onHide。
注意
注意
uni-app x android
平台,如需获取 activity 实例,此时当前页面的 activity 实例
并未创建完成,会获取到上一个页面的 activity 实例
(首页会获取应用默认的 activity 实例
)。如需获取当前页面的 activity 实例
,应在 onShow
或 onReady
生命周期中获取。可在pages.json里定义具体页面底部的触发距离onReachBottomDistance,
比如设为50,那么滚动页面到距离底部50px时,就会触发onReachBottom事件。
如使用scroll-view导致页面没有滚动,则触底事件不会被触发。scroll-view滚动到底部的事件请参考scroll-view的文档。
参数说明
Attribute | Type | Instruction |
---|---|---|
scrollTop | Number | 页面在垂直方向已滚动的距离(单位px) |
onPageScroll : function(e) { //nvue暂不支持滚动监听,可用bindingx代替
console.log("滚动距离为:" + e.scrollTop);
},
注意
onPageScroll
里不要写交互复杂的js,比如频繁修改页面。因为这个生命周期是在渲染层触发的,在非h5端,js是在逻辑层执行的,两层之间通信是有损耗的。如果在滚动过程中,频发触发两层之间的数据交换,可能会造成卡顿。(uvue在app端无此限制)参数说明
属性 | 类型 | 说明 |
---|---|---|
from | String | 触发返回行为的来源:'backbutton'——左上角导航栏按钮及安卓返回键;'navigateBack'——uni.navigateBack() 方法。支付宝小程序端不支持返回此字段 |
export default {
onBackPress(options) {
console.log('from:' + options.from)
}
}
注意
onBackPress
上不可使用async
,会导致无法阻止默认返回navigateBack
引发的返回事件(使用小程序开发工具时不会触发onBackPress
),不可以阻止默认返回行为详细说明及使用:onBackPress 详解
参数说明
Attribute | Type | Instruction |
---|---|---|
index | Number | The serial number of the clicked tabItem, starting from 0 |
pagePath | String | The page path of the clicked tabItem |
text | String | The buttom text of the clicked tabItem |
onTabItemTap : function(e) {
console.log(e);
// Return format of e is json object: {"index":0,"text":"Home page","pagePath":"pages/index/index"}
},
注意
参数说明
Attribute | Type | Instruction |
---|---|---|
index | Number | Subscript of native title bar button array |
onNavigationBarButtonTap : function (e) {
console.log(e);
// The return format of e is a json object: {"text":"test","index":0}
}
Notice
The uni-app
component supports the same lifecycle as the vue standard components. There is no page-level onLoad and other life cycles here:
Function name | Instruction | Platform difference description | Minimum version |
---|---|---|---|
beforeCreate | is called before the instance is initialized. See details | ||
created | is called immediately after the instance is created. See | ||
beforeMount | is called before the mount starts. See details | ||
mounted | Called after the instance is mounted. See details Note: It is not sure that all subcomponents are mounted here, if you need to perform operations after subcomponents are fully mounted Use $nextTick Vue official document | ||
beforeUpdate | Called when the data is updated, before the virtual DOM is patched. See details | Only supported by H5 platform | |
updated | This hook is called after the virtual DOM has been re-rendered and patched due to data changes. See details | Only supported by H5 platform | |
beforeDestroy | Called before the instance is destroyed. At this step, the instance is still fully available. See details | ||
destroyed | Called when the Vue instance is destroyed. After calling, everything pointed to by the Vue instance will be unbound, all event listeners will be removed, and all child instances will be destroyed. See details |
getApp()
函数用于获取当前应用实例,一般用于获取globalData。也可通过应用实例调用 App.vue methods
中定义的方法。
实例 Instance
const app = getApp()
console.log(app.globalData)
app.doSomething() // 调用 App.vue methods 中的 doSomething 方法
注意: Notice:
App()
内的函数中,或调用 App
前调用 getApp()
,可以通过 this.$scope
获取对应的app实例getApp()
in a function defined in App()
or before calling App
, you can get the corresponding app instance through this.$scope
getApp()
获取实例之后,不要私自调用生命周期函数。getApp()
, do not call the life cycle function privately.nvue
中使用getApp()
不一定可以获取真正的App
对象。对此提供了const app = getApp({allowDefault: true})
用来获取原始的App
对象,可以用来在首页对globalData
等初始化getApp()
in the home page nvue
, you may not necessarily get the real App
object. For this reason, const app = getApp({allowDefault: true})
is provided to obtain the original App
object, which can be used to initialize globalData
etc. on the homepagegetCurrentPages()
函数用于获取当前页面栈的实例,以数组形式按栈的顺序给出,数组中的元素为页面实例,第一个元素为首页,最后一个元素为当前页面。
List of method properties for each page instance:
Methods | Description | Platform Description |
---|---|---|
page.$getAppWebview() | Get the webview object instance of the current page | App |
page.route | Get the route of the current page |
注意:
getCurrentPages()
仅用于展示页面栈的情况,请勿修改页面栈,以免造成页面状态错误。
页面关闭时,对应页面实例会在页面栈中删除。
Tips:
navigateTo
, redirectTo
只能打开非 tabBar 页面。switchTab
只能打开 tabBar
页面。tabBar
由页面决定,即只要是定义为 tabBar
的页面,底部都有 tabBar
。onReady
之前进行页面跳转。uni-app
在 getCurrentPages()
获得的页面里内置了一个方法 $getAppWebview()
可以得到当前webview的对象实例,从而实现对 webview 更强大的控制。在 html5Plus 中,plus.webview具有强大的控制能力,可参考:WebviewObject。
uni-app
There is a built-in method $getAppWebview()
in the page obtained by getCurrentPages()
, which can get the object instance of the current webview, so as to realize the update of the webview. Powerful controls. In html5Plus, plus.webview has powerful control ability, please refer to: WebviewObject.
But the uni-app
framework has its own window management mechanism, please do not create and destroy the webview yourself. If you need to cover the sub-form, please use native sub-form subNvue.
Note: This method is only supported by App
Example:
Get the object instance of the current page 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
}
}
Get the object instance of the specified page webview
getCurrentPages()
can get all page objects, and then according to the array, you can get the specified page webview object
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
The web-view component that comes with uni-app is a newly inserted sub-webview in the page. For the method of obtaining this object, see: https://ask.dcloud.net.cn/article/35036
Trigger a global custom event. Additional parameters are passed to the listener callback.
Attribute | Type | Describe |
---|---|---|
eventName | String | Event name |
OBJECT | Object | Additional parameters carried by triggering events |
Code example
uni.$emit('update',{msg:'页面更新'})
Listen to global custom events. Events can be triggered by uni.$emit, and the callback function receives all the additional parameters of the incoming event trigger function.
Attribute | Type | Describe |
---|---|---|
eventName | String | Event name |
callback | Function | Event callback function |
Code example
uni.$on('update',function(data){
console.log('监听到事件来自 update ,携带参数 msg 为:' + data.msg);
})
Listen to global custom events. Events can be triggered by uni.$emit, but only once. Remove the listener after the first trigger.
Attribute | Type | Describe |
---|---|---|
eventName | String | Event name |
callback | Function | Event callback function |
Code example
uni.$once('update',function(data){
console.log('监听到事件来自 update ,携带参数 msg 为:' + data.msg);
})
Remove the global custom event listener.
Attribute | Type | Describe |
---|---|---|
eventName | Array<String> | Event name |
callback | Function | Event callback function |
Tips
Code example
$emit
, $on
and $off
are commonly used for cross-page and cross-component communication, and are placed on the same page for easy demonstration
<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>
Precautions
Further reading:
uni-app
page routing is managed by the framework. Developers need to configure the path and page style of each routing page in pages.json. Similar to the applet configuring page routing in app.json. Therefore, the routing usage of uni-app
is different from that of Vue Router
. If you still want to use Vue Router
to manage routing, you can search for [Vue-Router](https://ext.dcloud.net.cn /search?q=vue-router).
uni-app
has two ways to jump to page routing: use navigator component to jump, and call API to jump.
注意:
页面返回时会自动关闭 loading 及 toast, modal 及 actionSheet 不会自动关闭。
页面关闭时,只是销毁了页面实例,未完成的网络请求、计时器等副作用需开发者自行处理。
The framework manages all current pages in the form of stack. When a route switch occurs, the page stack behaves as follows:
Routing mode | Page stack performance | Trigger timing |
---|---|---|
Initialization | Pushing a new page into the stack | The first page opened by uni-app |
Open a new page | New page onto the stack | Call API uni.navigateTo, use component <navigator open-type="navigate"/> |
Page redirection | The current page is out of the stack, and the new page is in the stack | Call API uni.redirectTo, use component <navigator open-type="redirectTo"/> |
Page return | The page is constantly popped until the target returns to the page | Call API uni.navigateBack , use component <navigator open-type="navigateBack"/>, user presses back button in the upper left corner, Android user presses back button |
Tab switching | All the pages are out of the stack, leaving only the new Tab page | Call API uni.switchTab, use component <navigator open-type="switchTab"/>, user switches Tab |
Reload | All the pages are out of the stack, leaving only the new page | Call API uni.reLaunch, Use component <navigator open-type="reLaunch"/> |
uni-app
支持在 template 模板中嵌套 <template/>
和 <block/>
,用来进行 条件渲染 和 列表渲染。
<template/>
and <block/>
is not a component, they are just a wrapper element that doesn't do any rendering on the page and only accepts control properties.
<block/>
There are some differences in the performance of different platforms, it is recommended to use it uniformly<template/>
.
Code example
<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>
Rendering based on native engines, although it is still a front-end technology stack, is definitely different from web development.
v-if
can be used to control the display and hide of nvue pages, not v-show
flex
layout, other layout methods are not supported. Before developing a page, first figure out what the vertical content of this page has, which ones are to be scrolled, and then what is arranged on the horizontal axis of each vertical content, and design the interface according to the flex layout.column
) by default. To change the layout direction, you can go to manifest.json
-> app-plus
-> nvue
-> flex-direction
Modifications under the node only take effect in uni-app mode. Details.display:flex
, their flex direction is horizontal instead of vertical by default. Therefore, when nvue is compiled into H5 and applet, it will automatically set the default layout of the page to flex and the direction to be vertical. Of course, the default settings will be overwritten by the developer after manual settings.<text>
under Components. cannot be in <div>
,<view> Write text directly in the
text` area of ``. Otherwise, even if it is rendered, the variables in js cannot be bound.text
tag can set the font size and font color.flex
is still very powerful. See detailsimage
component and hierarchy to achieve background effects similar to those in the web. Because native development itself does not have the concept of web background imagebackground-color
is not set, it may cause ghosting problems.class
only supports array syntax when binding.bounce
rebound effect, only a few list components have the bounce
effect, including list
, recycle-list
, waterfall
.list
, waterfall
, scroll-view/scroller
). Sleeve under the rollable assembly. This is not in line with the habit of front-end development, so when nvue is compiled into uni-app mode, a scroller
is automatically placed on the outer layer of the page, and the page content is too high and it will scroll automatically. (Components will not be nested, nor will they be nested when the page has a recycle-list
). The configuration will be provided later, and it can be set to not automatically set.globalData
and vuex
are in effect.APP-PLUS-NVUE
style
. Reference for the use of font icons in nvue: Load custom font. If it is a local font, you can use the plus.io
API to convert the path.typescript/ts
in nvue pages is not supported.json
to draw the native navigation bar, but it takes much longer to parse the js of nvue to draw the entire page, especially when the new page enters the animation. For complex pages, there is no native navigation bar. Blank or flicker the entire screen during the animation.