合作联系微信: w6668263      合作联系电话:177-9238-7426     

使用Vue.js创建一个可重用的SVG组件

使用Vue.js创建一个可重用的SVG组件

 


SVG图像可以在标记中引用,就像任何其他图像格式一样,但内联SVG元素是最健壮的方法,因为它允许动态编辑SVG属性,而且不需要额外的HTTP请求。然而,对于复杂的图像,内联SVG代码可能会很混乱,并且为多个图像重复这段代码不是很DRY。在多个地方使用内联SVG可能需要复制和粘贴冗长的代码块,这很快就会变得难以管理,并可能污染原本整洁的代码库。


解决方案是使用Vue组件包装SVG内联代码。这允许您将内联SVG代码与应用程序模板的其余部分分开,并拥有相同SVG图像的多个实例,每个实例都有自己的动态属性。

 

管理Vue应用程序中的自定义图标集合有时可能是一项挑战。图标字体很容易使用,但对于定制,您必须依赖于第三方字体生成器,并且合并冲突可能很难解决,因为字体是二进制文件。


而使用SVG文件可以消除这些问题,但我们如何确保它们在易于使用的同时也易于添加或删除图标呢?


以下是我理想中的图标系统:


要添加图标,只需将它们放入指定的图标文件夹。如果你不再需要一个图标,你只需要删除它。

要在模板中使用rocket.svg图标,语法简单如。

这些图标可以使用CSS字体和颜色属性(就像图标字体一样)缩放和着色。

如果同一图标的多个实例出现在页面上,则SVG代码不会每次都重复。

不需要webpack配置编辑。

这就是我们将通过编写两个小的单文件组件来构建的内容。这个实现有一些特定的要求,尽管我相信你们中的许多人可以在其他框架和构建工具中重新设计这个系统:

webpack:如果你使用Vue CLI来构建你的应用,那么你已经在使用webpack了。

SVG -inline-loader:这允许我们加载所有的SVG代码,并清理我们不想要的部分。

继续,从终端运行开始。

https://www.npmjs.com/package/svg-inline-loader

npm install svg-inline-loader --save-dev

 

 

SVG精灵组件

为了满足不为页面上的每个图标实例重复SVG代码的要求,我们需要构建一个SVG“精灵”。如果您以前没有听说过SVG精灵,可以将其视为包含其他SVG的隐藏SVG。任何需要显示图标的地方,我们都可以通过引用标签中的图标id将其复制出来,如下所示:

<svg><use xlink:href="#rocket" /></svg>

 

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>

在模板中,我们唯一的元素的内容绑定到$options.svgSprite上。如果您不熟悉$options,它包含直接附加到Vue组件的属性。我们可以将svgSprite附加到组件的数据上,但我们并不需要Vue来设置响应性,因为我们的SVG加载器只会在应用构建时运行。

 


$option 是用来获取data外面的数据和方法

export default {
  name: "Test",
  data() {
    return {
         
    };
  },
  //在data外面定义的属性和方法通过$options可以获取和调用
  age: 12,
  haha() {
    console.log("haha");
  },
  created() {  
    console.log(this.$options.name);  // Test
    console.log(this.$options.age);  // 12
    this.$options.haha();  // haha
  
  }

 



在我们的脚本中,我们使用了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
)

 

我们在此所做的基本上是清理位于特定目录(/assets/icons)中的SVG文件,以便它们处于良好状态,可以在任何需要它们的地方使用。


removeTags参数去掉了图标不需要的标记,比如标题和样式。我们特别想要删除标题标签,因为它们会导致不必要的工具提示。如果您希望在图标中保留任何硬编码的样式,那么添加removingTags=title作为附加参数,以便只删除标题标签。


我们还告诉我们的加载器删除填充属性,以便我们以后可以用CSS设置自己的填充颜色。你可能想要保留你的填充颜色。如果是这种情况,那么只需删除removeSVGTagAttrs和removingTagAttrs参数。


最后一个加载器参数是SVG图标文件夹的路径。然后我们提供需求。context具有另外两个参数,因此它搜索子目录并只加载SVG文件。


为了将所有SVG元素嵌套到SVG精灵中,我们必须将它们从< SVG >元素转换为SVG 元素。这很简单,只需更改标记并给每个标记一个唯一的id,这个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>')
})

我们怎么处理这个组件?我们把它放在页面上任何依赖于它的图标之前。我建议将其添加到App.vue文件的顶部。

<!-- App.vue -->
<template>
  <div id="app">
    <svg-sprite />
<!-- ... -->

The icon component

现在让我们构建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>

 

这个组件要简单得多。如前所述,我们利用标签来引用精灵中的id。那个id来自我们组件的图标道具。


我添加了一个旋转道具在那里切换。icon-spin类作为一个可选的动画位,如果我们需要的话。例如,这可能对加载旋转器图标很有用。

这个例子是 当加载的时候 图标在loading 旋转

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

 

 

根据您的需要,您可能希望添加额外的道具,如旋转或翻转。如果愿意,您可以简单地将类直接添加到组件中,而不需要使用道具。


我们组件的大部分内容都是CSS。除了旋转动画之外,这大部分用于使我们的SVG图标表现得更像图标字体¹。为了让图标与文本基线对齐,我发现在大多数情况下,应用垂直对齐:中间,加上0.125em的底部边缘都是可行的。我们还将填充属性值设置为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)

 

 

 

 

文章用翻译软件翻译成中文转载来自下面:

https://css-tricks.com/a-font-like-svg-icon-system-for-vue/

https://hackwild.com/article/creating-a-reusable-svg-component-with-vue/

posted on 2022-03-20 09:35  龙行龘龘9527  阅读(446)  评论(0编辑  收藏  举报

导航