VueJS - 将样式应用于包裹元素的插槽

syn*_*t1c 7 javascript vue.js css-modules vuejs2 vuejs-slots

我想使用 vue 创建一个组件,该组件具有使用vuejs slot api 的Card标题和内容部分。

我无法理解如何在 Card 组件中创建结构。该卡应包含所有线框样式(填充和边距),但可以从使用该组件的子模板中进行扩展。

我想知道是否有任何标准方法可以对子组件中带有插槽的包装元素进行样式化。

基本Card元素有 2 个插槽,其中包含结构元素,我希望子模板可以在必要时进行修改。

<div class="Card">
  <header class="CardHeader">
    <slot name="header"></slot>
  </header>
  <div class="CardContent">
    <slot></slot>
  </div>
</div>
Run Code Online (Sandbox Code Playgroud)

理想情况下,我想向元素添加一个:class属性#slot,并在插槽中的元素上使用该属性,但是,似乎旧语法在最新版本的框架中已被弃用,例如。

<Card>
  <template #header class="extendHeader">
    stuff
  </template>
</Card>
Run Code Online (Sandbox Code Playgroud)

我可以想到 3 种行之有效的方法每种方法都有其缺点。

  1. 使用 props 通过根元素添加类
  2. 在根元素上使用类并在组件元素上使用样式挂钩
  3. 将插槽内容包装在另一个元素中

我的项目必须使用 css-modules 来尽可能减少全局 css,因为它在过去给我带来了很多悲伤。

1.使用props通过根元素添加类

此方法允许我使用 css-modules 并使Card元素开放以供扩展

组件模板需要从子模板中组合额外的样式

<header :class="$style.Header, ...headerClasses]">
  <slot name="header"></slot>
</header>
Run Code Online (Sandbox Code Playgroud)

然后,子模板可以用来:header-classes扩展基本 Card 类,或覆盖不需要的样式。

<Card :header-classes="[$style.header]">
  <template #header>
    stuff
  </template>
</Card>
<style module>
  .header {
    background: var(--v-blue);
  }
</style>
Run Code Online (Sandbox Code Playgroud)

2. 在根元素上使用类并在组件元素上使用样式挂钩

模板Card需要分配额外的类,这些类可用于扩展组件的基本结构组件。不应使用 css 模块类,因为名称经过哈希处理以避免冲突。

<div :class="[$style.Card, 'CardStyleHook']">
  <header :class="[$style.Header, 'CardHeaderStyleHook']">
    <slot name="header"></slot>
  </header>
  <div :class="[$style.Content, 'CardContentStyleHook']">
    <slot></slot>
  </div>
</div>
Run Code Online (Sandbox Code Playgroud)

然后可以将单个类添加到组件中,并且可以使用额外类的样式

<Card :class="$style.extendCard">
  <template #header>
    stuff
  </template>
</Card>
<style module>
  .extendCard .CardHeaderStyleHook {
    background: var(--v-blue);
  }
</style>
Run Code Online (Sandbox Code Playgroud)

3. 将槽内容包裹在另一个元素中

我认为这种方式违背了插槽的目的,并且会导致我需要从 中的包装结构元素中删除填充的问题Card,它并不是真正开放用于扩展,并且需要更多的解决方法来允许这种样式工作。

<Card>
  <template #header>
    <div :class="$style.customHeader">
      stuff
    </div>
  </template>
</Card>
<style module>
  .customHeader{
    background: var(--v-blue);
  }
</style>
Run Code Online (Sandbox Code Playgroud)

由于旧插槽已折旧,是否有任何标准方法来处理这些情况?我是否错过了文档中的某些内容,我只玩了几天 vue,所以这绝对是可能的。

如果您需要提供任何示例,下面的代码片段中有完整的示例和工作代码。

谢谢你的帮助!

<div class="Card">
  <header class="CardHeader">
    <slot name="header"></slot>
  </header>
  <div class="CardContent">
    <slot></slot>
  </div>
</div>
Run Code Online (Sandbox Code Playgroud)
<Card>
  <template #header class="extendHeader">
    stuff
  </template>
</Card>
Run Code Online (Sandbox Code Playgroud)
<header :class="$style.Header, ...headerClasses]">
  <slot name="header"></slot>
</header>
Run Code Online (Sandbox Code Playgroud)