---
title: 组件模板和样式
summary: "介绍自定义组件的模板与样式，包括 slot 插槽、样式隔离、外部样式类及组件样式作用域规则。"
questions:
  - 涂鸦小程序自定义组件中如何使用 slot 承载外部传入的子节点？
  - 如何在组件模板中使用多个具名 slot？
  - 组件 tyss 样式中有哪些选择器是不能使用的？
  - styleIsolation 选项的 isolated、apply-shared 和 shared 三个取值分别有什么作用？
  - 如何通过 externalClasses 让组件接受外部传入的样式类？
  - 组件模板中的数据绑定只能传递什么类型的数据？
  - :host 选择器在组件样式中的作用是什么？
  - addGlobalClass 选项设置为 true 后会有什么效果？
  - 继承样式（如 font 和 color）在组件内外的表现是怎样的？
---

类似于页面，自定义组件拥有自己的 `tyml` 模板和 `tyss` 样式。

## 组件模板

组件模板的写法与页面模板相同。组件模板与组件数据结合后生成的节点树，将被插入到组件的引用位置上。
在组件模板中可以提供一个 `<slot>` 节点，用于承载组件引用时提供的子节点。

```xml
<!-- 组件模板 -->
<view class="wrapper">
  <view>这里是组件的内部节点</view>
  <slot></slot>
</view>
```

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

注意，在模板中引用到的自定义组件及其对应的节点名需要在 json 文件中显式定义，否则会被当作一个无意义的节点。

## 模板数据绑定

与普通的 `tyml` 模板类似，可以使用数据绑定，这样就可以向子组件的属性传递动态数据。

**示例代码：**

```xml
<!-- 引用组件的页面模板 -->
<view>
  <component-tag-name prop-a="{{dataFieldA}}" prop-b="{{dataFieldB}}">
    <!-- 这部分内容将被放置在组件 <slot> 的位置上 -->
    <view>这里是插入到组件slot中的内容</view>
  </component-tag-name>
</view>
```

在以上例子中，组件的属性 `propA` 和 `propB` 将收到页面传递的数据。页面可以通过 `setData` 来改变绑定的数据字段。

**注意**：这样的数据绑定只能传递 JSON 兼容数据。

## 组件 tyml 的 slot

<DemoBlock 
  githubUrl="https://github.com/Tuya-Community/tuya-miniapp-demo/tree/master/slot" 
  qrCodeUrl="/images/qrCode/slot.png" 
  lang="zh">
</DemoBlock>

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

一个组件的 `tyml` 中支持有一个 slot 或者多个 slot。

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

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

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

```xml
<!-- 引用组件的页面模板 -->
<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>
```

## 组件样式

组件对应 `tyss` 文件的样式，只对组件 `tyml` 内的节点生效。编写组件样式时，需要注意以下几点：

- 组件和引用组件的页面不能使用 `id` 选择器（#a）、属性选择器（[a]）和标签名选择器，请改用 `class` 选择器。
- 组件和引用组件的页面中使用后代选择器（.a .b）在一些极端情况下会有非预期的表现，如遇，请避免使用。
- 子元素选择器（.a>.b）只能用于 `view` 组件与其子节点之间，用于其他组件可能导致非预期的情况。
- 继承样式，如 `font` 和 `color`，会从组件外继承到组件内。
- 除继承样式外，`app.tyss` 中的样式、组件所在页面的样式对自定义组件无效（除非更改组件样式隔离选项）。

```css
#a {
} /* 在组件中不能使用 */
[a] {
} /* 在组件中不能使用 */
button {
} /* 在组件中不能使用 */
.a > .b {
} /* 除非 .a 是 view 组件节点，否则不一定会生效 */
```

除此以外，组件可以指定它所在节点的默认样式，使用 `:host` 选择器。

**代码实例：**

```css
/* 组件 custom-component.tyss */
:host {
  color: yellow;
}
```

```xml
<!-- 页面的 tyml -->
<custom-component>这段文本是黄色的</custom-component>
```

## 组件样式隔离

默认情况下，自定义组件的样式只受到自定义组件 `tyss` 的影响。除非以下两种情况：

`app.tyss` 或页面的 `tyss` 中使用了标签名选择器（或一些其他特殊选择器）来直接指定样式，这些选择器会影响到页面和全部组件。通常情况下这是不推荐的做法。
指定特殊的样式隔离选项 `styleIsolation`。

```js
Component({
  options: {
    styleIsolation: 'isolated',
  },
});
```

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

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

**使用后两者时，请务必注意组件间样式的相互影响。**

**代码实例：**

```js
/* 组件 custom-component.js */
Component({
  options: {
    addGlobalClass: true,
  },
});
```

```xml
<!-- 组件 custom-component.tyml -->
<text class="red-text">这段文本的颜色由 app.tyss 和页面 tyss 中的样式定义来决定</text>
```

```css
/* app.tyss */
.red-text {
  color: red;
}
```

## 外部样式类

有时，组件希望接受外部传入的样式类。此时可以在 `Component` 中用 `externalClasses` 定义段定义若干个外部样式类。

这个特性可以用于实现类似于 `view` 组件的 `hover-class` 属性：页面可以提供一个样式类，赋予 `view` 的 `hover-class` ，这个样式类本身写在页面中而非 `view` 组件的实现中。

注意：在同一个节点上使用普通样式类和外部样式类时，两个类的优先级是未定义的，因此最好避免这种情况。

代码示例：

```js
/* 组件 custom-component.js */;
Component({
  externalClasses: ['my-class'],
});
```

```html
<!-- 组件 custom-component.wxml -->
<custom-component class="my-class">这段文本的颜色由组件外的 class 决定</custom-component>
```

这样，组件的使用者可以指定这个样式类对应的 class ，就像使用普通属性一样。在 2.12.0 之后，可以指定多个对应的 class 。
