微信小程序中的behaviors
作者:前端 贾公子
概括
一句话总结: behaviors是用于组件间代码共享的特性, 类似一些编程语言中的'mixin'或者'traits'.
A.每个behaviors包含一组属性、数据、生命周期函数、自定义方法 -> 组件引用它时, 属性、数据、生命周期函数、自定义方法都会被合并到组件中,生命周期函数也会在对应的时机被调用.
B. 每个组件可以引用多个behavior, behavior也可引用其它behavior;
Demo演示
下文主要贴出了主要代码, 可自行拷贝运行.
页面级wxml
// 新建page, 页面级wxml <test-comp></test-comp> // 页面级json { "usingComponents": { "test-comp": "../components/testComp/testComp" } }
组件级wxml
// 新建个组件, 组件级wxml <view>属性: {{myBehaviorProperty}} --- {{myCompProperty}}</view> <view>数据: {{myBehaviorData}} --- {{myCompData}}</view> <view bind:tap="myBehaviorMethod">触发behavior的自定义方法</view> <view bind:tap="myCompMethod">触发组件的自定义方法</view> // 组件级js import testBehavior from './testBehavior' Component({ behaviors: [testBehavior], properties: { myCompProperty: { type: String, value: '' } }, data: { myCompData: 'myCompData' }, created: function (){ console.log('[my-component]- created') }, attached: function (){ console.log('[my-component]- attached') }, ready: function (){ console.log('[my-component]- ready') }, methods: { myCompMethod: function () { console.log('[my-component]- method') } } })
behavior级
// behavior级 export default Behavior({ behaviors: [], properties: { myBehaviorProperty: { type: String, value: 'myBehaviorProperty' } }, data: { myBehaviorData: 'myBehaviorData' }, created: function () { console.log('[my-behavior]- created') }, attached: function () { console.log('[my-behavior]- attached') }, ready: function () { console.log('[my-behavior]- ready') }, methods: { myBehaviorMethod: function () { console.log('[my-behavior]- method') } } })
先来对上述代码做一波解析:
behavior结构:
属性: myBehaviorProperty
数据: myBehaviorData
生命周期: created() && attached() && ready()
自定义方法: myBehaviorMethod
组件引入该behaviors后的结构:
属性: myBehaviorProperty、 myCompProperty
数据: myBehaviorData、myCompData
生命周期: created() && attached() && ready()
自定义方法: myBehaviorMethod、myCompMethod
紧接着, 来看看代码运行结果: 也许你会对输出有疑问, 先不着急, 慢慢往下看.
进阶演示
上面的Demo仅演示了最基础的behaviors的用法, 接下来我们看看遇到同名的属性or数据or生命周期方法or自定义方法, 该属性会做些什么呢?
1. 若具有同名的属性或方法
A. 若组件本身有, 则组件会覆盖behavior;
B. 若存在嵌套子behaviors的情况, 则父behavior会覆盖子behavior;
Demo演示: 基于上面的Demo代码, 追加如下部分
// 新建个组件, 组件级wxml <view bind:tap="sameMethod">同名属性: {{sameProperty}}</view> // 组件级js properties: { sameProperty: { type: String, value: 'sameProperty-myCompProperty' } }, methods: { sameMethod: function (){ console.log('[my-component]- sameMethod') } } // behavior级 properties: { sameProperty: { type: String, value: 'sameProperty-myBehaviorProperty' } }, methods: { sameMethod: function (){ console.log('[my-behavior]- sameMethod') } }
上述代码表现形式如下: 组件的同名属性覆盖了behavior的同名属性; 点击自定义方法, 触发的是组件的自定义方法.
至此, 你会不会好奇如果属性是个object, 是怎么个表现形式呢, 接下来看看实际效果.
// 新建个组件, 组件级wxml <view>同名属性: {{sameProperty && sameProperty.val1}}</view> <view>同名属性: {{sameProperty && sameProperty.val2}}</view> // 组件级js properties: { sameProperty: { type: Object, value: { val1: '[my-component]-同名属性类型是对象' } } } // behavior级 properties: { sameProperty: { type: Object, value: { val1: '[my-behavior]-同名属性类型是对象', val2: '[my-behavior]-体现同名对象类型不会做合并' } } }
上述代码表现形式如下: 同名属性即使是对象类型, 也只会做覆盖,
区别于下文的同名数据的合并操作哦.
2. 若有同名的数据
A. 若数据类型是对象, 进行对象合并;
B. 其它类型会进行数据覆盖, 覆盖原则:组件 > 父behavior > 子behavior; 靠后的behavior > 靠前的behavior;
Demo演示: 针对数据是对象&非对象
// 组件级js data: { sameObj: { val1: '[my-component]-同名数据类型是对象' }, sameData: false }, ready: function (){ console.log('[my-component]- ready') console.log('[my-behavior]- 同名数据', this.data.sameObj, this.data.sameData) }, // behavior级 data: { sameObj: { val1: '[my-behavior]-同名数据类型是对象', val2: '[my-behavior]-体现同名数据类型做合并' }, sameData: true },
上述代码表现形式如下: 同名数据对象做合并, 同名数据非对象做覆盖.
3. 若有同名的生命周期函数
不会被覆盖、而是在对应的触发时机内逐个调用:
A. 不同的生命周期之间, 遵循组件生命周期的执行顺序;
B. 同种生命周期函数:
①. behavior优先于组件执行;
②. 子behavior优先于父behavior执行;
③. 靠前的behavior优先于靠后的behavior执行;
C. 如果同一个 behavior 被一个组件多次引用,它定义的生命周期函数只会被执行一次;
应用场景
相信到了这里, 你应该明白了Demo演示中控制台的输出是基于什么来输出的, 接下来我们看看什么样的应用场景会考虑使用该属性呢?
如下图, 有个中间弹窗组件&&底部弹窗组件, 均内聚有如下功能点:
A. 触发某一条件后, 出现该弹窗;
B. 点击遮罩层, 关闭弹窗;
考虑下如果将弹窗显示跟隐藏的逻辑放在behaviors里面, 是否能避免同份代码逻辑写2遍的问题呢.
Page中不能使用behaviors、只能在Components中使用!!!!!! 故若遇到真想使用behaviors属性的页面, 试试把某块页面内容抽离成组件, 然后引用组件的方式去实现.
最后
behaviors
是用于组件间代码共享的特性,类似于一些编程语言中的 “mixins” 或 “traits”。
每个 behavior
可以包含一组属性、数据、生命周期函数和方法。组件引用它时,它的属性、数据和方法会被合并到组件中,生命周期函数也会在对应时机被调用。 每个组件可以引用多个 behavior
,behavior
也可以引用其它 behavior
。
属性&方法
注册一个 behavior
,接受一个 Object
类型的参数。
定义段 | 类型 | 是否必填 | 描述 | 最低版本 |
---|---|---|---|---|
properties | Object Map | 否 | 组件的对外属性,是属性名到属性设置的映射表 | |
data | Object | 否 | 组件的内部数据,和 properties 一同用于组件的模板渲染 | |
observers | Object | 否 | 组件数据字段监听器,用于监听 properties 和 data 的变化,参见 数据监听器 | 2.6.1 |
methods | Object | 否 | 组件的方法,包括事件响应函数和任意的自定义方法,关于事件响应函数的使用,参见 组件间通信与事件 | |
behaviors | String Array | 否 | 类似于mixins和traits的组件间代码复用机制,参见 behaviors | |
created | Function | 否 | 组件生命周期函数-在组件实例刚刚被创建时执行,注意此时不能调用 setData ) | |
attached | Function | 否 | 组件生命周期函数-在组件实例进入页面节点树时执行) | |
ready | Function | 否 | 组件生命周期函数-在组件布局完成后执行) | |
moved | Function | 否 | 组件生命周期函数-在组件实例被移动到节点树另一个位置时执行) | |
detached | Function | 否 | 组件生命周期函数-在组件实例被从页面节点树移除时执行) | |
relations | Object | 否 | 组件间关系定义,参见 组件间关系 | |
lifetimes | Object | 否 | 组件生命周期声明对象,参见 组件生命周期 | 2.2.3 |
pageLifetimes | Object | 否 | 组件所在页面的生命周期声明对象,参见 组件生命周期 | 2.2.3 |
definitionFilter | Function | 否 | 定义段过滤器,用于自定义组件扩展,参见 自定义组件扩展 | 2.2.3 |
组件中使用
组件引用时,在 behaviors
定义段中将它们逐个列出即可。
代码示例:
// my-component.js var myBehavior = require('my-behavior') Component({ behaviors: [myBehavior], properties: { myProperty: { type: String } }, data: { myData: 'my-component-data' }, created: function () { console.log('[my-component] created') }, attached: function () { console.log('[my-component] attached') }, ready: function () { console.log('[my-component] ready') }, methods: { myMethod: function () { console.log('[my-component] log by myMethod') }, } })
在上例中, my-component
组件定义中加入了 my-behavior
,
而 my-behavior
结构为:
- 属性:
myBehaviorProperty
- 数据字段:
myBehaviorData
- 方法:
myBehaviorMethod
- 生命周期函数:
attached
、created
、ready
这将使 my-component
最终结构为:
- 属性:
myBehaviorProperty
、myProperty
- 数据字段:
myBehaviorData
、myData
- 方法:
myBehaviorMethod
、myMethod
- 生命周期函数:
attached
、created
、ready
当组件触发生命周期时,上例生命周期函数执行顺序为:
[my-behavior] created
[my-component] created
[my-behavior] attached
[my-component] attached
[my-behavior] ready
[my-component] ready
详细规则参考 同名字段的覆盖和组合规则。
同名字段的覆盖和组合规则
组件和它引用的 behavior
中可以包含同名的字段,对这些字段的处理方法如下:
- 如果有同名的属性 (properties) 或方法 (methods):
- 若组件本身有这个属性或方法,则组件的属性或方法会覆盖 behavior 中的同名属性或方法;
- 若组件本身无这个属性或方法,则在组件的 behaviors 字段中定义靠后的 behavior 的属性或方法会覆盖靠前的同名属性或方法;
- 在 2 的基础上,若存在嵌套引用 behavior 的情况,则规则为:引用者 behavior 覆盖 被引用的 behavior 中的同名属性或方法。
- 如果有同名的数据字段 (data):
- 若同名的数据字段都是对象类型,会进行对象合并;
- 其余情况会进行数据覆盖,覆盖规则为: 引用者 behavior > 被引用的 behavior 、 靠后的 behavior > 靠前的 behavior。(优先级高的覆盖优先级低的,最大的为优先级最高)
- 生命周期函数和 observers 不会相互覆盖,而是在对应触发时机被逐个调用:
- 对于不同的生命周期函数之间,遵循组件生命周期函数的执行顺序;
- 对于同种生命周期函数和同字段 observers ,遵循如下规则:
- behavior 优先于组件执行;
- 被引用的 behavior 优先于 引用者 behavior 执行;
- 靠前的 behavior 优先于 靠后的 behavior 执行;
- 如果同一个 behavior 被一个组件多次引用,它定义的生命周期函数和 observers 不会重复执行。
到此这篇关于微信小程序之behaviors的文章就介绍到这了,更多相关微信小程序behaviors内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!