《十一》微信小程序中自定义组件的 Component()

Component(): 用来创建自定义组件。接受一个 Object 类型的参数,可以指定组件的属性、数据、方法等。

  1. 使用 Component 构造器构造组件:

    Component({
      // 配置选项
      options: {},
      // 传入的数据:在 properties 定义段中,属性名采用驼峰写法(propertyName);在 wxml 中,指定属性值时则对应使用连字符写法(property-name=""),应用于数据绑定时采用驼峰写法(attr="propertyName")
      properties: {
        myProperty: { 
          type: String,
          value: ''
        },
        myProperty2: String // 简化的定义方式
      },
      // 内部的数据
      data: {}, 
      // 类似于 mixins 和 traits 的组件间代码复用机制
      behaviors: [],
      // 数据监听器,用于监听 properties 和 data 的变化
      observers:{},
      // 组件间关系定义
      relations: {},
      // 外部样式类
      externalClasses: [],
      // 组件生命周期声明对象
      lifetimes: {
        attached: function () { },
        moved: function () { },
        detached: function () { },
      },
      // 组件所在页面的生命周期声明对象
      pageLifetimes: {
        show: function () { },
        hide: function () { },
        resize: function () { },
      },
      // 方法,包括事件响应函数和任意的自定义方法
      methods: {
        onMyButtonTap: function(){},
        // 内部方法建议以下划线开头
        _myPrivateMethod: function(){},
      },
    })
    
  2. 使用 Component 构造器构造页面:小程序的页面也可以视为自定义组件,因此页面也可以使用 Component 构造器构造,拥有与普通组件一样的定义段与实例方法。

    使用 Component 构造器来构造页面的一个好处是可以使用 behaviors 来提取所有页面中公用的代码段。

    此时:

    • 要求对应 json 文件中包含 usingComponents 定义段。
      {
        "usingComponents": {}
      }
      
    • 页面的生命周期方法(即 on 开头的方法),应写在 methods 定义段中。
      Component({
        methods: {
          onLoad: function() {}
        }
      })
      
    • 组件的属性可以用于接收页面的参数,如访问页面 /pages/index/index?paramA=123&paramB=xyz ,如果声明有属性 paramA 或 paramB ,则它们会被赋值为 123 或 xyz 。
      Component({
        properties: {
          paramA: Number,
          paramB: String,
        },
        methods: {
          onLoad: function() {
            this.data.paramA // 页面参数 paramA 的值
            this.data.paramB // 页面参数 paramB 的值
          }
        }
      })
      

生命周期:

组件的生命周期:

组件的生命周期,指的是组件自身的一些函数,这些函数在特殊的时间点或遇到一些特殊的事件时被自动触发。可以直接定义在 Component 构造器的第一级参数中;也可以在 lifetimes 字段内进行声明(这是推荐的方式,其优先级最高)。

组件的生命周期函数:

  1. created:在组件实例刚刚被创建时执行。

    此时还不能调用 setData 。

  2. attached: 在组件实例进入页面节点树时执行。

    绝大多数初始化工作可以在这个生命周期进行。

  3. ready:在组件在视图层布局完成后执行。
  4. moved:在组件实例被移动到节点树另一个位置时执行。
  5. detached:在组件实例被从页面节点树移除时执行。
  6. error:每当组件方法抛出错误时执行。
Component({
  lifetimes: {
    attached: function() {},
    detached: function() {},
  },
  // 以下是旧式的定义方式,可以保持对 <2.2.3 版本基础库的兼容
  attached: function() {},
  detached: function() {},
})

组件所在页面的生命周期:

组件所在页面的生命周期在 pageLifetimes 定义段中定义。

  1. show:组件所在的页面被展示时执行。
  2. hide:组件所在的页面被隐藏时执行。
  3. resize:组件所在的页面尺寸变化时执行。
Component({
   // 组件所在页面的生命周期声明对象
  pageLifetimes: {
    // 组件所在的页面被展示时执行
    show: function () { }, 
  },
})

自定义组件和页面生命周期函数的执行顺序:

页面引用自定义组件,初次加载的生命周期函数执行顺序:

请添加图片描述

behaviors:

behaviors 是用于组件间代码共享的特性,类似于一些框架中的 mixins 混入。

每个 behavior 可以包含一组属性、数据、生命周期函数和方法。组件引用它时,它的属性、数据和方法会被合并到组件中,生命周期函数也会在对应时机被调用。

每个组件可以引用多个 behavior ,behavior 也可以引用其它 behavior 。

定义 behavior:

Behavior():注册一个 behavior,接受一个 Object 类型的参数。

// 定义 behavior
// my-behavior.js
export default Behavior({
  // 引入的其它 behavior
  behaviors: [],
  // 属性
  properties: {
    myBehaviorProperty: {
      type: String
    }
  },
  // 数据
  data: {
    myBehaviorData: {}
  },
  // 数据字段监听器
  observers: {},
  // 生命周期声明对象
  lifetimes: {},
  // 所在页面的生命周期声明对象
  pageLifetimes: {}.
  // 方法
  methods: {
    myBehaviorMethod: function(){}
  }
})

使用 behavior:

组件引用时,在 behaviors 定义段中将它们逐个列出即可。

Page 中不能使用 behaviors。

// 组件中使用 behavior
// my-component.js
import myBehavior from 'my-behavior'
Component({
  behaviors: [myBehavior],
})

同名字段的覆盖和组合原则:

组件和它引用的 behavior 中可以包含同名的字段,对这些字段的处理方法如下:

  1. 如果有同名的属性 properties 或方法 methods:
    • 若组件本身有这个属性或方法,则组件的属性或方法会覆盖 behavior 中的同名属性或方法;
    • 若组件本身无这个属性或方法,则在组件的 behaviors 字段中定义靠后的 behavior 的属性或方法会覆盖靠前的同名属性或方法;
    • 在 2 的基础上,若存在嵌套引用 behavior 的情况,则规则为:父 behavior 覆盖子 behavior 中的同名属性或方法;
  2. 如果有同名的数据字段 data:
    • 若同名的数据字段都是对象类型,会进行对象合并;
    • 其余情况会进行数据覆盖,覆盖规则为:组件 > 父 behavior > 子 behavior 、 靠后的 behavior > 靠前的 behavior。(优先级高的覆盖优先级低的,最大的为优先级最高);
  3. 生命周期函数不会相互覆盖,而是在对应触发时机被逐个调用:
    • 对于不同的生命周期函数之间,遵循组件生命周期函数的执行顺序;
    • 对于同种生命周期函数,遵循如下规则:behavior 优先于组件执行、子 behavior 优先于 父 behavior 执行、靠前的 behavior 优先于靠后的 behavior 执行;
    • 如果同一个 behavior 被一个组件多次引用,它定义的生命周期函数只会被执行一次;

内置 behaviors:

自定义组件可以通过引用内置的 behavior 来获得内置组件的一些行为。

内置 behavior 往往会为组件添加一些属性。
在没有特殊说明时,组件可以覆盖这些属性来改变它的 type 或添加 observer 。

  1. wx://form-field:使自定义组件有类似于表单控件的行为。 form 组件可以识别这些自定义组件,并在 submit 事件中返回组件的字段名及其对应字段值。
  2. wx://form-field-group:使 form 组件可以识别到这个自定义组件内部的所有表单控件。
  3. wx://form-field-button:使 form 组件可以识别到这个自定义组件内部的 button 。如果自定义组件内部有设置了 form-type 的 button ,它将被组件外的 form 接受。
  4. wx://component-export:使自定义组件支持 export 定义段。这个定义段可以用于指定组件被 selectComponent 调用时的返回值。
Component({
  behaviors: ['wx://form-field']
})

数据监听器 observers:

数据监听器可以用于监听和响应任何属性和数据字段的变化。

数据监听器监听的是 setData 涉及到的数据字段,即使这些数据字段的值没有发生变化,数据监听器依然会被触发。
如果在数据监听器函数中使用 setData 设置本身监听的数据字段,可能会导致死循环。

例如, this.data.sum 永远是 this.data.numberA 与 this.data.numberB 的和。此时,可以使用数据监听器进行如下实现:

Component({
  observers: {
    'numberA, numberB': function(numberA, numberB) {
      // 在 numberA 或者 numberB 被设置时,执行这个函数
      this.setData({
        sum: numberA + numberB
      })
    }
  }
})

数据监听器支持监听属性或内部数据的变化,可以同时监听多个。一次 setData 最多触发每个监听器一次。

Component({
  observers: {
    'some.subfield': function(subfield) {
      // 使用 setData 设置 this.data.some.subfield 时触发;除此以外,使用 setData 设置 this.data.some 也会触发
      subfield === this.data.some.subfield
    },
    'arr[12]': function(arr12) {
      // 使用 setData 设置 this.data.arr[12] 时触发;除此以外,使用 setData 设置 this.data.arr 也会触发
      arr12 === this.data.arr[12]
    },
  }
})

如果需要监听所有子数据字段的变化,可以使用通配符 **

Component({
  observers: {
    'some.field.**': function(field) {
      // 使用 setData 设置 this.data.some.field 本身或其下任何子数据字段时触发;除此以外,使用 setData 设置 this.data.some 也会触发
      field === this.data.some.field
    },
  }
})

仅使用通配符 ** 可以监听全部 setData 。

Component({
  observers: {
    '**': function() {
      // 每次 setData 都触发
    },
  }
})

组件间关系 relations:

当两个自定义组件之间存在嵌套关系时,可以在两个组件中定义 relations,从而可以直接访问对方组件的实例对象。

必须在两个组件中都定义 relations,否则不会生效。

relations 定义段包含目标组件路径及其对应选项。

选项:

  1. type:目标组件的相对关系,可选的值为 parent 、 child 、 ancestor 、 descendant。
  2. linked:关系生命周期函数,当关系被建立在页面节点树中时触发,触发时机在组件 attached 生命周期之后。
  3. linkChanged:关系生命周期函数,当关系在页面节点树中发生改变时触发,触发时机在组件 moved 生命周期之后。
  4. unlinked:关系生命周期函数,当关系脱离页面节点树时触发,触发时机在组件 detached 生命周期之后。
  5. target:如果这一项被设置,则它表示关联的目标节点所应具有的 behavior,所有拥有这一 behavior 的组件节点都会被关联。

定义组件间关系后,可以通过 getRelationNodes(path) 方法获取到路径对应的组件实例组成的数组。通过该方法,可以直接获取到关联组件的 properties 属性、data 数据等,并且能够调用关联组件中的方法,修改关联组件实例的变量。

然后可以通过对应组件的 setData() 方法,修改组件实例的变量

当关联组件不止一个的时候,数组会包含所有的组件实例,并按照文档流的顺序排列。

例如:custom-ul 和 custom-li 都是自定义组件,它们存在嵌套关系。

<!-- index.wxml -->
<!-- custom-ul 和 custom-li 都是自定义组件,在 index.wxml 中引入它们并使其形成嵌套关系 -->
<custom-ul>
  <!-- custom-li 通过 slot 渲染到 custom-ul 中 -->
  <custom-li></custom-li>
</custom-ul>
<!-- custon-ul.wxml -->
<view>
  <view class="header">我是自定义的 ul</view>
  <slot></slot>
</view>

// custom-ul.js
Component({
  relations: {
    '../custom-li/custom-li': {
      type: 'child', // 关联的目标节点应为子节点
      linked: function(target) {
        // 每次有 custom-li 插入时触发,target 是插入的 custom-li 节点的实例对象
      },
    }
  },
  lifetimes: {
  	 ready: function(){
    	this.getLiNodes()
  	}
  },
  methods: {
    getLiNodes: function(){
      // 使用 getRelationNodes() 可以获得 nodes 数组,包含所有已关联的且有序的 custom-li 实例对象
      const nodes = this.getRelationNodes('../custom-li/custom-li')
      console.log(nodes[0].data)
    }
  },
})
// custom-li.js
Component({
  relations: {
    '../custom-ul/custom-ul': {
      type: 'parent', // 关联的目标节点应为父节点
      linked: function(target) {
        // 每次被插入到 custom-ul 时执行,target 是被插入的 custom-ul 节点的实例对象
      },
    }
  },
  lifetimes: {
  	 ready: function(){
    	this.getUlNodes()
  	}
  },
  methods: {
    getUlNodes: function(){
      // 使用 getRelationNodes() 可以获得 nodes 数组,包含所有已关联的且有序的 custom-ul 实例对象
      const nodes = this.getRelationNodes('../custom-ul/custom-ul')
      nodes[0].setData({type: 'ul'})
    }
  },
})

自定义组件扩展:

自定义组件扩展其实就是提供了修改自定义组件定义段的能力。Behavior() 构造器提供了新的定义段 definitionFilter ,用于支持自定义组件扩展。 definitionFilter 是一个函数,在被调用时会注入两个参数,第一个参数是使用该 behavior 的 component/behavior 的定义对象,第二个参数是该 behavior 所使用的 behavior 的 definitionFilter 函数列表。

// 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
  }
})

纯数据字段:

纯数据字段是一些不用于界面渲染的 data 字段,可以用于提升页面更新性能。指定纯数据字段的方法是在 Component 构造器的 options 定义段中指定 pureDataPattern 为一个正则表达式,字段名符合这个正则表达式的字段将成为纯数据字段。

Component({
  options: {
    pureDataPattern: /^_/,
  },
})

有些情况下,某些 properties 和 data 中的字段既不会展示在页面上,也不会传递给其他组件,仅仅在当前组件内部使用。此时,可以指定这样的数据字段为“纯数据字段”,它们将仅仅被记录在 this.data 中,而不参与任何界面渲染过程,这样有助于提升页面更新性能。

可以使用数据监听器监听纯数据字段。

Component({
  options: {
    pureDataPattern: /^_/ // 指定所有 _ 开头的数据字段为纯数据字段
  },
  properties: {
  	 // 普通属性字段
    c: {
      type: Boolean,
      value: false,
    },
     // 纯数据属性字段
    _d: {
      type: Boolean,
      value: false,
    },
  }
  data: {
    a: true, // 普通数据字段
    _b: true, // 纯数据字段
  },
  methods: {
    myMethod() {
      this.setData({
        c: true, // 普通数据字段
        _d: true, // 纯数据字段
      })
    }
  }
})

<view wx:if="{{a}}"> 这行会被展示 </view>
<view wx:if="{{_b}}"> 这行不会被展示 </view>
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值