小程序自定义组件学习笔记

1.监听小程序组件的属性值变化

我们可以使用两种形式,一种是给observer直接定义一个函数,另一种是observer调用methods中的方法

此处不能使用箭头函数,否则this会报undefined

javascript 复制代码
show: {
  // 显示隐藏导航,隐藏的时候navigation-bar的高度占位还在
  type: Boolean,
  value: true,
  observer: function(newVal,oldVal){
  }
}

直接写methods中的方法名即可

javascript 复制代码
show: {
  // 显示隐藏导航,隐藏的时候navigation-bar的高度占位还在
  type: Boolean,
  value: true,
  observer: '_showChange'
}

2.组件间通信

父组件可以通过this.selectComponent获取子组件的实例对象,这样可以直接访问子组件的任何数据和方法

3.behavior

用于组件间共享代码,类似于编程语言中的mixins。每个behavior可以包含一组属性、数据、方法和生命周期,组件引用它时,它的属性、数据和方法会被合并到组件中,生命周期也会在对应的时机被调用。每个组件可以引用多个behavior,每个behavior也可以引用其他behavior

如果组件中存在同名的属性和方法,则组件的属性和方法会覆盖behavior中的属性和方法。靠后的behavior中的属性和方法,会覆盖靠前的behavior属性和方法。

生命周期函数:behavior会优先于组件执行,被引用的behavior会优先于引用的behavior执行。靠前的behavior会优先于靠后的behavior执行。

javascript 复制代码
module.exports = Behavior({
  behaviors: [],
  properties: {
    myBehaviorProperty: {
      type: String
    }
  },
  data: {
    myBehaviorData: {}
  },
  attached: function(){},
  methods: {
    myBehaviorMethod: function(){}
  }
})

4.监听组件属性值变化

observers,类似于vue中的watch

javascript 复制代码
Component({
  attached: function() {
    this.setData({
      numberA: 1,
      numberB: 2,
    })
  },
  observers: {
    'numberA, numberB': function(numberA, numberB) {
      // 在 numberA 或者 numberB 被设置时,执行这个函数
      this.setData({
        sum: numberA + numberB
      })
    }
  }
})

5.组件间关系

在下面的案例中,custom-ui和custom-li都是自定义组件,他们之间有相互依赖关系,组件间通信往往很复杂,此时可以在组件定义时加入relations,可以解决这问题.

html 复制代码
<custom-ul>
  <custom-li> item 1 </custom-li>
  <custom-li> item 2 </custom-li>
</custom-ul>
javascript 复制代码
// path/to/custom-ul.js
Component({
  relations: {
    './custom-li': {
      type: 'child', // 关联的目标节点应为子节点
      linked: function(target) {
        // 每次有custom-li被插入时执行,target是该节点实例对象,触发在该节点attached生命周期之后
      },
      linkChanged: function(target) {
        // 每次有custom-li被移动后执行,target是该节点实例对象,触发在该节点moved生命周期之后
      },
      unlinked: function(target) {
        // 每次有custom-li被移除时执行,target是该节点实例对象,触发在该节点detached生命周期之后
      }
    }
  },
  methods: {
    _getAllLi: function(){
      // 使用getRelationNodes可以获得nodes数组,包含所有已关联的custom-li,且是有序的
      var nodes = this.getRelationNodes('path/to/custom-li')
    }
  },
  ready: function(){
    this._getAllLi()
  }
})
javascript 复制代码
// path/to/custom-li.js
Component({
  relations: {
    './custom-ul': {
      type: 'parent', // 关联的目标节点应为父节点
      linked: function(target) {
        // 每次被插入到custom-ul时执行,target是custom-ul节点实例对象,触发在attached生命周期之后
      },
      linkChanged: function(target) {
        // 每次被移动后执行,target是custom-ul节点实例对象,触发在moved生命周期之后
      },
      unlinked: function(target) {
        // 每次被移除时执行,target是custom-ul节点实例对象,触发在detached生命周期之后
      }
    }
  }
})

6.纯数据字段

如果一些数据不用于界面渲染,可以把它设置成春数据字段。这样可以提供页面性能

指定纯数据字段的方法是在Component的options属性中,指定pureDataPattern为一个正则表达式,字段名符合这个正则表达式的字段,就是纯数据字段。纯数据字段不能参与页面渲染。

javascript 复制代码
Component({
  options: {
    pureDataPattern: /^_/ // 指定所有 _ 开头的数据字段为纯数据字段
  },
  data: {
    a: true, // 普通数据字段
    _b: true, // 纯数据字段
  },
  methods: {
    myMethod() {
      this.data._b // 纯数据字段可以在 this.data 中获取
      this.setData({
        c: true, // 普通数据字段
        _d: true, // 纯数据字段
      })
    }
  }
})

属性也可以被指定为纯数据字段,同样,属性也不能参与wxml渲染。纯数据字段的属性的observer永远不会被触发,如果需要监听其变化,可以使用数据监听器

javascript 复制代码
Component({
  options: {
    pureDataPattern: /^_/
  },
  properties: {
    a: Boolean,
    _b: {
      type: Boolean,
      observer() {
        // 不要这样做!这个 observer 永远不会被触发
      }
    },
  }
})

也可以在页面或者自定义组件的json中配置pureDataPattern,但此时的pureDataPattern是一个字符串,而不是正则表达式

javascript 复制代码
{
  "pureDataPattern": "^_"
}

7.抽象节点

有时候,自定义组件模板中的一些节点,其对应的自定义组件不是由自定义组件本身决定的,而是由自定义组件的调用者决定的,这时候可以把这个节点声明为抽象节点。

html 复制代码
<!-- selectable-group.wxml -->
<view wx:for="{{labels}}">
  <label>
    <selectable disabled="{{false}}"></selectable>
    {{item}}
  </label>
</view>

其中,"selectable"不是任何在 json 文件的 usingComponents 字段中声明的组件,而是一个抽象节点。它需要在 componentGenerics 字段中声明。

json 复制代码
{
  "componentGenerics": {
    "selectable": true
  }
}

在使用 selectable-group 组件时,必须指定"selectable"具体是哪个组件:

ini 复制代码
<selectable-group generic:selectable="custom-radio" />

这样,在生成这个 selectable-group 组件的实例时,"selectable"节点会生成"custom-radio"组件实例。这个custom-radio需要包含在组件json的usingComponents字段中。

json 复制代码
{
  "usingComponents": {
    "custom-radio": "path/to/custom/radio",
    "custom-checkbox": "path/to/custom/checkbox"
  }
}

抽象节点可以指定一个默认组件,当具体组件未被指定时,将创建默认组件的实例。默认组件可以在 componentGenerics 字段中指定:

json 复制代码
{
  "componentGenerics": {
    "selectable": {
      "default": "path/to/default/component"
    }
  }
}

节点的 generic 引用 generic:xxx="yyy" 中,值 yyy 只能是静态值,不能包含数据绑定。因而抽象节点特性并不适用于动态决定节点名的场景

8.自定义组件扩展

behavior提供了新的自定义字段,definitionFilter用于支持自定义组件扩展。

案例:实现组件的computed属性

javascript 复制代码
// behavior.js
module.exports = Behavior({
  lifetimes: {
    created() {
      this._originalSetData = this.setData // 原始 setData
      this.setData = this._setData // 封装后的 setData
    }
  },
  definitionFilter(defFields) {
    const computed = defFields.computed || {}
    const computedKeys = Object.keys(computed)
    const computedCache = {}

    // 计算 computed
    const calcComputed = (scope, insertToData) => {
      const needUpdate = {}
      const data = defFields.data = defFields.data || {}

      for (let key of computedKeys) {
        const value = computed[key].call(scope) // 计算新值
        if (computedCache[key] !== value) needUpdate[key] = computedCache[key] = value
        if (insertToData) data[key] = needUpdate[key] // 直接插入到 data 中,初始化时才需要的操作
      }

      return needUpdate
    }

    // 重写 setData 方法
    defFields.methods = defFields.methods || {}
    defFields.methods._setData = function (data, callback) {
      const originalSetData = this._originalSetData // 原始 setData
      originalSetData.call(this, data, callback) // 做 data 的 setData
      const needUpdate = calcComputed(this) // 计算 computed
      originalSetData.call(this, needUpdate) // 做 computed 的 setData
    }

    // 初始化 computed
    calcComputed(defFields, true) // 计算 computed
  }
})

9.占位组件

自定义组件所引用的其他自定义组件,在刚开始进行渲染时可能处于不可用的状态。此时,为了使渲染过程不被阻塞,可以说使用占位组件。

页面或自定义组件对应的 JSON 配置中的 componentPlaceholder 字段用于指定占位组件,如:

json 复制代码
{
  "usingComponents": {
    "comp-a": "../comp/compA",
    "comp-b": "../comp/compB",
    "comp-c": "../comp/compC"
  },
  "componentPlaceholder": {
    "comp-a": "view",
    "comp-b": "comp-c"
  }
}
相关推荐
xkxnq4 小时前
微信小程序地理定位功能
微信小程序·小程序
難釋懷4 小时前
微信小程序全局数据共享
微信小程序·小程序
xmdoor11 小时前
微信小程序:酒店预订管理系统
微信小程序·酒店预订·酒店系统·酒店管理
The_era_achievs_hero1 天前
微信小程序141~150
微信小程序·小程序·notepad++
熊猫片沃子1 天前
小程序间跳转与传值实现方案
前端·微信小程序
normi-D181 天前
微信小程序未登录状态下的导航拦截有哪些方法可以实现
微信小程序·小程序
wocwin1 天前
uniapp微信小程序vue3封装时间段范围选择组件
vue.js·微信小程序
晓风伴月2 天前
微信小程序:在ios中border边框显示不全
ios·微信小程序·小程序
新酱爱学习2 天前
前端海报生成的几种方式:从 Canvas 到 Skyline
前端·javascript·微信小程序