所以,我用一种非常hacky的方式解决了这个问题,但至少我的重新渲染问题不再存在,而jest也不再抱怨。我编写了一个带有渲染函数的组件,将该类附加到所有子元素上。
<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)最佳实践的任何建议,因为这看起来非常业余。
- 对于符号相等性的任何其他测试方法,因为我不知道有哪些。
编辑
这是我的最新尝试,一个名为ClassedSlot.js
的文件中的渲染函数:
import { cloneVNode } from 'vue';
function recursivelyAddClass(element, classToAdd) {
if (Array.isArray(element)) {
return element.map(el => recursivelyAddClass(el, classToAdd));
} else if (element.type.toString() === 'Symbol(Fragment)') {
const clone = cloneVNode(element);
clone.children = recursivelyAddClass(element.children, classToAdd)
return clone;
} else {
return cloneVNode(element, { class: classToAdd });
}
}
export default {
props: {
childrenClass: {
type: String,
required: true
},
},
render() {
const slot = this.$slots.default();
return recursivelyAddClass(slot, this.$props.childrenClass);
},
};
这个组件的使用方法与之前的完全相同。我对这个解决方案感到满意,它似乎更加健壮和符合惯用法。请注意,它是JavaScript编写的,因为我发现正确输入这些函数非常困难。