如何在Vue中使用类似Font的SVG图标系统?让我们今天了解一下!!!
做过VUE项目的童鞋可能已经经历过了,有时在VUE应用程序中很难管理图标的自定义集合。图标字体很容易使用,但你必须依靠第三方字体生成器进行自定义,并且可能很难解决合并冲突,因为字体是一个二进制文件。
相反,使用SVG文件可以消除这些痛点,但我们如何确保它们同样容易使用,并且可以轻松地添加或删除图标呢?
这是我理想图标系统的外观:
-
添加图标,只需将其放入指定的图标中
icons
文件夹中。如果不再需要图标,只需删除即可。 -
在模板中使用robott.SVG图标,语法很简单
<svg-icon icon="rocket" />
。 -
可使用CSS
font-size
和color
属性(像图标字体一样)缩放和着色图标。 -
如果同一图标的多个例子出现在页面上,SVG代码不会每次都重复。
-
无需编辑Webpack配置。
这是我们通过编写两个小的单文件组件来构建的。虽然我相信您的许多导游可以重新设计其他框架和构建工具:
-
webpack:假如你使用Vue CLI构建应用程序意味着您已经在使用webpack。
-
svg-inline-loader:这样我们就可以加载所有的SVG代码,清理不必要的部分。继续并继续
npm install svg-inline-loader --save-dev
从终端运行开始。
SVG Sprite组件
为了满足我们对页面上每个图标实例不重复SVG代码的要求,我们需要建立一个SVG“精灵”。如果您以前从未听说过SVG子图片,请将其视为包含其他SVG的隐藏SVG。我们可以引用任何需要显示图标的地方<use>
将标签中的图标ID复制到sprite以外,如下所示:
<svg><use xlink:href="#rocket" /></svg>
这个代码本质上是我们的<SvgIcon>
组件的工作模式,但让我们继续先创建它<SvgSprite>
组件。这是整个SvgSprite.vue
文件;起初,它似乎有点令人生畏,但我把它分解了。
<!-- SvgSprite.vue --> <template> <svg width="0" height="0" style="display: none;" v-html="$options.svgSprite" /> </template> <script> 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 ) 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', `<symbol id="${id}"`).replace('svg>', 'symbol>') }) export default { name: 'SvgSprite', svgSprite: symbols.join('\n'), // concatenate all symbols into $options.svgSprite } </script>
在模板中,我们的lone <svg>
元素的内容绑定到$options.svgSprite
。假如你不熟悉$options
它包含直接附加到我们的Vue组件中的属性。我们可以添加它svgSprite
到组件的data
,但我们真的不需要Vue来设置响应性,因为我们的SVG加载器只在构建应用程序时运行。
我们在脚本中使用它require.context
在使用时检索所有SVG文件并清理它们。svg-inline-loader
使用与查询字符串参数非常相似的语法来调用和传递几个参数。我把它们分成多行,让它们更容易理解。
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 )
我们在这里基本上要做的就是清理位于特定目录中的SVG文件(/assets/icons
在任何需要的地方使用它们都处于良好的状态。
该removeTags
我们不需要为我们的图标删除参数标签,如果没有title
和style
。我们特别想删除它title
因为这些标签可能会导致不必要的工具提示。如果您想在图标中保留任何硬编码样式,请添加removingTags=title
作为附加参数,只能使用title
删除标记。
我们还告诉加载程序删除fill
属性,以便fill
以后可以使用CSS 设置自己的颜色。你可能想保留自己fill
颜色。在这种情况下,只需删除即可removeSVGTagAttrs
和removingTagAttrs
参数。
SVG图标文件夹的路径是最后一个加载程序参数。然后require.context
,为了搜索子目录,只加载SVG文件,我们提供了另外两个参数。
为了在SVG精灵中嵌入所有的SVG元素,我们必须将它们从<svg>
将元素转换为SVG <symbol>
元素。这就像改变标签并赋予每个标签独特性一样简单id
,然后从文件名中提取唯一性。
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', `<symbol id="${id}"`).replace('svg>', 'symbol>') })
如何处理这个问题?<SvgSprite>
组件?我们把它放在我们页面上所有依赖它的图标之前。我建议将其添加到App.vue
文件的顶部。
<!-- App.vue --> <template> <div id="app"> <svg-sprite /> <!-- ... -->
图标组件
现在,让我们建造它SvgIcon.vue
组件。
<!-- SvgIcon.vue --> <template> <svg class="icon" :class="{ 'icon-spin': spin }"> <use :xlink:href="`#${icon}`" /> </svg> </template> <script> export default { name: 'SvgIcon', props: { icon: { type: String, required: true, }, spin: { type: Boolean, default: false, }, }, } </script> <style> svg.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>
这个组件要简单得多。如前所述,我们使用它<use>
引用精灵中的ID进行标记。然后id
来自我们的组件icon
道具。
我spin
在那里加一个道具,可以根据需要切换.icon-spin
类作为动画的可选位置。例如,这可能对加载微调图标非常有用。
<svg-icon v-if="isLoading" icon="spinner" spin />
根据您的需要,您可能需要添加其他道具,例如rotate
或flip
。在不使用道具的情况下,可以根据需要直接将类添加到组件中。
我们组件的大部分内容是CSS。除了旋转动画,大多数动画都被用来使我们的SVG图标更像图标字体。为了使图标与文本基线对齐,我发现它可以在大多数情况下应用vertical-align: middle
,底边0.125em
为了。我们还会fill
属性值设置为currentColor
,这使我们能够像文本一样为图标着色。
<p style="font-size: 2em; color: red;"> <svg-icon icon="exclamation-circle" /><!-- This icon will be 2em and red. --> Error! </p>
只是!如果您想在应用程序中的任何位置使用图标组件,并且不需要将其导入需要它的每个组件,请确保在main.js
该组件在文件中注册:
// main.js import Vue from 'vue' import SvgIcon from '@/components/SvgIcon.vue' Vue.component('svg-icon', SvgIcon) // ...
总结
这里有一些改进的想法,我故意遗漏了一些,使解决方案易于处理:
-
具有非正方形尺寸的缩放图标以保持其比例
-
SVG无需其他组件即可使用 将Sprite注入页面。
-
与vite一起使用vite,vite是vue创作者Evann You是一种新的、快速的(而且没有webpack)建筑工具。
-
利用Vue 3 Composition API。
如果你想快速使用这些组件,我已经基于默认的vue-cli模板创建了一个演示应用程序。如果你对DEMO感兴趣,你可以添加一个小组来讨论源代码,我希望这能帮助你开发适合你的应用程序需求的实现!