探讨uniapp的页面问题

1 新建页面

uni-app中的页面,默认保存在工程根目录下的pages目录下。
在这里插入图片描述

每次新建页面,均需在pages.json中配置pages列表;
在这里插入图片描述

未在pages.json -> pages 中注册的页面,uni-app会在编译阶段进行忽略。pages.json的完整配置参考:页面配置。

通过HBuilderX开发 uni-app 项目时,在 uni-app 项目上右键“新建页面”,HBuilderX会自动在pages.json中完成页面注册,开发更方便。

同时,HBuilderX 还内置了常用的页面模板(如图文列表、商品列表等),选择这些模板,可以大幅提升你的开发效率。

在这里插入图片描述
新建页面时,可以选择vue或nvue,还可以选择是否创建同名目录。创建目录的意义在于,如果你的页面较复杂,需要拆分多个附属的js、css、组件等文件,则使用目录归纳比较合适。如果只有一个页面文件,大可不必多放一层目录。

2 删除页面

删除页面时,需做两件工作:

  1. 删除.vue文件或.nvue文件
  2. 删除pages.json -> pages列表项中的配置(如使用HBuilderX删除页面,会在状态栏提醒删除pages.json对应内容)

pages.json是工程的页面管理配置文件,包括:页面路由注册、页面参数配置(原生标题栏、下拉刷新…)、首页tabbar等众多功能。

其篇幅较长,另见 pages.json

3 应用首页

pages.json -> pages 配置项中的第一个页面,作为当前工程的首页(启动页)。

{"pages": [{"path": "pages/index/index", //名字叫不叫index无所谓,位置在第一个,就是首页"style": {"navigationBarTitleText": "首页" //页面标题}},{"path": "pages/my","style": {"navigationBarTitleText": "我的"}},]
}

4 页面内容构成

uni-app 页面基于 vue 规范。一个页面内,有3个根节点标签 、

<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>

4.1 template模板区

vue的template中写的全都是vue组件,每个组件支持属性、事件、vue指令,还可以绑定vue的data数据。

4.2 script脚本区

在vue的选项式(option)规范中,script下包含export default {}。(除了选项式,还有组合式)

页面级的代码大多写在export default {}中。写在里面的代码,会随着页面关闭而关闭。

在这里插入图片描述
export default 外的代码
先来介绍写在export default {}外面的代码,一般有几种情况:

  • import三方js模块
  • import非easycom的组件(一般组件推荐使用easycom,无需导入注册)
  • 定义作用域更大的变量
  • 在ts/uts中,对data的类型进行type定义
<script>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个注意事项:

  • 在应用启动时执行。也就是这里的代码执行时机是应用启动、而不是页面加载。如果这里的代码写的太复杂,会影响应用启动速度和内存占用。
  • 不跟随页面关闭而回收。在外层的静态变量不会跟随页面关闭而回收。

export default 里的代码
export default {} 里的内容,是页面的主要逻辑代码。包括几部分:

  • data:template模板中需要使用的数据。data 必须声明为返回一个初始数据对象的函数(注意函数内返回的数据对象不要直接引用函数外的对象)。
  • 页面生命周期:如页面加载、隐藏、关闭
  • methods方法,如按钮点击、屏幕滚动

如下页面代码的逻辑是:
在这里插入图片描述

  1. 在data中定义了title,初始值是"点我"
  2. 在页面中放置了一个button组件,按钮文字区使用{{}}模板写法,里面写title,把data里的title绑定到按钮的文字区,即按钮的初始文字是"点我"
  3. 按钮的点击事件@click,指向了methods里的一个方法buttonClick,点击按钮即触发这个方法的执行
  4. buttonClick方法里通过this.title的方式,访问data数据,并重新赋值为"被点了"。由于vue中data和界面是双向绑定,修改data中的title后,因为按钮文字绑定了title,会自动更新按钮的文字。

整体效果就是,刚开始按钮文字是"点我",点一下后按钮文字变成了"被点了"

5 页面生命周期

uni-app 页面除支持 Vue 组件生命周期外还支持下方页面生命周期函数.
在这里插入图片描述
在这里插入图片描述

5.1 页面加载时序介绍

接下来我们介绍onLoad、onReady、onShow的先后关系,页面加载的详细流程。
在这里插入图片描述

  1. uni-app框架,首先根据pages.json的配置,创建页面 。所以原生导航栏是最快显示的。页面背景色也应该在这里配置。
  2. 根据页面template里的组件,创建dom。
    这里的dom创建仅包含第一批处理的静态dom,对于通过js更新data,然后通过v-for再创建的列表数据,不在第一批处理。要注意一个页面静态dom元素过多,会影响页面加载速度。在uni-app x Android版本上,可能会阻碍页面进入的转场动画。 因为此时,页面转场动画还没有启动。
  3. 触发onLoad
    此时页面还未显示,没有开始进入的转场动画,页面dom还不存在。所以这里不能直接操作dom(可以修改data,因为vue框架会等待dom准备后再更新界面);
    在 app-uvue 中获取当前的activity拿到的是老页面的activity,只能通过页面栈获取activity。
    onLoad比较适合的操作是:接受上页的参数,联网取数据,更新data。
    手机都是多核的,uni.request或云开发联网,在子线程运行,不会干扰UI线程的入场动画,并行处理可以更快的拿到数据、渲染界面。
    但onLoad里不适合进行大量同步耗时运算,因为此时转场动画还没开始。 尤其uni-app x 在 Android上,onLoad里的代码(除了联网和加载图片)默认是在UI线程运行的,大量同步耗时计算很容易卡住页面动画不启动。除非开发者显式指定在其他线程运行。
  4. 转场动画开始
    新页面开始进入的转场动画,动画默认耗时300ms,可以在路由API中调节时长。
  5. 页面onReady
    第2步 创建dom是虚拟dom,dom创建后需要经历一段时间,UI层才能完成了页面上真实元素的创建,即触发了onReady。
    onReady后,页面元素就可以自由操作了,比如ref获取节点。同时首批界面也渲染了。
    注意:onReady和转场动画开始、结束之间,没有必然的先后顺序,完全取决于dom的数量和复杂度。
    如果元素排版和渲染够快,转场动画刚开始就渲染好了;
    大多情况下,转场动画走几格就看到了首批渲染内容;
    如果元素排版和渲染过慢,转场动画结束都没有内容,就会造成白屏。
    联网进程从onLoad起就在异步获取数据更新data,如果服务器速度够快,第二批数据也可能在转场动画结束前渲染。
  6. 转场动画结束
    再次强调,5和6的先后顺序不一定,取决于首批dom渲染的速度。

5.2 页面加载常见问题

了解了页面加载时序原理,我们就知道如何避免页面加载常见的问题:

优化白屏的方法:

  1. 页面dom太多,注意有的组件写的不好,会拖累整体页面。uni-app x 里减少dom数量的策略,详见
  2. 联网不要在onReady里,那样太慢了,在onLoad里早点联网
  3. 在pages.json里配置原生导航栏和背景色
  4. 有的页面template内容非常少,整页就是一个需要联网加载的列表,这会造成虽然首批dom飞快渲染了,但页面其实还是白的,联网后才能显示字和图。
    此时需要在template里做一些简单占位组件,比如loading组件、骨架屏,让本地先显示一些内容。

卡住动画不启动的原因:

  1. 页面dom太多,注意有的组件写的不好,会拖累整体页面。uni-app x 里减少dom数量的策略,详见
  2. onLoad里执行了耗时的同步计算

5.3 onShow和onHide

  • 注意页面显示,是一个会重复触发的事件。
  • a页面刚进入时,会触发a页面的onShow。
  • 当a跳转到b页面时,a会触发onHide,而b会触发onShow。
  • 但当b被关闭时,b会触发onUnload,此时a再次显示出现,会再次触发onShow。
  • 在tabbar页面(指pages.json里配置的tabbar),不同tab页面互相切换时,会触发各自的onShow和onHide。

5.4 onInit

不建议使用

5.5 onReachBottom

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

onPageScroll : function(e) { //nvue暂不支持滚动监听,可用bindingx代替console.log("滚动距离为:" + e.scrollTop);
},
  • 可在pages.json里定义具体页面底部的触发距离onReachBottomDistance,比如设为50,那么滚动页面到距离底部50px时,就会触发onReachBottom事件。
  • 如使用scroll-view导致页面没有滚动,则触底事件不会被触发。scroll-view滚动到底部的事件请参考scroll-view的文档
  • onPageScroll里不要写交互复杂的js,比如频繁修改页面。因为这个生命周期是在渲染层触发的,在非h5端,js是在逻辑层执行的,两层之间通信是有损耗的。如果在滚动过程中,频发触发两层之间的数据交换,可能会造成卡顿。

5.6 onBackPress

在这里插入图片描述
在这里插入图片描述

  • onBackPress上不可使用async,会导致无法阻止默认返回

当用户进行以下操作时,会触发该函数:

  • Android 实体返回键 (from = backbutton)
  • 顶部导航栏左边的返回按钮 (from = backbutton)
  • 返回 API,即 uni.navigateBack() (from = navigateBack)

注意事项:

  • 只有在该函数中返回值为 true 时,才表示不执行默认的返回,自行处理此时的业务逻辑。

场景示例:
在这里插入图片描述

页面中的遮罩处于显示状态时,点击返回不希望直接关闭页面,而是隐藏掉遮罩。遮罩隐藏后,继续点击返回再执行默认的逻辑。

自定义遮罩 通常自定义的遮罩/弹出层,都会做成组件,这样方便复用。新建 uni-app 项目->components->mask.vue 文件,代码如下:

<template>  <view>  <view class="cpt-mask">  </view>  </view>  
</template>  <script>  export default {}  
</script>  <style>  .cpt-mask {  position: fixed;  top: 0;  left: 0;  width: 100%;  height: 100%;  background-color: #000000;  opacity: 0.5;  z-index: 99;  }  
</style>

引用遮罩组件 在页面中引入 mask 自定义组件后,通过一个状态值来控制其隐藏/显示。

<mask v-if="showMask"></mask>

这里用 v-if,不要用 v-show,自定义组件存在一些问题待优化。

在 onBackPress 中,判定当前遮罩是否处于显示状态。如果显示,则关闭遮罩并返回 true。

		onBackPress() {if (this.showMask) {console.log('onBackPress close mask');this.showMask = false;return true;} else {uni.showModal({title: '提示',content: '自定义是否退出uni-app?',success: function(res) {if (res.confirm) {// 退出当前应用,改方法只在App中生效plus.runtime.quit();} else if (res.cancel) {console.log('用户点击取消');}}});return true;}},

5.7 onTabItemTap

在这里插入图片描述

  • onTabItemTap常用于点击当前tabitem
onTabItemTap : function(e) {console.log(e);// e的返回格式为json对象: {"index":0,"text":"首页","pagePath":"pages/index/index"}
},

5.8 onNavigationBarButtonTap

点击导航栏 buttons 时触发
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

{"fontSrc": "/static/yticon.ttf","text": "","fontSize": "26","color": "#303133","float": "left","background": "rgba(0,0,0,0)","onclick": "function() { [native code] }","__cb__": {"id": "plus71692953577889","htmlId": "__uniapp__service"},"index": 0
}

6 组件生命周期

在这里插入图片描述

7 页面调用接口

7.1 getApp()

getApp() 函数用于获取当前应用实例VUE,一般用于获取globalData。也可通过应用实例调用 App.vue methods 中定义的方法。
在这里插入图片描述

7.2 getCurrentPages()

getCurrentPages() 函数用于获取当前页面栈的实例,以数组形式按栈的顺序给出,数组中的元素为页面实例,第一个元素为首页,最后一个元素为当前页面。

在这里插入图片描述
getCurrentPages()仅用于展示页面栈的情况,请勿修改页面栈,以免造成页面状态错误。页面关闭时,对应页面实例会在页面栈中删除。

在这里插入图片描述

			var pages = getCurrentPages();var page = pages[pages.length - 1];

8 页面通讯

8.1 uni.$emit(eventName,OBJECT)

触发全局的自定义事件。附加参数都会传给监听器回调。
在这里插入图片描述

	uni.$emit('update',{msg:'页面更新'})

8.2 uni.$on(eventName,callback)

监听全局的自定义事件。事件可以由 uni.$emit 触发,回调函数会接收所有传入事件触发函数的额外参数。
在这里插入图片描述

	uni.$on('update',function(data){console.log('监听到事件来自 update ,携带参数 msg 为:' + data.msg);})

8.3 uni.$once(eventName,callback)

监听全局的自定义事件。事件可以由 uni.$emit 触发,但是只触发一次,在第一次触发之后移除监听器。

在这里插入图片描述

	uni.$once('update',function(data){console.log('监听到事件来自 update ,携带参数 msg 为:' + data.msg);})

8.3 uni.$off([eventName, callback])

移除全局自定义事件监听器。

在这里插入图片描述

  • 如果没有提供参数,则移除所有的事件监听器;
  • 如果只提供了事件,则移除该事件所有的监听器;
  • 如果同时提供了事件与回调,则只移除这个回调的监听器;
  • 提供的回调必须跟$on的回调为同一个才能移除这个回调的监听器;

$emit、$on、$off常用于跨页面、跨组件通讯,这里为了方便演示放在同一个页面

8.4 如何使用uni.$emit()和uni.$on() 进行页面间通讯:

监听事件

// 我的页面  
onLoad(){  // 监听事件  uni.$on('login',(usnerinfo)=>{  this.usnerinfo = usnerinfo;  })  
},  
onUnload() {  // 移除监听事件  uni.$off('login');  },

因为事件监听是全局的,所以使用 uni.$on ,需要使用 uni.$off 移除全局的事件监听,避免重复监听。

触发事件

// 登陆页面  
uni.$emit('login', {  avatarUrl: 'https://img-cdn-qiniu.dcloud.net.cn/uploads/nav_menu/10.jpg',  token: 'user123456',  userName: 'unier',  login: true  });

使用 uni.$emit 触发事件后,对应的 uni.$on 就会监听到事件触发,在回调中去执行相关的逻辑。

在这里插入图片描述

9 路由

uni-app 有两种页面路由跳转方式:使用navigator组件跳转、调用API跳转。

  • 页面返回时会自动关闭 loading 及 toast, modal 及 actionSheet 不会自动关闭。
  • 页面关闭时,只是销毁了页面实例,未完成的网络请求、计时器等副作用需开发者自行处理

10 页面栈

框架以栈的形式管理当前所有页面, 当发生路由切换的时候,页面栈的表现如下:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/83602.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

APSIM模型应用与参数优化、批量模拟

APSIM (Agricultural Production Systems sIMulator)模型是世界知名的作物生长模拟模型之一。APSIM模型有Classic和Next Generation两个系列模型&#xff0c;能模拟几十种农作物、牧草和树木的土壤-植物-大气过程&#xff0c;被广泛应用于精细农业、水肥管理、气候变化、粮食安…

【动手学深度学习】--18.图像增广

文章目录 图像增广1.常用的图像增广方法1.1翻转和裁剪1.2改变颜色1.3结合多种图像增广方法 2.使用图像增广进行训练3.训练 图像增广 官方笔记&#xff1a;图像增广 学习视频&#xff1a;数据增广【动手学深度学习v2】 图像增广在对训练图像进行一系列的随机变化之后&#xff…

【从零学习python 】56. 异常处理在程序设计中的重要性与应用

文章目录 异常的概念读取文件异常try...except语句try...else语句try...finally语句 进阶案例 异常的概念 在程序运行过程中&#xff0c;由于编码不规范或其他客观原因&#xff0c;可能会导致程序无法继续运行&#xff0c;此时就会出现异常。如果不对异常进行处理&#xff0c;…

APP Binder客户端调用全流程分析

现在要搞明白JAVA层app调用跨进程的Service接口时&#xff0c;它的binder是怎样从Java->jni-->native--->binder驱动的这条链路&#xff1a;就是上图中的左半部分从上至下的流程。所以切入点在于&#xff0c;如app调用另一个进程的Service接口的getString&#xff08;…

“石头剪刀布”游戏:while、函数自调用实现循环游戏

if…else实现“石头剪刀布”游戏&#xff0c;while、函数自调用实现循环游戏。 (本笔记适合学过if…else的coder翻阅) 【学习的细节是欢悦的历程】 Python 官网&#xff1a;https://www.python.org/ Free&#xff1a;大咖免费“圣经”教程《 python 完全自学教程》&#xff0c…

React Diff算法

文章目录 React Diff算法一、它的作用是什么&#xff1f;二、React的Diff算法1.了解一下什么是调和&#xff1f;2.react的diff算法3.React Diff的三大策略4.tree diff&#xff1a;1、如果DOM节点出现了跨层级操作&#xff0c;Diff会怎么办? 5. component diff&#xff1a;6. e…

Windows平台Unity下播放RTSP或RTMP如何开启硬解码?

我们在做Windows平台Unity播放RTMP或RTSP的时候&#xff0c;遇到这样的问题&#xff0c;比如展会、安防监控等场景下&#xff0c;需要同时播放多路RTMP或RTSP流&#xff0c;这样对设备性能&#xff0c;提出来更高的要求。 虽然我们软解码&#xff0c;已经做的资源占有非常低了…

mysql 默认的4个数据库 介绍

mysql 存储MySQL的用户账号和权限信息&#xff0c;一些存储过程、事件的定义信息 一些运行过程中产生的日志信息&#xff0c;一些帮助信息以及时区信息等 information_schema 存储Mysql服务器 维护的所有其它数据库的信息&#xff0c;比如有哪些表、哪些视图、哪些触发器、哪…

基于YOLOv8模型和DarkFace数据集的黑夜人脸检测系统(PyTorch+Pyside6+YOLOv8模型)

摘要&#xff1a;基于YOLOv8模型和DarkFace数据集的黑夜人脸检测系统可用于日常生活中检测与定位黑夜下的人脸&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的目标检测&#xff0c;另外本系统还支持图片、视频等格式的结果可视化与结果导出。本系统采用YOLOv8目…

【IO进程线程】使用标准IO函数完成用户的登录和注册

1 实现登录功能 自定义一个usr.txt&#xff0c;先手动输入其账户密码。 格式&#xff1a;账户 密码 例&#xff1a; zhangsan 12345 lisi abcde wangwu abc123 需求如下&#xff1a; 1. 从终端获取账户密码&#xff0c;与文件中的账户密码比较&#xff1b; 2. 若终端输入的账户…

把Android手机变成电脑摄像头

一、使用 DroidCam 使用 DroidCam&#xff0c;你可以将手机作为电脑摄像头和麦克风。一则省钱&#xff0c;二则可以在紧急情况下使用&#xff0c;比如要在电脑端参加一个紧急会议&#xff0c;但电脑却没有摄像头和麦克风。 DroidCam 的安卓端分为免费的 DroidCam 版和收费的 …

设计模式之抽象工厂

文章目录 一、介绍二、基本组件三、演示案例1. 定义抽象工厂2. 定义抽象产品3. 定义具体工厂4. 定义具体产品5. 代码演示6. 代码改造 四、总结 一、介绍 抽象工厂模式(Abstract Factory Pattern)属于创建型设计模式。用于解决比工厂方法设计模式更加复杂的问题。 复杂到哪里了…