拨开荷叶行,寻梦已然成。仙女莲花里,翩翩白鹭情。
IMG-LOGO
主页 文章列表 为插槽的每个子级添加一个类

为插槽的每个子级添加一个类

白鹭 - 2022-02-22 2111 0 0

我正在尝试设定一个带有插槽的组件,该组件在呈现时会向该插槽的每个子项添加一个类。以一种非常简化的方式:

<template>
<div>
  <slot name="footerItems"></slot>
</div>
</template>

我该怎么办?我当前的解决方案是将类添加到onBeforeUpdate钩子中的元素

<script setup lang="ts">
import { useSlots, onMounted, onBeforeUpdate } from 'vue';

onBeforeUpdate(() => addClassToFooterItems());
onMounted(() => addClassToFooterItems());

function addClassToFooterItems() {
  const slots = useSlots();

  if (slots && slots.footerItems) {
    for (const item of slots.footerItems()) {
      item.el?.classList.add("card-footer-item");
    }
  }
}
</script>

但是,元素在重新渲染(使用npm run serve时会丢失样式,并且玩笑测验会给我一个警告:

    [Vue warn]: Slot "footerItems" invoked outside of the render function: this will not track dependencies used in the slot. Invoke the slot function inside the render function instead.

我应该将插槽移动到它自己的组件并在那里使用渲染函式吗?但即便如此,我也不确定如何编辑子级以添加类或如何从渲染函式生成多个根级元素。

uj5u.com热心网友回复:

你需要这个类来应用一些风格吗?

您可以使用props传递样式或类

并应用类或风格,:style=""或者:,它的解释这里

但只为申请一门课,就:解决了你的问题

uj5u.com热心网友回复:

所以,我设法以一种令人难以置信的骇人听闻的方式解决了这个问题,但至少我的重新渲染问题不再发生,开玩笑也没有抱怨。我写了一个带有渲染函式的组件,该函式将该类附加到所有子项


<template>
<render>
  <slot></slot>
</render>
</template>

<script setup lang="ts">
import { useSlots } from 'vue';

const props = defineProps<{
  childrenClass: string;
}>();

function recurseIntoFragments(element: any): any {
  if (element.type.toString() === 'Symbol(Fragment)'
    && element.children[0].type.toString() === 'Symbol(Fragment)'
  ) {
    return recurseIntoFragments(element.children[0]);
  } else {
    return element;
  }
}

const render = () => {

  const slot = useSlots().default!();
  recurseIntoFragments(slot[0]).children.forEach((element: any) => {
    if (element.props?.class && !element.props?.class.includes(props.childrenClass)) {
      element.props.class  = ` ${props.childrenClass}`;
    } else {
      element.props.class = props.childrenClass;
    }
  });

  return slot;
}
</script>

然后我只需将插槽包装在此组件中以将类添加到子元素:

<template>
<div>
  <classed-slot childrenClass="card-footer-item">
    <slot name="footerItems"></slot>
  </classed-slot>
</div>
</template>

我很乐意接受改进此解决方案的任何答案,尤其是:

  • 任何键入它的提示。所有这些都any感觉很奇怪,但我发现将 Vue 型别用于插槽是非常不切实际的,因为它们通常是 3 或 4 种型别的联合,唯一的解决方案是将它们包装在型别检查中
  • 任何提高其可靠性的东西,因为它似乎会在与我想要的设定略有不同的设定中崩溃
  • 任何基于 Vue(或 TS)最佳实践的建议,因为这看起来非常业余。
  • 真的有任何其他方法来测验符号相等性,因为我不知道
标签:

0 评论

发表评论

您的电子邮件地址不会被公开。 必填的字段已做标记 *