---
title: Component
summary: "介绍 Component() 构造器的完整配置项，包括属性、数据监听、生命周期、组件通信及样式隔离等。"
questions:
  - Component 构造器接受哪些配置项？
  - 组件实例 this 上有哪些常用属性和方法？
  - styleIsolation 有哪些取值，各代表什么含义？
  - 如何定义和使用组件的 properties？
  - observers 数据监听器的使用方式和注意事项有哪些？
  - 组件的生命周期函数有哪些，分别在什么时候触发？
  - 如何实现组件间的通信与事件传递？
  - 组件模板中 slot 的使用方式是什么？
  - 什么是纯数据字段，如何使用 pureDataPattern 优化性能？
  - relations 组件间关系如何定义和使用？
---

## Component(config: Object)

注册自定义组件，接受一个 `Object` 参数，用于描述组件的逻辑交互行为。

```js
// 文件 /components/foo/index.js
Component({
  options: Object,
  properties: Object,
  observers: Object,
  data: Object,
  methods: Object,
  behaviors: Array,
  lifetimes: Object,
  pageLifetimes: Object,
  relations: Array,
});
```

完整的配置项如上所示，在自定义组件内部可通过 `this` 关键字访问实例对象。

## 组件 this 实例

### 属性

| 属性       | 类型   | 描述                                               |
| ---------- | ------ | -------------------------------------------------- |
| is         | String | 组件的文件路径                                     |
| id         | String | 节点 id                                            |
| dataset    | String | 节点 dataset                                       |
| data       | Object | 组件数据，**包括内部数据和属性值**                 |
| properties | Object | 组件数据，**包括内部数据和属性值**（与 data 一致） |

### 方法

| 方法名                     | 参数                                             | 描述                                                                                                                             |
| -------------------------- | ------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------- |
| setData                    | Object `newData`                                 | 设置 data 并执行视图层渲染                                                                                                       |
| triggerEvent               | String `name`, Object `detail`, Object `options` | 触发事件，参见 [组件间通信与事件](#组件间通信与事件)                                                                             |
| createSelectorQuery        |                                                  | 创建一个 [SelectorQuery](/cn/miniapp/develop/miniapp/api/tyml/SelectorQuery/SelectorQuery) 对象，选择器选取范围为这个组件实例内          |
| createIntersectionObserver |                                                  | 创建一个 [IntersectionObserver](/cn/miniapp/develop/miniapp/api/tyml/IntersectionObserver/IntersectionObserver) 对象，选择器选取范围为这个组件实例内 |
| selectComponent            | String `selector`                                | 使用选择器选择组件实例节点，返回匹配到的第一个组件实例对象                                                                       |
| selectAllComponents        | String `selector`                                | 使用选择器选择组件实例节点，返回匹配到的全部组件实例对象组成的数组                                                               |
| selectOwnerComponent       |                                                  | 选取当前组件节点所在的组件实例（即组件的引用者），返回它的组件实例对象                                                           |
| getRelationNodes           | String `relationKey`                             | 获取这个关系所对应的所有关联节点，参见[组件间关系](#relations)                                                                   |

## options

可声明自定义组件的渲染行为及数据交互等。

| 属性            | 类型    | 必填 | 描述                                                                                |
| --------------- | ------- | ---- | ----------------------------------------------------------------------------------- |
| pureDataPattern | regexp  | 否   | 纯数据字段是一些不用于界面渲染的`data` 字段，可以用于提升页面更新性能。             |
| styleIsolation  | string  | 否   | 组件样式隔离配置，可声明当前组件样式的渲染方式。                                    |
| multipleSlots   | boolean | 否   | 启动组件定义多 slot 特性。                                                          |
| addGlobalClass  | boolean | 否   | 添加全局样式，等同于 `styleIsolation=apply-shared` 优先级低于 `styleIsolation` 配置 |

### styleIsolation 组件样式隔离

> 从基础库版本 2.0.0 开始支持。它支持以下取值：

- `isolated` 表示启用样式隔离，在自定义组件内外，使用 `class` 指定的样式将不会相互影响（一般情况下的默认值）；
- `apply-shared` 表示页面 `css` 样式将影响到自定义组件，但自定义组件 `css` 中指定的样式不会影响页面；
- `shared` 表示页面 `css` 样式将影响到自定义组件，自定义组件 `css` 中指定的样式也会影响页面和其他设置了 `apply-shared` 或 `shared` 的自定义组件。（这个选项在插件中不可用。）

## properties

声明自定义组件的属性配置及数据处理，每一个键值代表一个属性名，使用驼峰写法，通过 `type` 定义属性值的类型：`String` `Number` `Boolean` `Object` `Array` 其一，也可以为 `null` 表示不限制类型。`value` 可声明默认值，不设置则值为 `null`，并可通过 `observer()` 监听属性值的变化。

```js
Component({
  properties: {
    myName: {
      type: String,
      value: 'smart',
      observer(newValue, oldValue) {
        // do something
      },
    },
  },
});
```

注意：在 `properties` 定义段中，属性名采用驼峰写法（`myName`）；在 `tyml` 中，指定属性值时则对应使用连字符写法（`<tag-name my-name="smart" />`）。

**tips**

多数情况下，属性最好指定一个确切的类型。这样，在 `tyml` 中以字面量指定属性值时，值可以获得一个确切的类型，如：

```xml
<custom-comp min="1" max="5" />
```

此时，由于自定义组件的对应属性被规定为 `Number` 类型， `min` 和 `max` 会被赋值为 `1` 和 `5` ，而非 `"1"` 和 `"5"` ，即：

```js
this.data.min === 1; // true
this.data.max === 5; // true
```

## observers

数据监听器可以用于监听和响应任何属性（properties）和数据 （data）字段的变化。通过定义以属性名、数据名、通配符 `*` 的函数处理响应。

```js
Component({
  observers: {
    'value1, value2': function (value1, value2) {
      // this.setData 对应数据时触发
    },
    '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];
    },
    'some.field.**': function (field) {
      // 使用 setData 设置 this.data.some.field 本身或其下任何子数据字段时触发
      // （除此以外，使用 setData 设置 this.data.some 也会触发）
      field === this.data.some.field;
    },
    '**': function () {
      // 每次 setData 都触发
    },
  },
});
```

**注意事项**

- 数据监听器监听的是 `setData` 涉及到的数据字段，即使这些数据字段的值没有发生变化，数据监听器依然会被触发。
- 如果在数据监听器函数中使用 `setData` 设置本身监听的数据字段，可能会导致死循环，需要特别留意。
- 数据监听器和属性的 `properties.field.observer` 相比，数据监听器更强大且通常具有更好的性能。

## data

自定义组件的数据对象和 `properties` 一同用于组件模板的渲染。

```js
Component({
  properties: {
    name: {
      type: String,
      value: 'smart',
    },
  },
  data: { age: 18 },
});
```

```html
<view>{{name}}: {{age}}</view>
```

## methods

自定义组件的逻辑交互行为，结合组件实例方法实现响应用户操作、数据变更、事件通信等，在函数内通过 `this` 可访问组件实例。

```js
Component({
  methods: {
    say() {
      this.setData({ name: 'hello world' });
    },
  },
});
```

## lifetimes

自定义组件的生命周期，可用于响应事件处理。

| 生命周期 | 参数         | 描述                                                   |
| -------- | ------------ | ------------------------------------------------------ |
| created  | 无           | 在组件实例刚刚被创建时执行                             |
| attached | 无           | 在组件实例进入页面节点树时执行                         |
| ready    | 无           | 在组件在视图层布局完成后执行, 节点的查找应在此阶段执行 |
| moved    | 无           | 在组件实例被移动到节点树另一个位置时执行               |
| detached | 无           | 在组件实例被从页面节点树移除时执行                     |
| error    | Object Error | 每当组件方法抛出错误时执行                             |

```js
Component({
  lifetimes: {
    attached() {
      // Do something when attached
    },
    ready() {
      // Do something when ready
    },
  },
});
```

## pageLifetimes

自定义组件所在页面的生命周期声明对象，可用于响应事件处理。

| 生命周期 | 参数 | 描述                         |       |
| -------- | ---- | ---------------------------- | ----- |
| show     | 无   | 组件所在的页面被展示时执行   |       |
| hide     | 无   | 组件所在的页面被隐藏时执行   |       |
| resize   | 无   | 组件所在的页面尺寸变化时执行 | 2.6.2 |

## externalClasses

组件接受的外部样式类，参见 [外部样式类](/cn/miniapp/develop/miniapp/framework/custom-component/tyml-tyss)。

## relations

组件间关系，定义和使用组件间关系。

```js
// path/to/custom-ul.js
Component({
  relations: {
    './custom-li': {
      type: 'child', // 关联的目标节点应为子节点
      linked(target) {
        // 每次有 custom-li 被插入时执行，target 是该节点实例对象，触发在该节点 attached 生命周期之后
      },
      linkChanged(target) {
        // 每次有 custom-li 被移动后执行，target 是该节点实例对象，触发在该节点 moved 生命周期之后
      },
      unlinked(target) {
        // 每次有 custom-li 被移除时执行，target 是该节点实例对象，触发在该节点 detached 生命周期之后
      },
    },
  },
});
```

```js
// path/to/custom-li.js
Component({
  relations: {
    './custom-ul': {
      type: 'parent', // 关联的目标节点应为父节点
      linked(target) {
        // 每次被插入到 custom-ul 时执行，target 是 custom-ul 节点实例对象，触发在attached生命周期之后
      },
      linkChanged(target) {
        // 每次被移动后执行，target 是 custom-ul 节点实例对象，触发在moved生命周期之后
      },
      unlinked(target) {
        // 每次被移除时执行，target 是 custom-ul 节点实例对象，触发在detached生命周期之后
      },
    },
  },
});
// 注意：必须在两个组件定义中都加入relations定义，否则不会生效。
```

### relations 定义段

relations 定义段包含目标组件路径及其对应选项，可包含的选项见下表。

| 选项        | 类型     | 是否必填 | 描述                                                                                                        |
| ----------- | -------- | -------- | ----------------------------------------------------------------------------------------------------------- |
| type        | String   | 是       | 目标组件的相对关系，可选的值为 `parent` 、 `child` 、 `ancestor` 、 `descendant`                            |
| linked      | Function | 否       | 关系生命周期函数，当关系被建立在页面节点树中时触发，触发时机在组件 `attached` 生命周期之后                  |
| linkChanged | Function | 否       | 关系生命周期函数，当关系在页面节点树中发生改变时触发，触发时机在组件 `moved` 生命周期之后                   |
| unlinked    | Function | 否       | 关系生命周期函数，当关系脱离页面节点树时触发，触发时机在组件 `detached` 生命周期之后                        |
| target      | String   | 否       | 如果这一项被设置，则它表示关联的目标节点所应具有的 `behavior`，所有拥有这一 `behavior` 的组件节点都会被关联 |

## behaviors

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

> 详细的 Behavior 介绍请参考 [Behavior](/cn/miniapp/develop/miniapp/framework/api/behavior).

### 在组件中使用

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

```js
// my-behavior.js
export default Behavior({
  behaviors: [
    /* 可引用其他 behavior */
  ],
  properties: { myBehaviorProperty: { type: String } },
  data: { myBehaviorData: {} },
  lifetimes: { attached() {} },
  methods: { myBehaviorMethod() {} },
});
```

```js
import myBehavior  from '/my-behavior';

Component({
  behaviors: [myBehavior],
});
```

### 同名字段的覆盖和组合规则

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

- 如果有同名的属性 (properties) 或方法 (methods)：

1. 若组件本身有这个属性或方法，则组件的属性或方法会覆盖 behavior 中的同名属性或方法；
2. 若组件本身无这个属性或方法，则在组件的 behaviors 字段中定义靠后的 behavior 的属性或方法会覆盖靠前的同名属性或方法；
3. 在 2 的基础上，若存在嵌套引用 behavior 的情况，则规则为：父 behavior 覆盖 子 behavior 中的同名属性或方法。

- 如果有同名的数据字段 (data)：

  - 若同名的数据字段都是对象类型，会进行对象合并；
  - 其余情况会进行数据覆盖，覆盖规则为：组件 > 父 behavior > 子 behavior 、 靠后的 behavior > 靠前的 behavior。（优先级高的覆盖优先级低的，最大的为优先级最高）

- 生命周期函数不会相互覆盖，而是在对应触发时机被逐个调用：
  - 对于不同的生命周期函数之间，遵循组件生命周期函数的执行顺序；
  - 对于同种生命周期函数，遵循如下规则：
    - behavior 优先于组件执行；
    - 子 behavior 优先于 父 behavior 执行；
    - 靠前的 behavior 优先于 靠后的 behavior 执行；
  - 如果同一个 behavior 被一个组件多次引用，它定义的生命周期函数只会被执行一次。

## definitionFilter

定义段过滤器，用于自定义组件扩展。

```js
// behavior.js
export default Behavior({
  definitionFilter(defFields) {
    defFields.data.from = 'behavior';
  },
});

// component.js
import myBehavior from './behavior.js'
Component({
  data: {
    from: 'component',
  },
  behaviors: [myBehavior],
  ready() {
    console.log(this.data.from); // 此处会发现输出 behavior 而不是 component
  },
});
```

通过例子可以发现，自定义组件的扩展其实就是提供了修改自定义组件定义段的能力，上述例子就是修改了自定义组件中的 data 定义段里的内容。

## 高级进阶

### 组件间通信与事件

组件间的基本通信方式有以下几种。

- TYML 数据绑定：用于父组件向子组件的指定属性设置数据，仅能设置 JSON 兼容数据。
- 事件：用于子组件向父组件传递数据，可以传递任意数据。
- 如果以上两种方式不足以满足需要，父组件还可以通过 `this.selectComponent` 方法获取子组件实例对象，这样就可以直接访问组件的任意数据和方法。

#### 监听事件

事件系统是组件间通信的主要方式之一。自定义组件可以触发任意的事件，引用组件的页面可以监听这些事件。关于事件的基本概念和用法，参见 [事件](/cn/miniapp/develop/miniapp/framework/event/interaction)。

监听自定义组件事件的方法与监听基础组件事件的方法完全一致：

**示例代码：**

```xml
<!-- 当自定义组件触发 myevent 事件时，调用“onMyEvent”方法 -->
<component-tag-name bind:myevent="onMyEvent" />
```

```js
Page({
  onMyEvent(event) {
    event.detail; // 自定义组件触发事件时提供的detail对象
  },
});
```

#### 触发事件

自定义组件触发事件时，需要使用 `triggerEvent` 方法，指定事件名、detail 对象和事件选项：

**示例代码：**

```xml
<!-- 在自定义组件中 -->
<button bind:tap="onTap">点击这个按钮将触发“myevent”事件</button>
```

```js
Component({
  properties: {},
  methods: {
    onTap() {
      var myEventDetail = {}; // detail对象，提供给事件监听函数
      this.triggerEvent('myevent', myEventDetail);
    },
  },
});
```

### 组件模板的 slot

在组件的 tyml 中可以包含 slot 节点，用于承载组件使用者提供的 tyml 结构。

一个组件的 tyml 中支持有一个 slot 或者多个 slot（需启用 `multipleSlots: true`）

在组件的 tyml 中使用多个 slot 时，以不同的 name 来区分。

```html
<!-- 组件模板 -->
<view class="wrapper">
  <slot name="before"></slot>
  <view>这里是组件的内部细节</view>
  <slot name="after"></slot>
</view>
```

使用时，用 slot 属性来将节点插入到不同的 slot 上。

```html
<!-- 引用组件的页面模板 -->
<view>
  <component-tag-name>
    <!-- 这部分内容将被放置在组件 <slot name="before"> 的位置上 -->
    <view slot="before">这里是插入到组件slot name="before"中的内容</view>
    <!-- 这部分内容将被放置在组件 <slot name="after"> 的位置上 -->
    <view slot="after">这里是插入到组件slot name="after"中的内容</view>
  </component-tag-name>
</view>
```

### 组件数据中的纯数据字段

有些情况下，某些 `data` 中的字段（包括 `setData` 设置的字段）既不会展示在界面上，也不会传递给其他组件，仅仅在当前组件内部使用。

此时，可以指定这样的数据字段为“纯数据字段”，它们将仅仅被记录在 `this.data`中，而不参与任何界面渲染过程，这样有助于提升页面更新性能。

指定“纯数据字段”的方法是在 `Component` 构造器的 `options` 定义段中指定 `pureDataPattern` 为一个正则表达式，字段名符合这个正则表达式的字段将成为纯数据字段。

**示例代码:**

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

上述组件中的纯数据字段不会被应用到 TYML 上：

```xml
<view ty:if="{{a}}"> 这行会被展示 </view>
<view ty:if="{{_b}}"> 这行不会被展示 </view>
```

#### 组件属性中的纯数据字段

属性也可以被指定为纯数据字段（遵循 `pureDataPattern` 的正则表达式）。

属性中的纯数据字段可以像普通属性一样接收外部传入的属性值，但不能将它直接用于组件自身的 TYML 中。

**示例代码:**

```js
Component({
  options: {
    pureDataPattern: /^_/,
  },
  properties: {
    a: Boolean,
    _b: {
      type: Boolean,
      observer() {
        // 不要这样做！这个 observer 永远不会被触发
      },
    },
  },
});
```

注意：属性中的纯数据字段的属性 `observer` 永远不会触发！如果想要监听属性值变化，使用 [数据监听器](/cn/miniapp/develop/miniapp/framework/custom-component/observers) 代替。

#### 使用数据监听器监听纯数据字段

[数据监听器](/cn/miniapp/develop/miniapp/framework/custom-component/observers)可以用于监听纯数据字段（与普通数据字段一样）。这样，可以通过监听、响应纯数据字段的变化来改变界面。

下面的示例是一个将 `JavaScript` 时间戳转换为可读时间的自定义组件。

```js
Component({
  options: {
    pureDataPattern: /^timestamp$/, // 将 timestamp 属性指定为纯数据字段
  },
  properties: {
    timestamp: Number,
  },
  observers: {
    timestamp() {
      // timestamp 被设置时，将它展示为可读时间字符串
      var timeString = new Date(this.data.timestamp).toLocaleString();
      this.setData({
        timeString: timeString,
      });
    },
  },
});
```

```xml
<view>{{timeString}}</view>
```
