微信小程序 Behaviors 机制详解:代码复用、合并与覆盖规则

作者:清欢

时间:2026-10-31

浏览:325

本文深入解析微信小程序中 behaviors 的代码复用机制。详细介绍 behaviors 如何合并属性、数据、生命周期及自定义方法,并重点阐述同名字段的覆盖优先级:属性与方法由组件优先覆盖,数据对象进行合并而基本类型按引用顺序覆盖,生命周期函数则按特定顺序逐个执行。通过代码示例展示实际应用与注意事项。

文章目录

概述

总结:behaviors 是微信小程序中用于实现组件间代码复用的功能,其作用类似于其他编程语言中的 mixin 或 traits。

A. 每个 behaviors 包含一组属性、数据、生命周期函数和自定义方法。当组件引用 behaviors 时,这些内容会被合并到组件中,且生命周期函数会在对应的时机被调用。 B. 每个组件可以引用多个 behaviors,且 behaviors 之间也可以相互引用。

基础演示

下文主要展示核心代码,读者可自行拷贝运行以验证效果。

页面级 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 的最基础用法。接下来探讨当遇到同名的属性、数据、生命周期方法或自定义方法时,系统如何处理这些冲突。

1. 若具有同名的属性或方法

A. 若组件本身定义了同名属性或方法,则组件的定义会覆盖 behaviors 中的定义; B. 若存在嵌套子 behaviors 的情况,则父 behaviors 的定义会覆盖子 behaviors 的定义;

演示代码:基于上述 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')
  }
}

上述代码运行表现如下:组件的同名属性覆盖了 behaviors 中的同名属性;点击自定义方法时,触发的是组件的自定义方法。

概述

至此,读者可能会好奇如果属性是 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. 其他类型的数据会进行覆盖,覆盖原则如下:

组件 > 父 behaviors > 子 behaviors;靠后的 behaviors 引用优先级高于靠前的 behaviors;

演示代码:针对数据是对象与非对象两种情况

// 组件级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. 同种生命周期函数: ①. behaviors 优先于组件执行; ②. 子 behaviors 优先于父 behaviors 执行; ③. 靠前的 behaviors 优先于靠后的 behaviors 执行; C. 如果同一个 behaviors 被一个组件多次引用,它定义的生命周期函数只会被执行一次;

应用场景

相信到这里,你已经明白了 Demo 中控制台输出的依据。接下来探讨哪些应用场景适合使用 behaviors。 如下图所示,有一个中间弹窗组件和一个底部弹窗组件,它们均内聚了以下功能点: A. 触发某一条件后,显示该弹窗; B. 点击遮罩层,关闭弹窗;

概述

如果将弹窗显示与隐藏的逻辑封装在 behaviors 中,是否就能避免在两份代码中重复编写相同的逻辑呢?

注意:Page 中不能使用 behaviors,只能在 Components 中使用。因此,若页面确实需要 behaviors 的功能,建议将相关页面内容抽离为组件,然后通过引用组件的方式来实现。

总结

behaviors 是用于组件间代码共享的特性,类似于一些编程语言中的 “mixins” 或 “traits”。

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

属性与方法

注册一个 behavior,接受一个 Object 类型的参数。

定义段类型是否必填描述最低版本
propertiesObject Map否组件的对外属性,是属性名到属性设置的映射表
dataObject否组件的内部数据,和 properties 一同用于组件的模板渲染
observersObject否组件数据字段监听器,用于监听 properties 和 data 的变化,参见 数据监听器2.6.1
methodsObject否组件的方法,包括事件响应函数和任意的自定义方法,关于事件响应函数的使用,参见 组件间通信与事件
behaviorsString Array否类似于mixins和traits的组件间代码复用机制,参见 behaviors
createdFunction否组件生命周期函数-在组件实例刚刚被创建时执行,注意此时不能调用 setData )
attachedFunction否组件生命周期函数-在组件实例进入页面节点树时执行)
readyFunction否组件生命周期函数-在组件布局完成后执行)
movedFunction否组件生命周期函数-在组件实例被移动到节点树另一个位置时执行)
detachedFunction否组件生命周期函数-在组件实例被从页面节点树移除时执行)
relationsObject否组件间关系定义,参见 组件间关系
lifetimesObject否组件生命周期声明对象,参见 组件生命周期2.2.3
pageLifetimesObject否组件所在页面的生命周期声明对象,参见 组件生命周期2.2.3
definitionFilterFunction否定义段过滤器,用于自定义组件扩展,参见 自定义组件扩展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内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章