详解小程序如何改变onLoad的执行时机


Posted in Javascript onNovember 01, 2019

也许在小程序所有生命周期里,我们用的最多的就是 onLoad,一大堆代码都要在初始化的时候执行。

很多时候,初始化的代码是每个页面共用的,比如获取用户信息、获取定位等:

Page({
 onLoad() {
  this.userData = getUserData()
  wx.getLocation({
   type: 'wgs84',
   success (res) {
    // 业务代码
    // ...
   }
  })
 }
 // ...
})

久而久之,每个页面的 js 里都是如上的重复代码。如果可以先执行完通用的初始化代码,再执行每个页面各自的 onLoad 多好,可惜小程序并没有提供类似的钩子函数,那就自己来吧。

代理 onLoad

按照前几篇的方法,可以代理原有的 onLoad 事件:

var originPage = Page

function MyPage(config) {
 this.lifetimeBackup = {
  onLoad: config.onLoad
 }
 config.onLoad = function(options) {
  // 自定义代码
  // 公共的初始化代码
  this.userData = getUserData()
   wx.getLocation({
   type: 'wgs84',
   success (res) {
    // 执行 onLoad
    this.lifetimeBackup.onLoad.call(this, options)
   }
  })
 }
 
 // ...

 originPage(config)
}

当然,实际开发过程中的初始化代码不可能这么少,可以用很多方式把它抽离出去,比如这样:

// utils/initial.js
function initial(callback) {
 this.userData = getUserData()
 wx.getLocation({
  type: 'wgs84',
  success (res) {
   callback()
  }
 })
}
 
// utils/wx.js
var initial = require('./initial')
var originPage = Page

function MyPage(config) {
 this.lifetimeBackup = {
  onLoad: config.onLoad
 }
 config.onLoad = function(options) {
  initial(() => {
   this.lifetimeBackup.onLoad.call(this, options)
  })
 }
 // ...
 originPage(config)
}

也可以使用更多高级的方法抽离出去,比如 event bus 之类的,就不多赘述。

看似很简单,但其实这样忽略了一个问题 —— 生命周期顺序被打乱了!如果初始化方法里有异步代码,那首先执行的可能就是 onShow ,而不是约定的 onLoad。

恢复生命周期顺序

为了保证生命周期函数能够按顺序执行,可以先临时清空生命周期函数,然后再依次执行,如下代码所示:

// utils/wx.js
const LIFETIME_EVENTS = ['onLoad', 'onShow', 'onReady']
var initial = require('./initial')
var originPage = Page


function MyPage(config) {
 LIFETIME_EVENTS.forEach((event) => {
  // 备份生命周期函数
  this.lifetimeBackup[event] = config[event]
  // 临时清空
  config[event] = function() {}
 })
 config.onLoad = function(options) {
  initial(() => {
   // 依次执行生命周期函数
   LIFETIME_EVENTS.forEach((event) => {
    this.lifetimeBackup[event].call(this, options)
   })
  })
 }
 // ...
 originPage(config)
}

注意上述代码还是有问题的,当小程序业务跳走再返回或者切后台到前台时,onShow 无法正常触发,因为被设置为空函数了。

为了保证 onShow 等生命周期函数的后续正常运行,需要在依次执行完生命周期函数后,再把它们恢复到 config 下,这是必不可少的。完整代码如下:

// utils/wx.js
const LIFETIME_EVENTS = ['onLoad', 'onShow', 'onReady']
var initial = require('./initial')
var originPage = Page


function MyPage(config) {
 LIFETIME_EVENTS.forEach((event) => {
  // 备份生命周期函数
  this.lifetimeBackup[event] = config[event]
  // 临时清空
  config[event] = function() {}
 })
 config.onLoad = function(options) {
  initial(() => {
   // 依次执行生命周期函数
   LIFETIME_EVENTS.forEach((event) => {
    this.lifetimeBackup[event].call(this, options)
    // 执行完后,恢复过来
    config[event] = this.lifetimeBackup[event]
   })
  })
 }
 // ...
 originPage(config)
}

总结

代理了 onLoad 后,就可以手动控制其执行的时机,可以折腾的事情就多了很多。比如当初始化函数需要执行(请求)的内容比较多,耗时比较长时,可以统一给页面增加一些 loading 提示等。总之,可以自由控制了。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
从零开始学习jQuery (四) jQuery中操作元素的属性与样式
Feb 23 Javascript
JavaScript String.replace函数参数实例说明
Jun 06 Javascript
Jquery时间轴特效(三种不同类型)
Nov 02 Javascript
基于JavaScript代码实现微信扫一扫下载APP
Dec 30 Javascript
jQuery取得iframe中元素的常用方法详解
Jan 14 Javascript
knockoutjs模板实现树形结构列表
Jul 31 Javascript
php 解压zip压缩包内容到指定目录的实例
Jan 23 Javascript
微信小程序日历组件使用方法详解
Dec 29 Javascript
如何解决.vue文件url引用文件的问题
Jan 18 Javascript
微信小程序左右滚动公告栏效果代码实例
Sep 16 Javascript
解决vue-router路由拦截造成死循环问题
Aug 05 Javascript
基于vue项目设置resolves.alias: '@'路径并适配webstorm
Dec 02 Vue.js
js canvas实现星空连线背景特效
Nov 01 #Javascript
jQuery鼠标滑过横向时间轴样式(代码详解)
Nov 01 #jQuery
微信小程序定义和调用全局变量globalData的实现
Nov 01 #Javascript
vue-router 中 meta的用法详解
Nov 01 #Javascript
VUE 解决mode为history页面为空白的问题
Nov 01 #Javascript
js+canvas实现两张图片合并成一张图片的方法
Nov 01 #Javascript
JS中自定义事件的使用与触发操作实例分析
Nov 01 #Javascript
You might like
从C/C++迁移到PHP——判断字符类型的函数
2006/10/09 PHP
使用 MySQL 开始 PHP 会话
2006/12/21 PHP
php基于dom实现的图书xml格式数据示例
2017/02/03 PHP
PHP的cookie与session原理及用法详解
2019/09/27 PHP
php 使用 __call实现重载功能示例
2019/11/18 PHP
用javascript实现点击链接弹出"图片另存为"而不是直接打开
2007/08/15 Javascript
js菜单点击显示或隐藏效果的简单实例
2014/01/13 Javascript
js中用window.open()打开多个窗口的name问题
2014/03/13 Javascript
教你用AngularJS框架一行JS代码实现控件验证效果
2014/06/23 Javascript
JavaScript设计模式之观察者模式(发布者-订阅者模式)
2014/09/24 Javascript
jQuery+HTML5美女瀑布流布局实现方法
2015/09/21 Javascript
使用vue制作FullPage页面滚动效果
2017/08/21 Javascript
几个你不知道的技巧助你写出更优雅的vue.js代码
2018/06/11 Javascript
JavaScript使用math.js进行精确计算操作示例
2018/06/19 Javascript
vue项目环境变量配置的实现方法
2018/10/12 Javascript
NodeJS服务器实现gzip压缩的示例代码
2018/10/12 NodeJs
vue-cli中使用高德地图的方法示例
2019/03/28 Javascript
js实现全选反选不选功能代码详解
2019/04/24 Javascript
vue如何自动化打包测试环境和正式环境的dist/test文件
2019/06/06 Javascript
详解Vue之事件处理
2020/07/10 Javascript
Python 正则表达式匹配字符串中的http链接方法
2018/12/25 Python
Python实现Singleton模式的方式详解
2019/08/08 Python
python内置模块collections知识点总结
2019/12/19 Python
pytorch .detach() .detach_() 和 .data用于切断反向传播的实现
2019/12/27 Python
python GUI库图形界面开发之PyQt5动态(可拖动控件大小)布局控件QSplitter详细使用方法与实例
2020/03/06 Python
Python3 ID3决策树判断申请贷款是否成功的实现代码
2020/05/21 Python
如何在网站上添加谷歌定位信息
2016/04/16 HTML / CSS
世界上最值得信赖的多日游在线市场:TourRadar
2018/07/20 全球购物
什么是Smart Navigation?
2016/07/03 面试题
Static Nested Class 和 Inner Class的不同
2013/11/28 面试题
网络教育毕业生自我鉴定
2013/10/10 职场文书
大学军训感言
2014/01/10 职场文书
双方协议书
2014/04/22 职场文书
青年文明号口号
2014/06/17 职场文书
个人股份合作协议书
2014/10/24 职场文书
豆瓣2021评分最高动画剧集-豆瓣评分最高的动画剧集2021
2022/03/18 日漫