微信小程序Behavior之definitionFilter自定义扩展段

809 阅读3分钟

先提一个问题:如果你想在所有小程序方法执行之前额外执行一段逻辑,例如权限判断,你会怎么做?貌似在微信小程序中没有比较优雅的解决方法。

现在我向大家介绍下Behavior的definitionFilter选项

1、definitionFilter

定义:definitionFilter 是一个函数,在被调用时会注入两个参数,第一个参数(defFields)是使用该 behavior 的 component/behavior 的定义对象,第二个参数(definitionFilterArr)是该 behavior 所使用的 behavior 的 definitionFilter 函数列表。

1)defFields(参数一)

接下来我们来看下defFields到底是什么东西

首先看下Page的定义

image.png

再来看下defFields

image.png

  • behaviors:当前页面使用的behaviors列表。
  • data:当前页面中的data数据。
  • methods:当前页面使用方法,包括生命周期方法。 总结一句话,函数会被放进methods中,其他的和定义段保持一致

那么defFields到底有什么用呢?

先贴一段官方的示例

// behavior.js
module.exports = Behavior({
  definitionFilter(defFields) {
    defFields.data.from = 'behavior'
  },
})

// component.js
Component({
  data: {
    from: 'component'
  },
  behaviors: [require('behavior.js')],
  ready() {
    console.log(this.data.from) // 此处会发现输出 behavior 而不是 component
  }
})

显然已经很明显了,它会在Page/Component生成之前修改(过滤)内部的各个选项。

2)definitionFilterArr(参数二)

definitionFilterArr是 behavior 所使用的 behavior 的 definitionFilter 函数列表。

以下举个例子来说明:

// behavior3.js
module.exports = Behavior({
    definitionFilter(defFields, definitionFilterArr) {},
})

// behavior2.js
module.exports = Behavior({
  behaviors: [require('behavior3.js')],
  definitionFilter(defFields, definitionFilterArr) {
    // definitionFilterArr[0](defFields)
  },
})

// behavior1.js
module.exports = Behavior({
  behaviors: [require('behavior2.js')],
  definitionFilter(defFields, definitionFilterArr) {},
})

// component.js
Component({
  behaviors: [require('behavior1.js')],
})

上述代码中声明了1个自定义组件和3个 behavior,每个 behavior 都使用了 definitionFilter 定义段。那么按照声明的顺序会有如下事情发生:

  1. 当进行 behavior2 的声明时就会调用 behavior3 的 definitionFilter 函数,其中 defFields 参数是 behavior2 的定义段, definitionFilterArr 参数即为空数组,因为 behavior3 没有使用其他的 behavior 。
  2. 当进行 behavior1 的声明时就会调用 behavior2 的 definitionFilter 函数,其中 defFields 参数是 behavior1 的定义段, definitionFilterArr 参数是一个长度为1的数组,definitionFilterArr[0] 即为 behavior3 的 definitionFilter 函数,因为 behavior2 使用了 behavior3。用户在此处可以自行决定在进行 behavior1 的声明时要不要调用 behavior3 的 definitionFilter 函数,如果需要调用,在此处补充代码 definitionFilterArr[0](defFields) 即可,definitionFilterArr 参数会由基础库补充传入。
  3. 同理,在进行 component 的声明时就会调用 behavior1 的 definitionFilter 函数。

2、例子(简易权限判断)

 //auth.js
 Behavior({
    ...
    definitionFilter(defFields) {
        const methods = defFields.methods;
        Object.keys(methods).forEach((name) => {
            const f = defFields.methods[name];
            //修改Page中的方法
            defFields.methods[name] = function () {
                if (/**权限判断 */) {
                  f.call(this);
                }
            }
      })
    },
   ...
  });

这样做会修改Page中的方法,使它们在调用前进行一个逻辑判断。但是这同样会发生在生命周期方法上,并且可能某些方法我们并不需要添加这段逻辑,那该怎么办呢?

答案是你可以在Page中定义一个自定义段,不妨叫它authMethods

Page({
    behaviors: [auth],
    //只能包含定义的方法名
    authMethods:['fun1'],
    fun1(){
        console.log('fun1');
    },
    fun2(){
        console.log('fun2');
    },
})

修改Behavior

 //auth.js
 Behavior({
    ...
    definitionFilter(defFields) {
        const authMethods = defFields.authMethods;
        authMethods?.forEach((name) => {
            const f = defFields.methods[name];
            //修改Page中的方法
            if(f){
                defFields.methods[name] = function () {
                    if (/**权限判断 */) {
                      f.call(this);
                    }
                }
            }
      })
    },
   ...
  });

首先拿到自定义段authMethods,然后对它进行遍历,拿到方法名称,只对列表中定义的方法添加额外的逻辑。

当然,这只是一个非常简易的权限判断。

作者自己也定义了一个比较通用的权限判断behavios,欢迎使用。