探讨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.rhkb.cn/news/108193.html

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

相关文章

JVM第三篇 运行时数据区-虚拟机栈和PC程序计数器

目录 1. JAVA中的线程 2. 栈区 2.1 栈帧 2.2 栈可能出现的异常 2.3 设置栈大小 3.程序计数器&#xff08;PC&#xff09; 4. PC和栈发挥的作用 5. 关于栈的常见面试题 虚拟机包含三大部分&#xff0c;类加载子系统&#xff0c;运行时数据区&#xff0c;执行引擎。运行时…

linux Firewalld学习笔记

1、Firewalld默认策略 默认情况会阻止流量流入&#xff0c;但允许流量流出。 2、Firewalld区域概念 拒绝区域drop、默认区域public、允许区域trusted 3、区域规则 区域与网卡接口 默认区域规则 常用的有trusted &#xff08;相当于白名单&#xff09;、work/public 区、…

网站和API支持HTTPS,最好在Nginx上配置

随着我们网站用户的增多&#xff0c;我们会逐渐意识到HTTPS加密的重要性。在不修改现有代码的情况下&#xff0c;要从HTTP升级到HTTPS&#xff0c;让Nginx支持HTTPS是个很好的选择。今天我们来讲下如何从Nginx入手&#xff0c;从HTTP升级到HTTPS&#xff0c;同时支持静态网站和…

leetcode 583. 两个字符串的删除操作

2023.8.26 本题看似很绕&#xff0c;其实就是 最长公共子序列 的变式。 求出最长公共子序列之后&#xff0c;再用两单词的总长度减去他们的最长公共子序列即可。 代码如下&#xff1a; class Solution { public:int minDistance(string word1, string word2) {vector<vec…

从爬楼梯到斐波那契数列:解密数学之美

题目描述 我们来看看力扣的一道经典问题70. 爬楼梯 递归 假设n级台阶有climbStairs(n)种方法爬到楼梯顶。如果有n级台阶&#xff0c;如果第一次往上爬1级台阶&#xff0c;就会剩下n-1级台阶&#xff0c;这n-1级台阶就有climbStairs(n-1)种方法爬到楼梯顶&#xff1b;如果第一…

Delphi 开发手持机(android)打印机通用开发流程(举一反三)

目录 一、场景说明 二、厂家应提供的SDK文件 三、操作步骤&#xff1a; 1. 导出Delphi需要且能使用的接口文件&#xff1a; 2. 创建FMX Delphi项目&#xff0c;将上一步生成的接口文件&#xff08;V510.Interfaces.pas&#xff09;引入: 3. 将jarsdk.jar 包加入到 libs中…

docker安装redis

拉取镜像 docker pull redis:6.0.6查看镜像 docker images查看一下镜像已经拉下来了 下载配置文件 到redis官网下载一下压缩包&#xff0c; http://www.redis.cn/download.html 解压一下&#xff0c;把这个文件准备好 然后修改redis.conf bind 127.0.0.1 # 注释掉这部分&…

浏览器的事件循环

其实在我们电脑的操作系统中&#xff0c;每一个运行的程序都会由自己的进程&#xff08;可能是一个&#xff0c;也可能有多个&#xff09;&#xff0c;浏览器就是一个程序&#xff0c;它的运行在操作系统中&#xff0c;拥有一组自己的进程&#xff08;主进程&#xff0c;渲染进…

C语言练习5(巩固提升)

C语言练习5 选择题 选择题 1&#xff0c;下面代码的结果是&#xff1a;( ) #include <stdio.h> #include <string.h> int main() {char arr[] { b, i, t };printf("%d\n", strlen(arr));return 0; }A.3 B.4 C.随机值 D.5 &#x1f4af;答案解析&#…

C++数据结构学习——栈

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、栈二、C语言实现1.声明代码2.实现增删查改代码3.测试代码 总结 前言 栈&#xff08;Stack&#xff09;是计算机科学中一种常见的数据结构&#xff0c;它是…

函数的参数传递和返回值-PHP8知识详解

本文学习的是《php8知识详解》中的《函数的参数传递和返回值》。主要包括&#xff1a;向函数传递参数值、向函数传递参数引用、函数的返回值。 1、向函数传递参数值 函数是一段封闭的程序&#xff0c;有时候&#xff0c;程序员需要向函数传递一些数据进行操作。可以接受传入参…

【Eclipse】汉化简体中文教程(官方汉化包,IDE自带软件安装功能),图文详情

目录 0.环境 1.步骤 1&#xff09;查看eclipse的版本 2&#xff09;在官网找语言包&#xff0c;并复制链接 3&#xff09;将链接复制到eclipse中 4&#xff09;汉化完成 0.环境 windows11&#xff0c;64位&#xff1b; eclipse 2021-6版本 1.步骤 思路&#xff1a;在官网找…

9个python自动化脚本,PPT批量生成缩略图、添加图片、重命名

引言 最近一番在整理资料&#xff0c;之前买的PPT资源很大很多&#xff0c;但归类并不好&#xff0c;于是一番准备把这些PPT资源重新整理一下。统计了下&#xff0c;这些PPT资源大概有2000多个&#xff0c;一共30多G&#xff0c;一个一个手动整理这个投入产出比也太低了。 作为…

咸鱼之王俱乐部网站开发

我的俱乐部 最新兑换码 *注意区分大小写&#xff0c;中间不能有空格&#xff01; APP666 HAPPY666 QQ888 QQXY888 vip666 VIP666 XY888 app666 bdvip666 douyin666 douyin777 douyin888 happy666 huhushengwei888 taptap666 周活动 宝箱周 宝箱说明 1.木质宝箱开启1个…

哈夫曼编码(C++实现)

文章目录 1. 前言2. 固定长度编码3. 哈夫曼编码4. 哈夫曼解码5. 编码特点6. 代码实现7. 总结 1. 前言 在上一篇文章中&#xff0c;介绍了 哈夫曼树的概念及其实现 。 哈夫曼树有什么用途呢&#xff1f; —— 那就是用来创建哈夫曼编码&#xff08;Huffman Coding —— 一种二…

IDEA软件安装包分享(附安装教程)

目录 一、软件简介 二、软件下载 一、软件简介 IntelliJ IDEA是一款流行的Java集成开发环境&#xff08;IDE&#xff09;&#xff0c;由捷克软件开发公司JetBrains开发。它专为Java开发人员设计&#xff0c;提供了许多高级功能和工具&#xff0c;使得开发人员能够更高效地编写…

识别图片中的文字

前言 PearOCR 是一款免费无限制网页版文字识别工具。 优点如下&#xff1a; 免费&#xff1a;完全免费&#xff0c;没有任何次数、大小限制&#xff0c;可以无限使用&#xff1b; 安全&#xff1a;全部数据本地运算&#xff0c;所有图片均不会被上传&#xff1b; 智能&#xf…

数仓--------简单了解

作者前言 &#x1f382; ✨✨✨✨✨✨&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f382; ​&#x1f382; 作者介绍&#xff1a; &#x1f382;&#x1f382; &#x1f382; &#x1f389;&#x1f389;&#x1f389…

【坑】Vue中带有__ob__: Observer的数组无法遍历的问题

控制台可以打印出数据但是渲染不出结构 解决办法&#xff1a; setTimeout(() > {Bus.$emit(shareRes, this.result.filter(item > item.id id)) }, 500)替换 Bus.$emit(shareRes, this.result.filter(item > item.id id))总结 解决和总结 好像和__ob__.Observe无…

Android 11/12 app-lint 系统Update-API时Lint检查问题

有以下两种解决方法 1. 加SupressLint注解 这种方式你可以其他博客也有 但是要每个类和方法都加上SuppressLint 太麻烦了 我才不要这样呢 2. 添加 --api-lint-ignore-prefix 参数直接跳过代码检查 1. 打开 frameworks/base/Android.bp 文件 2. 搜索找到这个字段 metalava…