如何在Vue项目中使用SVG Icon
栏目: JavaScript · 发布时间: 5年前
内容简介:Web中对于Icon的使用已经是非常频繁的一件事情了,而且很有图标的使用会让你的Web应用程序或Web网页面变得更具可交互性和可使用性。早前在《Web中的图标》一文中和大家一起探讨了如何在Web中使用图标。其中不同的使用方式都具有各自的优势,但随着技术的革新,其中SVG的图标在Web中的使用也越来越频繁,并且其具备的优势也越来越明显。正因如此,在自己的项目中使用SVG的图标的场景也越来越多,因此,今天想和大家一起聊聊如何在Vue的项目中更好的使用SVG图标。在Vue官方网站专门有一节内容,向大家介绍了如何在
Web中对于Icon的使用已经是非常频繁的一件事情了,而且很有图标的使用会让你的Web应用程序或Web网页面变得更具可交互性和可使用性。早前在《Web中的图标》一文中和大家一起探讨了如何在Web中使用图标。其中不同的使用方式都具有各自的优势,但随着技术的革新,其中SVG的图标在Web中的使用也越来越频繁,并且其具备的优势也越来越明显。正因如此,在自己的项目中使用SVG的图标的场景也越来越多,因此,今天想和大家一起聊聊如何在Vue的项目中更好的使用SVG图标。
单个Icon组件的使用
在Vue官方网站专门有一节内容,向大家介绍了如何在项目中更好的使用SVG图标系统,而且这个系统是可具编辑的。先来看最基础的一个示例,这个示例是基于Vue CLI3的基础上构建的。通过官网提供的命令,使用CLI命令创建一个Vue项目,比如:
vue create svg-icon-app
采用默认的模板来构建了一个 svg-icon-app
项目。我们先跟着官网提供的思路来一步一步往下走,在 components
目录下创建一个新的目录 icons
。并将相应的SVG图标以一种标准化的方式命名,比如:
components/icons/IconBox.vue components/icons/Facebook.vue components/icons/Twitter.vue components/icons/GooglePlus.vue
其中 IconBox.vue
是SVG图标的一个基础图标组件,在这个组件中使用了 slot
,其模板如下:
<!-- IconBox.vue --> <template> <svg xmlns="http://www.w3.org/2000/svg" :width="width" :height="height" viewBox="0 0 18 18" :aria-labelledby="iconName" role="presentation" > <title :id="iconName" lang="en" >{{ iconName }} icon</title> <g :fill="iconColor"> <slot /> </g> </svg> </template>
你可以像上面这样使用这个基础图标,唯一可能要做的就是根据你图标的 viewBox
来更新其 viewBox
。在基础图标组件里会有 width
、 height
、 iconColor
以及 iconName
的 props
,这样我们就可以通过 props
对其动态更新。 iconName
将会同时用在 <title>
的内容及其用于提供可访问性的 id
上。
<!-- IconBox.vue --> <script> export default { name: 'IconBox', props: { iconName: { type: String, default: 'box' }, width: { type: [Number, String], default: 32 }, height: { type: [Number, String], default: 32 }, iconColor: { type: String, default: 'currentColor' } }, data () { return { } } } </script>
currentColor
会成为 fill
的默认值,于是图标就会继承 color
的值( currentColor
是CSS的一个很优秀的属性)。我们也可以根据需求传递一个不一样的颜色值。
特别声明, viewBox
是SVG中的一个重要的概念,如果你从未接触过的话,建议你花点时间对该概念进行了解。你可以点击这里、或这里、还有这里进行了解。
IconBox
组件完成了之后,接下来把对应的图标组件完善。
示例中的几个图标,都来自于 Font Awesome 提供的SVG图标。
除此之外,还可以通过 iconmonstr 、 IcoMoon 平台,甚至还可以使用 NucleoApp 来获取SVG图标。特别是NucleoApp来管理你的SVG图标:
我们通过编辑器打开其中一个 .svg
文件,比如 facebook.svg
,其代码会是这样的:
<svg aria-hidden="true" focusable="false" data-prefix="fab" data-icon="facebook-square" class="svg-inline--fa fa-facebook-square fa-w-14" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"> <path d="M29,0 L3,0 C1.35,0 0,1.35 0,3 L0,29 C0,30.65 1.35,32 3,32 L16,32 L16,18 L12,18 L12,14 L16,14 L16,12 C16,8.69375 18.69375,6 22,6 L26,6 L26,10 L22,10 C20.9,10 20,10.9 20,12 L20,14 L26,14 L25,18 L20,18 L20,32 L29,32 C30.65,32 32,30.65 32,29 L32,3 C32,1.35 30.65,0 29,0 Z" id="Path"></path> </svg>
我们只需要将其中 <path>
部分代码放到图标组件的 <template>
中,比如 facebook.svg
的放到对应的 Fackbook.vue
组件:
<!-- Facebook.vue --> <template> <path d="M29,0 L3,0 C1.35,0 0,1.35 0,3 L0,29 C0,30.65 1.35,32 3,32 L16,32 L16,18 L12,18 L12,14 L16,14 L16,12 C16,8.69375 18.69375,6 22,6 L26,6 L26,10 L22,10 C20.9,10 20,10.9 20,12 L20,14 L26,14 L25,18 L20,18 L20,32 L29,32 C30.65,32 32,30.65 32,29 L32,3 C32,1.35 30.65,0 29,0 Z" id="Path"></path> </template> <script> export default { name:'Facebook' } </script>
对于 GooglePlus.vue
和 Twitter.vue
组件类似。
为了更好的演示官网提供的示例,将在 components
目录中新创建一个 .vue
文件,将引用我们创建的 Facebook
、 Twitter
和 GooglePlus
组件。该文件名暂时取名为 VueOfficialSvgIcons.vue
,接下来我们就可以这样使用这几个SVG图标:
<!-- VueOfficialSvgIcons.vue --> <template> <div class="icons"> <IconBox icon-name="facebook"><Facebook /></IconBox> <IconBox icon-name="twitter"><Twitter /></IconBox> <IconBox icon-name="google plus"><GooglePlus /></IconBox> </div> </template> <script> import IconBox from './icons/IconBox' import Facebook from './icons/Facebook' import Twitter from './icons/Twitter' import GooglePlus from './icons/GooglePlus' export default { name: 'VueOfficialSvgIcons', components: { IconBox, Facebook, Twitter, GooglePlus } } </script>
现在看到的效果,都是默认的尺寸 32px x 32px
。
如果我们需要多种尺寸的图标,可以像下面这样做:
<!-- VueOfficialSvgIcons.vue --> <IconBox width="16" height="16" icon-name="facebook"><Facebook /></IconBox> <IconBox icon-name="twitter"><Twitter /></IconBox> <IconBox width="48" height="48" icon-name="google plus"><GooglePlus /></IconBox>
得到的效果如下:
如果你需要不同的图标颜色,可以通过 iconColor
传一个图标的颜色:
<!-- VueOfficialSvgIcons.vue --> <IconBox icon-color="#f36" icon-name="facebook"><Facebook /></IconBox> <IconBox icon-color="#f0987a" icon-name="twitter"><Twitter /></IconBox> <IconBox icon-name="google plus"><GooglePlus /></IconBox>
效果如果如下:
这是Vue项目中使用SVG图标最基本的方式。通过上面的示例我们可以看出来,如果你还需要更多的控制SVG图标,可以在 IconBox
基本组件中的 props
设置更多的属性。在使用的时候按需传入即可。
SVG Sprite的使用
上面这种方式,每个Icon都需要一个独立的组件。如果你的Web应用有许多图标用在不同的地方时,这种方式较为适合。如果你只在一个页面上重复使用相同图标多次,那么使用SVG Sprite更为理想。
有关于SVG Sprites的使用可以阅读《SVG Sprite》一文。
简单地说,可以通过SVG的 <symbol>
标签把所以SVG图标合并在一起,然后使用 <use>
标签来调用 <symbol>
中指定的图标。即 <use>
中的 xlink:href
属性值与 <symbol>
标签指定的 id
相同。
在这里,我们来看看在Vue中怎么使用SVG Sprites来创建图标。基于上面的示例,我们先创建一个名为 Icon.vue
组件:
<!-- Icon.vue --> <template> <svg :width="width" :height="height" :style="{color: iconColor}"> <use xmlns:xlink="http://www.w3.org/1999/xlink" :xlink:href="iconId"></use> </svg> </template> <script> export default { name: 'Icon', props: { iconName: { type: String, default: 'box' }, width: { type: [Number, String], default: 32 }, height: { type: [Number, String], default: 32 }, iconColor: { type: String, default: 'currentColor' } }, computed: { iconId() { return `#icon-${this.iconName}` } } } </script>
现在 Icon
组件是功能性的了,我们需要在 src/mail.js
中注册到 Vue
实例中:
<!-- src/main.js --> import iconComponent from './components/svgSprites/Icon' Vue.component('icon', iconComponent)
为了区分前面的示例,这里为SVG Sprites单独创建一个独立的组件,比如 SvgSpritesIcon.vue
组件,然后再这个组件中调用:
<icon icon-name="facebook"></icon> <icon icon-name="twitter"></icon> <icon icon-name="google"></icon>
但在页面中并不会看到有任何的Icon。这主要是因为我们还没有创建SVG Sprites。暂时我们人肉创建一个SVG Sprites,比如在 App.vue
文件中创建一个SVG Sprites:
<!-- App.vue --> <svg xmlns="http://www.w3.org/2000/svg" style="display: none;"> <symbol viewBox="0 0 32 32" id="icon-facebook" fill="currentColor"> <path d="M29,0 L3,0 C1.35,0 0,1.35 0,3 L0,29 C0,30.65 1.35,32 3,32 L16,32 L16,18 L12,18 L12,14 L16,14 L16,12 C16,8.69375 18.69375,6 22,6 L26,6 L26,10 L22,10 C20.9,10 20,10.9 20,12 L20,14 L26,14 L25,18 L20,18 L20,32 L29,32 C30.65,32 32,30.65 32,29 L32,3 C32,1.35 30.65,0 29,0 Z"></path> </symbol> <symbol viewBox="0 0 32 32" id="icon-twitter" fill="currentColor"> <path d="M28.5714286,0 L3.42857143,0 C1.53571429,0 0,1.53571429 0,3.42857143 L0,28.5714286 C0,30.4642857 1.53571429,32 3.42857143,32 L28.5714286,32 C30.4642857,32 32,30.4642857 32,28.5714286 L32,3.42857143 C32,1.53571429 30.4642857,0 28.5714286,0 Z M25.0785714,11.3428571 C25.0928571,11.5428571 25.0928571,11.75 25.0928571,11.95 C25.0928571,18.1428571 20.3785714,25.2785714 11.7642857,25.2785714 C9.10714286,25.2785714 6.64285714,24.5071429 4.57142857,23.1785714 C4.95,23.2214286 5.31428571,23.2357143 5.7,23.2357143 C7.89285714,23.2357143 9.90714286,22.4928571 11.5142857,21.2357143 C9.45714286,21.1928571 7.72857143,19.8428571 7.13571429,17.9857143 C7.85714286,18.0928571 8.50714286,18.0928571 9.25,17.9 C7.10714286,17.4642857 5.5,15.5785714 5.5,13.3 L5.5,13.2428571 C6.12142857,13.5928571 6.85,13.8071429 7.61428571,13.8357143 C6.30917726,12.9675977 5.52600528,11.5031734 5.52857143,9.93571429 C5.52857143,9.06428571 5.75714286,8.26428571 6.16428571,7.57142857 C8.47142857,10.4142857 11.9357143,12.2714286 15.8214286,12.4714286 C15.1571429,9.29285714 17.5357143,6.71428571 20.3928571,6.71428571 C21.7428571,6.71428571 22.9571429,7.27857143 23.8142857,8.19285714 C24.8714286,7.99285714 25.8857143,7.6 26.7857143,7.06428571 C26.4357143,8.15 25.7,9.06428571 24.7285714,9.64285714 C25.6714286,9.54285714 26.5857143,9.27857143 27.4285714,8.91428571 C26.7928571,9.85 25.9928571,10.6785714 25.0785714,11.3428571 Z"></path> </symbol> <symbol viewBox="0 0 32 32" id="icon-google" fill="currentColor"> <path d="M28.5714286,0 L3.42857143,0 C1.53571429,0 0,1.53571429 0,3.42857143 L0,28.5714286 C0,30.4642857 1.53571429,32 3.42857143,32 L28.5714286,32 C30.4642857,32 32,30.4642857 32,28.5714286 L32,3.42857143 C32,1.53571429 30.4642857,0 28.5714286,0 Z M11.7142857,23.1428571 C7.76428571,23.1428571 4.57142857,19.95 4.57142857,16 C4.57142857,12.05 7.76428571,8.85714286 11.7142857,8.85714286 C13.6428571,8.85714286 15.25,9.55714286 16.5,10.7285714 L14.5642857,12.5928571 C14.0357143,12.0857143 13.1142857,11.4928571 11.7214286,11.4928571 C9.28571429,11.4928571 7.3,13.5071429 7.3,16.0071429 C7.3,18.5 9.28571429,20.5214286 11.7214286,20.5214286 C14.55,20.5214286 15.6071429,18.4857143 15.7785714,17.4428571 L11.7142857,17.4428571 L11.7142857,14.9857143 L18.4571429,14.9857143 C18.5285714,15.3428571 18.5714286,15.7071429 18.5714286,16.1714286 C18.5714286,20.25 15.8357143,23.1428571 11.7142857,23.1428571 Z M27.4285714,17.3 L25.3571429,17.3 L25.3571429,19.3714286 L23.2714286,19.3714286 L23.2714286,17.3 L21.2,17.3 L21.2,15.2142857 L23.2714286,15.2142857 L23.2714286,13.1428571 L25.3571429,13.1428571 L25.3571429,15.2142857 L27.4285714,15.2142857 L27.4285714,17.3 Z"></path> </symbol> </svg>
此时,你刷新你的页面,可以看到图标,如下图所示:
和前面的示例一样,我们可以通过 props
中的 width
、 height
和 iconColor
来设置图标的大小和颜色,比如:
<icon icon-name="facebook"></icon> <icon icon-name="twitter" width="48" height="48"></icon> <icon icon-name="google" width="64" height="64" icon-color="green"></icon>
此时的效果如下:
上面的示例中,虽然达到我们想要的效果。但SVG Sprite是我们人肉生成的。其实,我们可以借助相关的 工具 链,自动生成SVG Sprite。比如:
这些工具会在编译时打包 SVG,但是在运行时编辑它们会有一些麻烦,因为 <use>
标签在处理一些复杂的事情时存在浏览器兼容问题。同时它们会给你两个嵌套的 viewBox
属性,这是两套坐标系。所以实现上稍微复杂了一些。
接下来我们以 svg-sprite-loader
为例,看看怎么自动生成SVG Sprite。我先从网上下载几个SVG的图标放在项目 src/assets/icons/
下:
注意,我们的环境是Vue Cli3下。
先进行安装:
npm i svg-sprite-loader -D
现在我们需要做一些配置。Vue Cli内部是利用 webpack-chain
插件来修改Webpack配置的。所以我们需要在项目根目录下创建一个 Vue.config.js
文件,在该文件中利用 webpack-chain
来修改相关的Webpack配置。比如:
// Vue.config.js const path = require('path') function resolve(dir) { return path.join(__dirname, '.', dir) } module.exports = { chainWebpack: config => { config.module.rules.delete('svg') config.module .rule('svg-sprite-loader') .test(/\.svg$/) .include .add(resolve('src/assets/icons')) // svg图标的路径 .end() .use('svg-sprite-loader') .loader('svg-sprite-loader') .options({ symbolId: 'icon-[name]' // 设置svg中symbol中id的值 }) } }
前面也提到过了,使用SVG Sprite,需要有一个模板,比如 /src/components/svgSprites/Icon.vue
组件:
<!-- /src/components/svgSprites/Icon.vue --> <template> <svg :width="width" :height="height" :style="{color: iconColor}"> <use xmlns:xlink="http://www.w3.org/1999/xlink" :xlink:href="iconId"></use> </svg> </template> <script> export default { name: 'Icon', props: { iconName: { type: String, default: 'box' }, width: { type: [Number, String], default: 32 }, height: { type: [Number, String], default: 32 }, iconColor: { type: String, default: 'currentColor' } }, computed: { iconId() { return `#icon-${this.iconName}` } } } </script>
虽然配置和模板都有了,但要使用还是需要人肉的引用 .svg
文件。所以我们借助Webpack的一些功能,来自动帮我们引入。接下来在 /src
目录下创建一个 utils/svg-icons
目录,并在该目录下创建一个 index.js
:
// src/utils/svg-icons/index.js import Vue from 'vue' import iconSpriteLoadComponent from '../../components/svgSprites/Icon.vue' Vue.component('icon',iconSpriteLoadComponent) const requireAll = requireContext => requireContext.keys().map(requireContext) const req = require.context('../../assets/icons', false, /\.svg$/) requireAll(req)
上面这段代码主要是用于注册 Icon
组件和批量引入 .svg
文件。有了这些之后,我们就可以像下面这样使用:
<icon icon-name="close"></icon> <icon icon-name="love"></icon> <icon icon-name="star" width="48" height="48"></icon>
将看到的效果如下:
通过 Icon.vue
组件中的 props
定义的属性,将相关的值传入进去。同样可以设置大小,但这里有一个小细节,如果你想像前面的示例通过 iconColor
来给图标传递相应的颜色时会失效,比如:
<icon icon-name="location" width="24" height="24" icon-color="red"></icon> <icon icon-name="collection" width="48" height="48" icon-color="lime"></icon>
颜色并没有重置过来:
那是因为,我们的 .svg
文件中 path
标签中的 fill
有一个默认值:
如果要让 iconColor
值生效,我们需要将 .svg
中的 fill
(和 stroke
)属性的值设置为 currentColor
。修改之后,你就能看到图标有相应的颜色了:
这里是通过人肉去修改每个 .svg
文件中 fill
和 stroke
属性,即 将其值修改为 currentColor
。不知道有没有相应的工具,能在合并成SVG Sprite时,自动将 fill
和 stroke
的值更换为 currentColor
。找了一圈,没找到。如果您在这方面有相应的经验,欢迎分享出您的方案。
上面是在Vue Cli3环境中的使用,如果你是自己的构建系统,那么可以借助Webpack相关配置,达到相应的效果。只需要修改 /build/webpack.base.conf.js
文件:
{ test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, exclude: [resolve('src/assets/icons')], // 新增加 loader: 'url-loader', options: [ limit: 10000, name: utils.assetsPath('img/[name].[hash:7].[ext]') ] } // 另外增加 { test: /\.svg$/, loader: 'svg-sprite-loader', include: [resolve('src/assets/iocns')], options: [ symbolId: 'icon-[name]' ] }
其他地方可以不修改。
注册事项
虽然SVG图标在Web中的运用越来越广泛,但是在使用和设计的时候还是需要注意一些细节,比如 .svg
文件的优化。大家都知道,用文本编辑器打开一个 .svg
文件,将看到一大坨的代码,如果你不知道什么可删除,什么不可删除,那么可以借助SVGOMG来优化:
代码上的变化如下:
另外有一点也需要特别注意,那就是SVG 图示的绘制。虽然在很多平台上能直接下载到自己需要的SVG图标,但有时候为了更适合自己的项目,设计师会为自己提供一些更具个性化的SVG图标,这个时候,需要一套较为标准的绘制规则和流程。有关于这方面可以参考 iconfont上的图标绘制规则和制作流程 。
写在最后
有关于在Vue项目中使用SVG的方案和相关的组件库在Github上非常的多。大家可以选择适合自己的组件,如果你喜欢 Font Awesome 图标的话,那么@E0 大大的 Vue-Awesome 就是一个不错的选择。
最后再说一点,这篇文章主要是亲测了在Vue项目中怎么灵活或者更好的使用SVG图标。文章开头跟着 Vue官网 提供的方式,做了一些尝试,感觉较为简单,特别适合那种,项目中运用图标不多的场景,可以为每个图标创建一个独立的组件,不需要全局注册,也可以在任何需要的地方使用。如果图标较多时,管理起来有点蛋疼而以。文章第二部分,介绍如何自动化生成SVG Sprite,并且在相应的脚手架中运用。
可能文章中有不对或者不好的地方,如果你有这方面的经验,欢迎拍正和分享。 文章中示例代码可以在Github中获取到 。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 使用 MonoRepo 管理前端项目
- 使用 Mkdocs 制作项目文档
- 使用Taro开发项目总结
- 使用 Maven 构建 Java 项目
- 使用gradle构建java项目
- flask使用蓝图规划大型项目
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
计算统计
Geof H.Givens、Jennifer A.Hoeting / 王兆军、刘民千、邹长亮、杨建峰 / 人民邮电出版社 / 2009-09-01 / 59.00元
随着计算机的快速发展, 数理统计中许多涉及大计算量的有效方法也得到了广泛应用与迅猛发展, 可以说, 计算统计已是统计中一个很重要的研究方向. 本书既包含一些经典的统计计算方法, 如求解非线性方程组的牛顿方法、传统的随机模拟方法等, 又全面地介绍了近些年来发展起来的某些新方法, 如模拟退火算法、基因算法、EM算法、MCMC方法、Bootstrap方法等, 并通过某些实例, 对这些方法的应用进行......一起来看看 《计算统计》 这本书的介绍吧!