背景
在项目中我们通常会使用很多icon
图标,一般有使用png
、svg
或者css
来实现图标,他们各自有自己的优缺点
png
:受控于颜色、大小,一个icon
的颜色或者大小改变了,则需要重新制作,在高清屏下,图片放大会失真,且每个图片都是一个文件,占用请求资源(当然这点可以利用雪碧图来解决,但是当合成为一张大图片的时候,可能会出现加载比较慢)css
:主要是书写比较复杂,为实现一个图标有时候可能会书写十几行的css
代码,更甚者几十行都有svg
:它不受控于颜色、大小,可以任意改变颜色、大小,且不失真,但是缺点是使用起来比较麻烦 本文就针对于svg
的使用做优化,本文实现Icon
组件库是基于vue2.x
、webpack4.x
构建的。
准备工作
安装vue
、webpack
或者直接使用vue-cli3.x
来创建一个vue
的项目,为了方便,我就使用vue-cli
来创建一个vue
项目
vue create my-app
cd my-app
npm run dev
这样我们先创建了一个项目,然后需要对项目做以下调整:
- 1、创建存放svg的目录,在src 下面新建一个asstes/icon的目录,西面存放所有需要用到的svg,
- 2、在项目根路径下新建vue的配置文件vue.config.js
- 3、在components目录下新建SvgIcon.vue文件,它是一个SvgIcon组件,存储我们需要用到的svg
- 4、在src目录下新建utils文件夹,在其下面新建index.js,这里是项目中常用的工具函数
// 只列出主要目录结构
my-app
│ .eslintrc
│ .gitignore
│ babel.config.js
│ package-lock.json
│ package.json
│ README.md
│ vue.config.js // 1、新增配置
├─public
│ favicon.ico
│ index.html
└─src
│ App.vue
│ main.js
├─assets
│ └─icon // 2、存放svg-icon
│ add.svg
│ search.svg
│ user.svg
├─components
│ SvgIcon.vue // 3、svg-icon组件
├─utils
│ index.js // 4、工具方法
└─views
About.vue
Home.vue
开始处理
- 1、首先配置webpack的rules,因为vue-cli有默认的webpack配置,我们需要修改默认的配置,vue.config.js是vue-cli提供的一个可选配置文件,同时也会介绍webpack的三种配置方式,如下:
// vue.config.js
const path = require('path')
const resolve = dir => path.join(__dirname, dir)
module.exports = {
lintOnSave: process.env.NODE_ENV !== 'development',
// 第一种:对象模式
// configureWebpack: {
// resolve: {
// alias: {
// comps: resolve('/src/components')
// }
// }
// },
// 第二种:函数模式
// configureWebpack: (config) => {
// config.resolve.alias.comps = resolve('/src/components')
// if (process.env.NODE_ENV === 'development') {
// console.log('dev---')
// config.name = '开发环境'
// } else {
// config.name = '正式环境'
// }
// },
// 第三种:因为vue-cli默认安装了chainwebpack第三方插件,可以使用chainwebpack配置,它可以实现链式调用
chainWebpack(config) {
// 给 components 起一个别名,若需要使用 components 下的组件可以使用 import xxx from '/comps' 就可以引入 components 下面的组件
config.resolve.alias.set('comps', resolve('/src/components'))
// 因为vue-cli默认配置处理了svg,所以此处,需要找到svg对应的规则,让默认的svg规则排除对 src/assets/icon 这个目录下svg的处理
config.module.rule('svg')
.exclude.add(resolve('src/assets/icon'))
// 对 src/assets/icon 这个目录下的svg使用我们自己写iocns规则
config.module.rule('icons')
.test(/\.svg$/)
.include.add(resolve('src/assets/icon')).end()
.use('svg-sprite-loader')
.loader('svg-sprite-loader')
.options({
symbolId: 'icon-[name]' // #icon-user.svg
})
}
}
- 2、SvgIcon.vue 组件放置我们所有svg内容 (通常使用从iconfont复制的svg内容)如下:
// SvgIcon.vue
<template>
<svg :class="svgClass" v-on="$listeners">
<use :xlink:href="fullIconName"></use>
</svg>
</template>
<script>
export default {
name: 'SvgIcon',
props: {
iconName: {
type: String,
require: true
},
className: {
type: String,
require: true
}
},
computed: {
fullIconName () {
return `#icon-${this.iconName}`
},
svgClass () {
return this.className ? `svg-icon ${this.className}` : 'svg-icon'
}
}
}
</script>
<style lang="postcss">
.svg-icon {
width: 1em;
height: 1em;
vertical-align: middle;
fill: currentColor;
overflow: hidden;
}
</style>
- 3、现在有了svg-icon组件,想要使用的话,我们在引入这个组件,但是,如果多个页面要使用的话,每个页面都要引入这个组件,这样的话很麻烦,所以只要把这个组件注册为全局组件就不用每个文件都引入了,于是,在utils/index.js中编写注册全局组件的代码,如下:
// main.js
import Vue from 'vue'
import SvgIcon from '@/components/SvgIcon.vue'
// 1、自动加载icon/*.svg文件
// 获取一个指定上下文的requie函数
const req = require.context('../assets/icon', false, /\.svg$/)
req.keys().map(req)
// 2、祖册全局的Icon组件
Vue.component('svg-icon', SvgIcon)
- 4、在main.js中引入公共方法
import Vue from "vue";
import App from "./App.vue";
import "@/utils" // 引入项目中的公共方法
Vue.config.productionTip = false;
new Vue({
router,
store,
render: h => h(App)
}).$mount("#app");
- 5、使用svg-icon组件,我们就再App.vue中试一下
// App.vue
<template>
<div id="app">
<div id="nav">
<router-link to="/">
<!-- 之前使用svg的方式
<svg>
<use xlink:href="#icon-user"></use>
</svg>
-->
<!-- 现在使用svg的方式 -->
<svg-icon icon-name='user'></svg-icon>
Home
</router-link> |
<router-link to="/about">About</router-link>
</div>
<router-view />
</div>
</template>