Un sistema de iconos SVG similar a una fuente para Vue

Índice
  1. El componente de sprites SVG
  2. El componente del icono
  3. Pensamientos finales

Administrar una colección personalizada de íconos en una aplicación Vue puede ser un desafío a veces. Una fuente de ícono es fácil de usar, pero para personalizarla, debe confiar en generadores de fuentes de terceros, y los conflictos de fusión pueden ser difíciles de resolver ya que las fuentes son archivos binarios.

En su lugar, usar archivos SVG puede eliminar esos puntos débiles, pero ¿cómo podemos asegurarnos de que sean iguales de fáciles de usar y al mismo tiempo facilitar agregar o eliminar íconos?

Así es como se ve mi sistema de iconos ideal:

  • Para agregar íconos, simplemente colóquelos en una iconscarpeta designada. Si ya no necesitas un ícono, simplemente eliminalo.
  • Para utilizar el ícono rocket.svg en una plantilla, la sintaxis es tan simple como svg-icon icon="rocket" /.
  • Los íconos se pueden escalar y colorear usando CSS font-sizey colorpropiedades (como una fuente de ícono).
  • Si aparecen varias instancias del mismo ícono en la página, el código SVG no se duplica cada vez.
  • No se requiere edición de configuración del paquete web.

Esto es lo que construiremos escribiendo dos componentes pequeños de un solo archivo. Hay algunos requisitos específicos para esta implementación, aunque estoy seguro de que muchos de ustedes, magos, podrían reelaborar este sistema para otros marcos y herramientas de compilación:

  • webpack: si usamos Vue CLI para desarrollar su aplicación, entonces ya está usando webpack.
  • svg-inline-loader: esto nos permite cargar todo nuestro código SVG y limpiar las partes que no queremos. Continúe y corra npm install svg-inline-loader --save-devdesde la terminal para comenzar.

El componente de sprites SVG

Para cumplir con nuestro requisito de no repetir el código SVG para cada instancia de un ícono en la página, necesitamos crear un “sprite” SVG. Si no has oído hablar de un objeto SVG antes, considéralo como un SVG oculto que alberga otros SVG. En cualquier lugar donde necesitemos mostrar un ícono, podemos copiarlo fuera del objeto haciendo referencia a la identificación del ícono dentro de una useetiqueta como esta:

svguse xlink_href="#rocket" //svg

Ese pequeño fragmento de código es esencialmente cómo SvgIconfuncionará nuestro componente, pero primero vamos a crear el SvgSpritecomponente. Aquí está el SvgSprite.vuearchivo completo; Algunas cosas pueden parecer desalentadoras al principio, pero las desglosaré todas.

!-- SvgSprite.vue --template  svg v-html="$options.svgSprite" //templatescriptconst svgContext = require.context(  '!svg-inline-loader?' +   'removeTags=true' + // remove title tags, etc.  'removeSVGTagAttrs=true' + // enable removing attributes  'removingTagAttrs=fill' + // remove fill attributes  '!@/assets/icons', // search this directory  true, // search subdirectories  /w+.svg$/i // only include SVG files)const symbols = svgContext.keys().map(path = {  // get SVG file content  const content = svgContext(path)   // extract icon id from filename  const id = path.replace(/^./(.*).w+$/, '$1')  // replace svg tags with symbol tags and id attribute  return content.replace('svg', `symboltoken interpolation"${id}"`).replace('svg', 'symbol')})export default {  name: 'SvgSprite',  svgSprite: symbols.join('n'), // concatenate all symbols into $options.svgSprite}/script

En la plantilla, nuestro único svgelemento tiene su contenido vinculado a $options.svgSprite. En caso de que no esté familiarizado con $optionsél, contiene propiedades que están directamente adjuntas a nuestro componente Vue. Podríamos haberlo adjuntado svgSpritea nuestro componente data, pero realmente no necesitamos que Vue configure la reactividad para esto, ya que nuestro cargador SVG solo se ejecutará cuando se cree nuestra aplicación.

En nuestro script, usamos require.contextpara recuperar todos nuestros archivos SVG y limpiarlos mientras lo hacemos. Invocamos svg-inline-loadery le pasamos varios parámetros usando una sintaxis que es muy similar a los parámetros de cadena de consulta. Los he dividido en varias líneas para que sean más fáciles de entender.

const svgContext = require.context(  '!svg-inline-loader?' +   'removeTags=true' + // remove title tags, etc.  'removeSVGTagAttrs=true' + // enable removing attributes  'removingTagAttrs=fill' + // remove fill attributes  '!@/assets/icons', // search this directory  true, // search subdirectories  /w+.svg$/i // only include SVG files)

Básicamente, lo que estamos haciendo aquí es limpiar los archivos SVG que se encuentran en un directorio específico (/assets/iconspara que estén en buenas condiciones para usarlos en cualquier lugar donde los necesitemos.

El removeTagsparámetro elimina las etiquetas que no necesitamos para nuestros íconos, como titley style. Especialmente queremos eliminar titleetiquetas, ya que pueden generar información sobre herramientas no deseadas. Si desea conservar cualquier estilo codificado en sus íconos, agréguelo removingTags=titlecomo parámetro adicional para que solo titlese eliminen las etiquetas.

También le decimos a nuestro cargador que elimine filllos atributos, para que podamos configurar nuestros propios fillcolores con CSS más adelante. Es posible que quieras conservar tus fillcolores. Si ese es el caso, simplemente elimine los parámetros removeSVGTagAttrsy removingTagAttrs.

El último parámetro del cargador es la ruta a nuestra carpeta de iconos SVG. Luego le proporcionamos require.contextdos parámetros más para que busque subdirectorios y solo cargue archivos SVG.

Para anidar todos nuestros elementos SVG dentro de nuestro objeto SVG, tenemos que convertirlos de svgelementos en elementos SVG symbol. Esto es tan sencillo como cambiar la etiqueta y darle a cada una una única id, que extraemos del nombre del archivo.

const symbols = svgContext.keys().map(path = {  // extract icon id from filename  const id = path.replace(/^./(.*).w+$/, '$1')  // get SVG file content  const content = svgContext(path)  // replace svg tags with symbol tags and id attribute  return content.replace('svg', `symboltoken interpolation"${id}"`).replace('svg', 'symbol')})

¿Qué hacemos con este SvgSpritecomponente? Lo colocamos en nuestra página antes de cualquier ícono que dependa de él. Recomiendo agregarlo al principio del App.vuearchivo.

!-- App.vue --template  div    svg-sprite /!-- ... --

El componente del icono

Ahora construimos el SvgIcon.vuecomponente.

!-- SvgIcon.vue --template  svg :class="{ 'icon-spin': spin }"    use :xlink:href="`#${icon}`" /  /svg/templatescriptexport default {  name: 'SvgIcon',  props: {    icon: {      type: String,      required: true,    },    spin: {      type: Boolean,      default: false,    },  },}/scriptstylesvg.icon {  fill: currentColor;  height: 1em;  margin-bottom: 0.125em;  vertical-align: middle;  width: 1em;}svg.icon-spin {  animation: icon-spin 2s infinite linear;}@keyframes icon-spin {  from {    transform: rotate(0deg);  }  to {    transform: rotate(359deg);  }}/style

Este componente es mucho más simple. Como se mencionó anteriormente, aprovechamos la useetiqueta para hacer referencia a una identificación dentro de nuestro objeto. Eso idproviene del iconapoyo de nuestro componente.

Agregué un spinaccesorio que alterna una .icon-spinclase como una parte opcional de animación, en caso de que alguna vez lo necesitemos. Esto podría resultar útil, por ejemplo, para un icono giratorio de carga.

svg-icon v-if="isLoading" icon="spinner" spin /

Dependiendo de tus necesidades, es posible que desees agregar accesorios adicionales, como rotateo flip. Si lo desea, simplemente puede agregar las clases directamente al componente sin usar accesorios.

La mayor parte del contenido de nuestro componente es CSS. Además de la animación giratoria, la mayor parte de esto se usa para hacer que nuestro ícono SVG actúe más como una fuente de ícono ¹. Para alinear los íconos con la línea base del texto, descubrí que aplicar vertical-align: middle, junto con un margen inferior de 0.125em, funciona en la mayoría de los casos. También configuramos el fillvalor del atributo en currentColor, lo que nos permite colorear el icono como si fuera texto.

p  svg-icon icon="exclamation-circle" /!-- This icon will be 2em and red. --  Error!/p

¡Eso es todo! Si desea utilizar el componente de ícono en cualquier lugar de su aplicación sin tener que importarlo a cada componente que lo necesite, asegúrese de registrar el componente en su main.jsarchivo:

// main.jsimport Vue from 'vue'import SvgIcon from '@/components/SvgIcon.vue'Vue.component('svg-icon', SvgIcon)// ...

Pensamientos finales

Aquí hay algunas ideas de mejoras, que omití intencionalmente para mantener esta solución accesible:

  • Escala los íconos que tienen dimensiones no cuadradas para mantener sus proporciones.
  • Inyecte el objeto SVG en la página sin necesidad de un componente adicional.
  • Haga que funcione con vite, que es una herramienta de compilación nueva, rápida (y sin paquetes web) del creador de Vue, Evan You.
  • Aproveche la API de composición de Vue 3.

Si desea probar rápidamente estos componentes, creó una aplicación de demostración basada en la plantilla vue-cli predeterminada. ¡Espero que esto te ayude a desarrollar una implementación que se ajuste a las necesidades de tu aplicación!


¹ Si se pregunta por qué usamos SVG cuando queremos que se como una fuente de ícono, consulte la publicación clásica que enfrenta a los dos entre sí.

SUSCRÍBETE A NUESTRO BOLETÍN 
No te pierdas de nuestro contenido ni de ninguna de nuestras guías para que puedas avanzar en los juegos que más te gustan.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Subir

Este sitio web utiliza cookies para mejorar tu experiencia mientras navegas por él. Este sitio web utiliza cookies para mejorar tu experiencia de usuario. Al continuar navegando, aceptas su uso. Mas informacion