虚拟组件节点

基础库 2.11.2 开始支持,低版本需做兼容处理。

默认情况下,自定义组件本身的那个节点是一个“普通”的节点,使用时可以在这个节点上设置 class style、动画、flex 布局等(就如同普通的 view 组件节点)。

<!-- 页面的 WXML -->
<view style="display: flex">
  <custom-component style="color: blue; flex: 1">蓝色、满宽的</custom-component>
</view>

启用组件节点虚拟化

有时,自定义组件并不希望这个节点本身响应 flex 布局,而是希望自定义组件内部的第一层节点能够响应 flex 布局。还有些时候,自定义组件不希望这个节点本身是一个“普通”可以设置样式的节点。

这种时候,可以将这个自定义组件设置为“虚拟的”:

export default Component({
  options: { virtualHost: true },
})

这样,可以将 flex item 放入自定义组件内部:

<!-- 页面的 WXML -->
<view style="display: flex">
  <!-- 如果设置了 virtualHost ,节点上的样式将失效 -->
  <custom-component style="color: blue">不是蓝色的</custom-component>
</view>
<!-- custom-component.wxml -->
<view style="flex: 1"> 满宽的 </view>

保留 class 和 style 能力

对于虚拟的组件节点,它的 class style 和动画将不再生效,但仍然可以:

  • style 定义成属性来获取 style 上设置的值;
  • class 定义成 外部样式类 使得自定义组件 WXML 可以使用 class
export default Component()
  .options({ virtualHost: true })
  .property('style', String)
  .externalClasses(['class'])
  .register()

引用外部样式

在组件样式隔离的前提下,有些组件希望接受组件使用者传入的样式类。

外部样式类

自基础库版本 1.9.90 起,可以用 externalClasses 定义若干个外部样式类。

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

/* foo-component.js */
export default Component({
  externalClasses: ['my-class'],
})
<!-- foo-component.wxml -->
<foo-component class="my-class">这段文本的颜色受组件引用者的 class 影响</foo-component>

这样,组件的使用者可以指定这个样式类对应的 class ,就像使用普通属性一样。在基础库版本 2.7.1 之后,可以指定多个对应的 class 。

/* 页面的 WXSS */
.red-text {
  color: red;
}
.large-text {
  font-size: 1.5em;
}
<!-- 页面的 WXML -->
<foo-component my-class="red-text" />
<foo-component my-class="red-text large-text" />

注意:在同一个节点上使用普通样式类和外部样式类时,两个类的优先级是未定义的。可以借助选择器优先级机制来控制两个类的优先级。

多层嵌套传递外部样式类

外部样式类可以多层嵌套传递。例如,定义一个 bar-component 来引用上面的 foo-component

/* bar-component.js */
export default Component()
  .externalClasses(['bar-class'])
  .register()
<!-- bar-component.wxml -->
<foo-component my-class="bar-class" />

页面在引用 bar-component 时:

<!-- 页面的 WXML -->
<bar-component bar-class="red-text" />

此时 .red-text 会从页面经过 bar-component 最终传递到 foo-component 中。

直接引用父组件的样式

即使启用了样式隔离 isolated,组件仍然可以通过一些特殊语法来使用组件所在页面的样式类或父组件的样式类。

需要注意的是,这会增加组件间的不良耦合,优先推荐使用 外部样式类 来代替。

例如,如果在页面 WXSS 中定义了:

.blue-text {
  color: blue;
}

在这个组件中可以使用 ~ 来引用页面中这个类的样式:

<view class="~blue-text"> 这段文本是蓝色的 </view>

其中的 ~ 表示引用页面中对应名称的样式类。

另外,可以使用 ^ 表示引用父组件中对应名称的样式类;也可以连续使用多个 ^ 来引用祖先组件中的。

组件样式

考虑到组件间相互影响的问题,组件的样式表写法受到一定限制。

组件选择器限制

在编写组件样式表时,只推荐使用 class 选择器、伪类和伪元素选择器。这样比较利于代码维护,且它们具有更好的性能。

使用其他选择器需要注意:

  • 属性选择器([foo])不受支持、不会生效;
  • ID 选择器(#foo)不推荐使用,仅在使用 Page 构造器构造的页面根组件中生效;
  • 子元素选择器(.foo > .bar)只能用于 view 组件与其子节点之间,用于其他组件可能导致非预期的情况;
  • 标签名选择器(button)应尽量避免使用,它不受样式隔离限制,对所有组件都会生效;如需使用,应写在 app.wxss 中。
[foo] { } /* 不受支持 */
#foo { } /* 不推荐  */
.foo > .bar { } /* 除非 .foo 是 view 组件节点,否则不一定会生效 */
button { } /* 不推荐 */

组件样式隔离

默认情况下,自定义组件的样式只受到自定义组件 WXSS 样式的影响,即 样式隔离 。这样,可以在自定义组件中使用比较短的 class 名字,无需担心与其他组件的 class 名冲突。

<view class="title">标题</view>
.title {
  font-size: 2em;
}

从基础库版本 2.10.1 开始,可以通过设置 styleIsolation 选项来修改自定义组件样式隔离行为。它支持以下取值:

  • isolated 表示启用样式隔离,在自定义组件内外,使用 class 指定的样式将不会相互影响;
  • apply-shared 表示页面的样式将影响到自定义组件,但自定义组件的样式不会影响页面;
  • shared 表示页面的样式将影响到自定义组件,自定义组件的样式也会影响页面和其他设置了 apply-sharedshared 的自定义组件(这个选项在插件的自定义组件中不可用)。

styleIsolation 选项需要在自定义组件 JSON 中设置:

{
  "usingComponents": {},
  "styleIsolation": "isolated"
}

对于 styleIsolation 的默认值:

  • 如果组件是 Page 构造器构造的页面根组件,styleIsolation 的默认值为 shared
  • 如果组件路径在 app.jsonpages 列表中,styleIsolation 的默认值为 shared
  • 在其他组件中,styleIsolation 的默认值为 isolated

styleIsolation 也可以在 JS 脚本的 options 中配置,但目前已不推荐。

JS 脚本的 options 中也支持 addGlobalClass: true 配置,等价于设置 styleIsolation: apply-shared。目前已不推荐使用这个配置。

host 节点选择器

自基础库 1.7.2 起,通过 :host 选择器,组件可以指定它自身对应节点的默认样式。例如:

/* custom-component.wxss */
:host {
  color: yellow;
}

无论引用者为组件赋予的节点名是什么,:host 选择器都会对这个节点生效。例如:

{
  "usingComponents": {
    "custom": "/path/to/custom-component"
  }
}
<!-- 引用组件的 WXML -->
<custom>这段文本是黄色的</custom>