Creé un componente Vue de ícono base sin procesamiento que solo genera lo que está en su ranura pero con algunos atributos adicionales agregados al componente ranurado. Uno de los atributos que configuro es class="icon" que me permite tener mis estilos para todos los íconos en un solo lugar.
<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>Entonces puedo crear más fácilmente muchos componentes de íconos diferentes, como este componente de ícono cercano.
<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> El problema es cuando uso el componente close-icon y configuro una class así:
<close-icon class="foo"/> La salida renderizada no combina las dos clases "icon foo" .
<svg class="foo" ...> ... </svg>¿Cómo puedo asegurarme de que la clase no se sobrescriba sino que se agregue para que el resultado sea:
<svg class="icon foo" ...> ... </svg> Si es posible, cualquier cambio que realice debe realizarse en Icon.vue y me gustaría evitar realizar cambios en Close-Icon.vue ya que hay una gran cantidad de otros íconos.
los enlaces de class y style no son parte de $attrs - fuente
No estoy seguro de por qué su código funciona incluso sin el enlace de class en close-icon pero si desea agregar/modificar las clases de VNode existente (que proviene de la ranura predeterminada), debe usar svg.data.staticClass en lugar de svg.data.attrs.class
El siguiente ejemplo incluso maneja el caso en el que la clase estática también se coloca directamente en el elemento svg dentro close-icon : representa <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>