微信小程序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);
     
}