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

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"
  }
}
相关推荐
從南走到北11 小时前
西陆房产系统小程序
微信·微信小程序·小程序
黑马源码库miui5208613 小时前
同城派送小程序
微信小程序·小程序
全职计算机毕业设计17 小时前
基于微信小程序的运动康复中心预约系统的设计与实现(SpringBoot+Vue+Uniapp)
vue.js·spring boot·微信小程序
知识分享小能手2 天前
uni-app 入门学习教程,从入门到精通,uni-app组件 —— 知识点详解与实战案例(4)
前端·javascript·学习·微信小程序·小程序·前端框架·uni-app
韩立学长2 天前
基于微信小程序的公益捐赠安全平台9hp4t247 包含完整开发套件(程序、源码、数据库、调试部署方案及开发环境)系统界面展示及获取方式置于文档末尾,可供参考。
数据库·微信小程序·小程序
亮子AI2 天前
【小程序】微信小程序点击效果(view、button、navigator)
微信小程序·小程序
Q_Q5110082852 天前
python+uniapp基于微信小程序团购系统
spring boot·python·微信小程序·django·uni-app·node.js·php
炒毛豆2 天前
uniapp微信小程序+vue3基础内容介绍~(含标签、组件生命周期、页面生命周期、条件编译(一码多用)、分包))
vue.js·微信小程序·uni-app
從南走到北2 天前
洗车小程序系统
微信小程序·小程序
namehu2 天前
前端性能优化之:图片缩放 🚀
前端·性能优化·微信小程序