微信小程序2 - 扩展Page参数
官方默认的Page初始代码为
var option = {
/**
* 页面的初始数据
*/
data: {
},
/**
* 生命周期函数--监听页面加载
*
*/
onLoad: function (options) {
}
// ... 其他生命周期函数,以及自定义 方法
}
Page(option);
其中: option中的函数,在运行期,this 指向 当前Page对象
扩展思路: 对Page页面提供的PageOption 再次包装
编码要求:
option不再是一个独立定义的对象,而是经过方法创建
整个创建过程,你可以认为类似 继承 , decorator包装器 等... , 创建类名称 /util/BasePageOptionClass.js
BasePageOptionClass 类中包含了微信小程序中所定义的所有生命周期函数的定义,并带有多个自定义的扩展函数
页面调用示例
let PageOption = {}
Page(app.BasePageOptionClass.initPage(PageOption));
核心函数 initPage
1 /** 2 * 全局初始化界面函数,供页面调用 3 * PageOption = { 4 * needLogin:false, //是否需要登录 5 * loginReturnUrl: null // 登录成功后,需要跳转回的页面,可以是function ,为空则返回默认页面 6 * 7 * } 8 * 9 */ 10 BasePageOptionClass.initPage = function (PageOption ) { 11 var app = getApp(); 12 PageOption = PageOption || {}; 13 14 var actualOption = new BasePageOptionClass(PageOption.data); 15 actualOption.PageOption = PageOption; 16 var wxFunctions = { 17 "onLoad": 1, "onReady": 1, "onShow": 1, "onHide": 1, "onUnload": 1, 18 "onPullDownRefresh": 1, "onReachBottom": 1 , "onShareAppMessage": 1, "onPageScroll": 1 19 }; 20 for (var key in PageOption) { 21 if (!wxFunctions[key]) { 22 const functionKey = key; 23 actualOption[functionKey] = actualOption.PageOption[functionKey] 24 } 25 } 26 27 for (var functionKey in wxFunctions) { 28 const key = functionKey; // 这里要一个临时常量,否则执行的时候,functionKey永远是最后一个 29 if (!PageOption[key]){ //如果 参数没有,而基类有,那么保持基类不变 30 if (actualOption[key]) { //目前只有 onShareAppMessage 是底层封装好的 31 continue; 32 } 33 } 34 //否则重写基类方法 35 Object.defineProperty(actualOption, key, { 36 configurable: true , 37 enumerable: true , 38 value: function () { 39 var $target = this; //这里的 $target 可以认为是 BasePageOptionClass实例, 实际上,在运行时,已经转变为 Page对象 40 try { 41 //处理通知消息 42 if("onLoad"==key){ //当页面第一次打开的时候,注册 以 当前页 route 为 name的通知事件,通知内部做了 获取未处理消息的机制,如果有未处理的消息,那么立即执行 43 $target.addNotifyListener($target.getCurrentPageUrl()); 44 } else if ("onUnload" == key) { 45 //页面销毁的时候,销毁所有已注册的通知 46 $target.removeNotifyListener(); 47 } 48 // 嵌入了 前置处理程序,如果注册了 , 必须有 返回值 true | false , 如 before_onLoad , 参数和 原始方法保持一致,类 拦截器,暂时未支持栈,只支持一个 49 var canContinueRun = BasePageOptionClass.wrapPageLifeCircle(key, $target) 50 if (!canContinueRun) { 51 console.log("前置处理未通过,方法 " + currUrl + " " + key) 52 return; 53 } 54 //这里要使用 actualOption ,不能用 $target ,在页面带有 component 时 , 会冲突掉 PageOption 55 var func = actualOption.PageOption[key]; 56 if (func && func!=null) { 57 console.log("初始化方法 " + key + " 执行 ") 58 func.apply($target, arguments); 59 } 60 } catch (err) { 61 console.log(key + "", err); 62 } 63 }, 64 writable: false 65 }); 66 } 67 // console.log(actualOption) 68 return actualOption; 69 } 70 71 72 73 BasePageOptionClass.wrapPageLifeCircle = function (LifeCircleFuncName, PageOption={}) { 74 var canContinueRun = true; 75 var app = getApp(); 76 // console.log(LifeCircleFuncName) 77 78 if (PageOption.needLogin) { //是否需要登录 79 // console.log("执行前置") 80 if ("onLoad" == LifeCircleFuncName || "onShow" == LifeCircleFuncName) { //在onload 事件之前做 登录判断 81 var xgUserInfo = app.globalData.xgUserInfo; 82 if (!xgUserInfo) { 83 var loginReturnUrl = "/pages/my/index/index" 84 if (!PageOption.loginReturnUrl) { 85 loginReturnUrl = PageOption.loginReturnUrl; 86 } else { 87 if (typeof loginReturnUrl === "function") { 88 loginReturnUrl = (loginReturnUrl)(); 89 } else { 90 loginReturnUrl = "/pages/my/index/index" 91 } 92 } 93 wx.reLaunch({ 94 url: "/pages/my/register/index?returnUrl=" + loginReturnUrl 95 }); 96 canContinueRun = false; 97 } 98 } 99 } 100 if (!canContinueRun) return canContinueRun; 101 102 var func = "before_" + LifeCircleFuncName; 103 var pf = PageOption[func]; 104 if (pf && pf!=null){ // 带有before_ 开头的对应的内置方法,作为前置判断 , 需要有返回值 105 var ret = pf.apply(PageOption, []); 106 if(ret!==undefined){ 107 if (!ret) canContinueRun=false; 108 } 109 } 110 // app.util.log("进入前置", LifeCircleFuncName) 111 return canContinueRun; 112 }
这个方法的核心完成了2件事
1. 包装 Page中的PageOption内的生命周期函数(onLoad等), 使得 onLoad函数被作为 超类 onLoad 方法中的一个过程.
结构类似
BasePageOptionClass.onLoad=function(options){ //一些逻辑 //固定前置拦截器 逻辑 PageOption.onLoad(options); } BasePageOptionClass.onLoad 最终作为生命周期函数传递给Page对象
2. 增加 固定模式的前置拦截器
这里的处理较简单, 只是增加了单个 以 before_ 开头,以生命周期函数名为结尾的函数,作为拦截器,return true | false
BasePageOptionClass.onLoad=function(options){ //一些逻辑 //固定前置拦截器 逻辑 伪代码 if(PageOption.before_onLoad){ //这里就是拦截器逻辑 var ret = PageOption.before_onLoad(option) if(!ret){ return; } } PageOption.onLoad(options); }