在 Vue 中编写 SVG 图标组件的方法


Posted in Javascript onFebruary 24, 2020

在 Vue 中编写 SVG 图标组件的方法

在考虑了将矢量图标从图标字体迁移到内联 SVG 的 原因 之后,我在 Vue.js 中找到了一个用 SVG 替换图标字体的解决方案,同时仍能保持使用图标字体的灵活性和易用性——能够使用 CSS 轻松改变图标的大小、颜色以及其它属性。

一种流行的方法是使用 v-html 指令和 npm 模块 html-loader 来将 SVG 导入到我们的 Vue 模板中,并在 Vue 的生命周期函数 mounted() 中修改渲染的 <svg> 元素。CSS 样式可以直接应用到 <svg> 元素或者是其父元素上,并且这些能够组成一个可复用的组件。

创建 Svg-icon 组件

让我们创建 Svg-icon.vue 组件文件,并在里面接收三个 prop 变量。

  • icon 是一个字符串类型的 prop 变量用来传递 .svg 文件名的导入
  • hasFill 是一个布尔类型的 prop 变量来告诉组件 fill 属性是否用于更改 <svg> 元素的颜色,默认值为 false 即不使用 fill 属性
  • growByHeight 是一个布尔类型的 prop 变量来决定 height 或 width 是否相对于 font-size 进行缩放,默认值为 true 即使用 height
<script>
function recursivelyRemoveFill(el) {
 if (!el) {
  return;
 }
 el.removeAttribute('fill');
 [].forEach.call(el.children, child => {
  recursivelyRemoveFill(child);
 });
}
export default {
 name: 'svg-icon',
 props: {
  icon: {
   type: String,
   default: null
  },
  hasFill: {
   type: Boolean,
   default: false
  },
  growByHeight: {
   type: Boolean,
   default: true
  },
 },
 mounted() {
  if (this.$el.firstElementChild.nodeName === 'svg') {
   const svgElement = this.$el.firstElementChild;
   const widthToHeight = (svgElement.clientWidth / svgElement.clientHeight).toFixed(2);
   if (this.hasFill) {
    // recursively remove all fill attribute of element and its nested children
    recursivelyRemoveFill(svgElement);
   }
   // set width and height relative to font size
   // if growByHeight is true, height set to 1em else width set to 1em and remaining is calculated based on widthToHeight ratio
   if (this.growByHeight) {
    svgElement.setAttribute('height', '1em');
    svgElement.setAttribute('width', `${widthToHeight}em`);
   } else {
    svgElement.setAttribute('width', '1em');
    svgElement.setAttribute('height', `${1 / widthToHeight}em`);
   }
   svgElement.classList.add('svg-class');
  }
 }
}
</script>

<template>
 <div v-html="require(`html-loader!../assets/svg/${icon}.svg`)" class="svg-container"></div>
</template>

<style lang="scss" scoped>
.svg-container {
 display: inline-flex;
}
.svg-class {
 vertical-align: middle;
}
</style>

我们将 .svg 图标文件通过 require() 传递给 html-loader 方法,该方法会将文件字符串化,并且通过 v-html 指令将其渲染为 <svg> 元素。

所有对 <svg> 元素修改的地方都在 mounted() 生命周期方法里面。

  • 将由 growByHeight 定义的 <svg> 元素的 height 或 width 属性设置为 1em ( font-size 的一倍)并对另一个元素使用 widthToHeight 。由于并非所有的 SVG 都是正方形的,因此我们从渲染的元素计算 withToHeight 比率,以便 SVG 在父元素的 font-size 属性大小改变的时候按比例缩放到其原始尺寸。
  • 为了设置 <svg> 元素的 fill 属性,我们需要覆盖掉 SVG 文件内部附带的 fill 属性。当 hasFill 值为 true 的时候,我们从 <svg> 元素及其子元素中递归地删除 fill 属性。然后使用 CSS 选择器将 fill 值添加到其父元素或 <svg> 元素就可以了。
  • 还可以向元素中添加例如 class 等其它 DOM 属性,这些属性可用于设置组件中的范围样式

创建微笑图标

让我们使用 Font Awesome 和我们的 Svg-icon 组件中的图标字体创建一个微笑图标。

在 Vue 中编写 SVG 图标组件的方法

使用图标字体

<template>
 <i class="fas fa-smile smile-icon"></i>
</template>

<style lang="scss" scoped>
.smile-icon {
 font-size: 24px;
 color: #aaa;

 &:hover {
 color: #666;
 }
}
</style>

.smile-icon 类的 CSS 选择器以及伪类选择器 :hover 来设置图标的 font-size 和 color 属性。

使用 Svg-icon 组件

<script>
import SvgIcon from './components/Svg-icon';

export default {
 name: 'my-component',
 components: {
 'svg-icon': SvgIcon,
 },
}
</script>

<template>
 <div class="smile-icon">
 <svg-icon icon="smile-solid" :hasFill="true"></svg-icon>
 </div>
</template>

<style lang="scss" scoped>
.smile-icon {
 font-size: 24px;
 fill: #aaa;

 &:hover {
 fill: #666;
 }
}
</style>

上面的实现和图标字体方法相同,除了 .smile-icon 类在父元素中,在 Svg-icon 组件中, color 属性被替换为 fill 。我们还必须确保 smile-solid.svg 文件位于 Svg-icon 组件的 require() 方法指定的路径( ./assets/svg/ )中。

渲染成 HTML

这是由 v-html 的输出渲染的 HTML。注意:会删除掉所有的 fill 属性,并将 height 和 width 属性添加到 <svg> 中。

<div class="smile-icon">
 <svg height="1em" width="1em" aria-hidden="true" focusable="false" data-prefix="fas" data-icon="smile" class="svg-inline--fa fa-smile fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512">
 <path d="M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm80 168c17.7 0 32 14.3 32 32s-14.3 32-32 32-32-14.3-32-32 14.3-32 32-32zm-160 0c17.7 0 32 14.3 32 32s-14.3 32-32 32-32-14.3-32-32 14.3-32 32-32zm194.8 170.2C334.3 380.4 292.5 400 248 400s-86.3-19.6-114.8-53.8c-13.6-16.3 11-36.7 24.6-20.5 22.4 26.9 55.2 42.2 90.2 42.2s67.8-15.4 90.2-42.2c13.4-16.2 38.1 4.2 24.6 20.5z">
 </path>
 </svg>
</div>

过渡到 SVG

在 Vue 中编写 SVG 图标组件的方法

由于 SVG 被认为是未来的发展方向,因此最好是在保留图标字体的易用性的基础上,逐步放弃使用图标字体。 Svg-icon 组件是一个例子,告诉了我们如何使用可用的库来抽离出 <svg> 元素中的混乱部分,同时模仿使用图标字体的好处!

总结

到此这篇关于在 Vue 中编写 SVG 图标组件的文章就介绍到这了,更多相关vue SVG 图标组件内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
js 跳出页面的frameset框架示例介绍
Dec 23 Javascript
JS cookie中文乱码解决方法
Jan 28 Javascript
angular2使用简单介绍
Mar 01 Javascript
Bootstrap4一次重大更新 几乎涉及每行代码
May 16 Javascript
jquery-mobile表单的创建方法详解
Nov 23 Javascript
vue图片加载与显示默认图片实例代码
Mar 16 Javascript
node.js+jQuery实现用户登录注册AJAX交互
Apr 28 jQuery
在百度搜索结果中去除掉一些网站的资料(通过js控制不让显示)
May 02 Javascript
JS实现指定区域的全屏显示功能示例
Apr 25 Javascript
vue resource发送请求的几种方式
Sep 30 Javascript
vue使用节流函数的踩坑实例指南
May 20 Vue.js
如何vue使用el-table遍历循环表头和表体数据
Apr 26 Vue.js
原生javascript中this几种常见用法总结
Feb 24 #Javascript
js实现坦克大战游戏
Feb 24 #Javascript
Vue中点击active并第一个默认选中功能的实现
Feb 24 #Javascript
如何在JavaScript中创建具有多个空格的字符串?
Feb 23 #Javascript
浅谈TypeScript的类型保护机制
Feb 23 #Javascript
原生javascript制作的拼图游戏实现方法详解
Feb 23 #Javascript
原生javascript运动函数的封装示例【匀速、抛物线、多属性的运动等】
Feb 23 #Javascript
You might like
模仿OSO的论坛(一)
2006/10/09 PHP
PHP数字格式化
2006/12/06 PHP
基于AppServ,XAMPP,WAMP配置php.ini去掉警告信息(NOTICE)的方法详解
2013/05/07 PHP
基于PHP CURL用法的深入分析
2013/06/09 PHP
php使用gzip压缩传输js和css文件的方法
2015/07/29 PHP
PHP+Ajax实现无刷新分页实例详解(附demo源码下载)
2016/04/07 PHP
thinkPHP5框架分页样式类完整示例
2018/09/01 PHP
PHP设计模式之模板方法模式实例浅析
2018/12/20 PHP
关于laravel后台模板laravel-admin select框的使用详解
2019/10/03 PHP
PHP unset函数原理及使用方法解析
2020/08/14 PHP
Jquery写一个鼠标拖动效果实现原理与代码
2012/12/24 Javascript
js/jquery去掉空格,回车,换行示例代码
2013/11/05 Javascript
JS使用replace()方法和正则表达式进行字符串的搜索与替换实例
2014/04/10 Javascript
jQuery 浮动导航菜单适合购物商品类型的网站
2014/09/09 Javascript
jquery让指定的元素闪烁显示的方法
2015/03/17 Javascript
Javascript中的数据类型之旅
2015/10/18 Javascript
Bootstrap table简单使用总结
2017/02/15 Javascript
BootstrapTable加载按钮功能实例代码详解
2017/09/22 Javascript
AngularJS 表单验证手机号的实例(非必填)
2017/11/12 Javascript
JavaScript复制内容到剪贴板的两种常用方法
2018/02/27 Javascript
Vue表单绑定的实例代码(单选按钮,选择框(单选时,多选时,用 v-for 渲染的动态选项)
2019/05/13 Javascript
Vue列表如何实现滚动到指定位置样式改变效果
2020/05/09 Javascript
[04:11]2014DOTA2国际邀请赛 CIS遗憾出局梦想不灭
2014/07/09 DOTA
在Python中操作列表之List.append()方法的使用
2015/05/20 Python
Python实现变量数值交换及判断数组是否含有某个元素的方法
2017/09/18 Python
放弃 Python 转向 Go语言有人给出了 9 大理由
2017/10/20 Python
解决python3 网络请求路径包含中文的问题
2018/05/10 Python
python 监听salt job状态,并任务数据推送到redis中的方法
2019/01/14 Python
详解python中TCP协议中的粘包问题
2019/03/22 Python
Python综合应用名片管理系统案例详解
2020/01/03 Python
python中if及if-else如何使用
2020/06/02 Python
一文详述 Python 中的 property 语法
2020/09/01 Python
材料会计岗位职责
2014/03/06 职场文书
医学生自我鉴定范文
2014/03/26 职场文书
中学生评语大全
2014/04/18 职场文书
2015年度学校卫生工作总结
2015/05/12 职场文书