Class 属性在无渲染 Vue 组件中被覆盖
Class Attribute Overwritten in Renderless Vue Component
我构建了一个无渲染的基本图标 Vue 组件,它只输出其插槽中的任何内容,但向插槽组件添加了一些附加属性。我设置的属性之一是 class="icon"
,它允许我将所有图标的样式集中在一个地方。
Icon.vue
<script>
import Vue from "vue";
export default {
name: "u-icon",
render(createElement) {
const svg = this.$slots.default[0];
const attrs = svg.data.attrs;
attrs.xmlns = "http://www.w3.org/2000/svg";
attrs.class = "icon";
attrs["aria-hidden"] = "true";
attrs.focusable = "false";
attrs.role = "img";
return this.$slots.default;
},
};
</script>
<style>
.icon {
// ...
}
</style>
关闭-Icon.vue
然后我可以更轻松地创建许多不同的图标组件,例如这个关闭图标组件。
<template>
<u-icon>
<svg viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<line x1="4" y1="4" x2="20" y2="20"></line>
<line x1="4" y1="20" x2="20" y2="4"></line>
</svg>
</u-icon>
</template>
<script>
import icon from "~/icon.vue";
export default {
name: "close-icon",
components: {
"u-icon": icon,
},
};
</script>
实际结果
问题是当我使用 close-icon
组件并像这样设置 class
时:
<close-icon class="foo"/>
呈现的输出未合并两个 classes "icon foo"
。
<svg class="foo" ...>
...
</svg>
预期结果
如何确保 class 不被覆盖而是附加到输出,以便输出为:
<svg class="icon foo" ...>
...
</svg>
如果可能,我所做的任何更改都应该对 Icon.vue
进行,并且我想避免对 Close-Icon.vue
进行更改,因为还有大量其他图标。
class
和 style
绑定不是 $attrs - source
的一部分
我不确定为什么你的代码即使没有 close-icon
class
绑定也能工作 但是 如果你想 add/modify classes 现有 VNode(来自默认插槽),您应该使用 svg.data.staticClass
而不是 svg.data.attrs.class
下面的示例甚至处理了静态 class 也直接放置在 close-icon
内的 svg
元素上的情况 - 呈现 <svg class="foo bar icon" ...
Vue.component("u-icon", {
render(createElement) {
const svg = this.$slots.default[0];
const attrs = svg.data.attrs;
attrs.xmlns = "http://www.w3.org/2000/svg";
attrs["aria-hidden"] = "true";
attrs.focusable = "false";
attrs.role = "img";
svg.data.staticClass = (svg.data.staticClass || "") + " icon";
return this.$slots.default;
},
});
Vue.component("close-icon", {
template:`
<u-icon>
<svg viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" class="bar">
<line x1="4" y1="4" x2="20" y2="20"></line>
<line x1="4" y1="20" x2="20" y2="4"></line>
</svg>
</u-icon>
`
})
new Vue({
el: "#app"
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.14/vue.js"></script>
<div id="app">
<close-icon class="foo"></close-icon>
</div>
我构建了一个无渲染的基本图标 Vue 组件,它只输出其插槽中的任何内容,但向插槽组件添加了一些附加属性。我设置的属性之一是 class="icon"
,它允许我将所有图标的样式集中在一个地方。
Icon.vue
<script>
import Vue from "vue";
export default {
name: "u-icon",
render(createElement) {
const svg = this.$slots.default[0];
const attrs = svg.data.attrs;
attrs.xmlns = "http://www.w3.org/2000/svg";
attrs.class = "icon";
attrs["aria-hidden"] = "true";
attrs.focusable = "false";
attrs.role = "img";
return this.$slots.default;
},
};
</script>
<style>
.icon {
// ...
}
</style>
关闭-Icon.vue
然后我可以更轻松地创建许多不同的图标组件,例如这个关闭图标组件。
<template>
<u-icon>
<svg viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<line x1="4" y1="4" x2="20" y2="20"></line>
<line x1="4" y1="20" x2="20" y2="4"></line>
</svg>
</u-icon>
</template>
<script>
import icon from "~/icon.vue";
export default {
name: "close-icon",
components: {
"u-icon": icon,
},
};
</script>
实际结果
问题是当我使用 close-icon
组件并像这样设置 class
时:
<close-icon class="foo"/>
呈现的输出未合并两个 classes "icon foo"
。
<svg class="foo" ...>
...
</svg>
预期结果
如何确保 class 不被覆盖而是附加到输出,以便输出为:
<svg class="icon foo" ...>
...
</svg>
如果可能,我所做的任何更改都应该对 Icon.vue
进行,并且我想避免对 Close-Icon.vue
进行更改,因为还有大量其他图标。
class
和 style
绑定不是 $attrs - source
我不确定为什么你的代码即使没有 close-icon
class
绑定也能工作 但是 如果你想 add/modify classes 现有 VNode(来自默认插槽),您应该使用 svg.data.staticClass
而不是 svg.data.attrs.class
下面的示例甚至处理了静态 class 也直接放置在 close-icon
内的 svg
元素上的情况 - 呈现 <svg class="foo bar icon" ...
Vue.component("u-icon", {
render(createElement) {
const svg = this.$slots.default[0];
const attrs = svg.data.attrs;
attrs.xmlns = "http://www.w3.org/2000/svg";
attrs["aria-hidden"] = "true";
attrs.focusable = "false";
attrs.role = "img";
svg.data.staticClass = (svg.data.staticClass || "") + " icon";
return this.$slots.default;
},
});
Vue.component("close-icon", {
template:`
<u-icon>
<svg viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" class="bar">
<line x1="4" y1="4" x2="20" y2="20"></line>
<line x1="4" y1="20" x2="20" y2="4"></line>
</svg>
</u-icon>
`
})
new Vue({
el: "#app"
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.14/vue.js"></script>
<div id="app">
<close-icon class="foo"></close-icon>
</div>