前言
Hello,大家好!我是Atrox🚀,一个正在努力学习的前端攻城狮🦁。在我的上一篇文章svg基础知识入门中,我向大家介绍了有关svg
的基础知识与语法,并且使用svg
完成了两个简单的案例。
在实际的项目开发中,svg
的使用也非常广泛,比如:项目中图标的展示;使用svg绘制坐标图、关系图等。其中比较经典与常见的使用便是使用svg
来展示各种类型的图标了,因此,如何在vue项目中封装一个svg-icon
组件呢?
下面这篇文章将带领大家从0到1完成一个svg-icon
组件的实现,一起来学习吧!😎😎😎
创建svg-icon组件
如图所示,首先我们需要在src
路径下的commponents
文件夹下新建一个svgIcon
文件夹用来创建svg-icon
组件。
<template>
<svg
class="svg-icon"
:style="{
fontSize: size + 'px',
width: width + 'px',
height: height + 'px',
color: color
}"
>
<use :xlink:href="iconName"></use>
</svg>
</template>
<script>
export default {
name: 'svgIcon',
props: {
icon: {
//svg图标名称
type: String,
required: true
},
color: {
type: String,
default: 'rgba(0,0,0,0.65)'
},
size: {
//svg尺寸
type: [Number, String]
},
width: {
//svg宽度
type: [Number, String]
},
height: {
//svg高度
type: [Number, String]
}
},
data() {
return {}
},
computed: {
iconName() {
return `#icon-${this.icon}`
}
}
}
</script>
<style scoped>
.svg-icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
</style>
在这里我们创建了一个svg
元素,并且允许接收一些参数来修改对应的样式。
存储收集svg
如图所示,首先我们需要在src
路径下新建一个名为的icons
文件夹用来存放项目所需要的svg
文件。然后在index.js
文件中收集获取所有的svg
文件,代码如下。
import Vue from 'vue'
import svgIcon from '@/components/svgIcon/index.vue' //引入项目中的svgIcon组件
Vue.component('svg-icon', svgIcon) // 全局注册svg-icon组件
/**
* @name require.context
* @description 一个 webpack 的 api ,通过该函数可以获取一个上下文,从而实现工程自动化(遍历文件夹的文件,从中获取指定文件,自动导入模块)。
* @description 在前端工程中,如果一个文件夹中的模块需要频繁引用时可以使用该中方式一次性引入
* @param dirname String 需要读取模块的文件的所在目录
* @param useSubdirectories Boolean 是否遍历子目录
* @param RegExp RegExp 匹配的规则(正则表达式)
* @returns resolve Function 接受一个参数request,request为文件夹下面匹配文件的相对路径,返回这个匹配文件相对于整个工程的相对路径
* @returns keys Function 返回一个数组,由匹配成功的文件所组成的数组
* @returns id String 执行环境的 id
*/
const req = require.context('./svg', false, /\.svg$/) // 遍历获取 svg 目录下所有的 svg 文件(不包括子目录)
const requireAll = (requireContext) => {
requireContext.keys().map(requireContext)
}
requireAll(req)//返回svg文件夹下文件相对于整个工程的相对路径
解析svg文件
在创建了基础的svg-icon
组件以及获得了项目中svg
文件的路径之后,我们需要解析svg
文件的内容,完成渲染。
这里我们需要借助第三方插件来完成内容的解析,推荐使用svg-sprite-loader。
执行npm i svg-sprite-loader
之后还需要在vue.config.js
文件中进行相关的webpack
配置来完成解析加载,具体代码如下。
const path = require('path')
function resolve(dir) {
return path.join(__dirname, dir)
}
module.exports = {
chainWebpack(config) {
//设置svg
config.module
.rule('svg')
.exclude.add(resolve('src/icons'))
.end()
config.module
.rule('icons')
.test(/\.svg$/)
.include.add(resolve('src/icons'))
.end()
.use('svg-sprite-loader')
.loader('svg-sprite-loader')
.options({
symbolId: 'icon-[name]'
})
.end()
}
}
至此我们已经完成整个组件的加载与解析,现在就可以去使用啦。
使用svg-icon组件
首先需要在main.js
引入处理好的svg
文件
import './icons/index'
然后就可以在项目的任何地方使用svg-icon
组件完成svg文件的渲染了。😁😁😁
<template>
<div class="project-layout">
<svg-icon icon="vue" width="64" height="64"></svg-icon>
</div>
</template>
如下图所示:
如何获取svg文件
对于项目中的svg
文件一般是ui同事提供,除此之外也可以去别的网站获取(例如iconfont
),这里提供一个可以编辑svg
的网址供大家使用---svg.wxeditor。
如果你有自己的想法也可以自己编写一个svg
文件,这里推荐一下svg基础知识入门这篇文章,可以帮助大家快速学习svg
的相关知识。
精灵图
- 精灵图介绍
在项目开发中,除了使用svg
作为图标外,也可以使用精灵图
来实现完成需求。
精灵图可以叫雪碧图也叫css sprites
,实质其实就是利用背景图和背景图的位置去显示同一张图上,不同位置的图片,进而,在引入一张图的前提下,显示不同的图片的技巧。它适合:一般小图标素材。
使用精灵图
可以加快网页加载速度,但在图片合并的时候,你要把多张图片有序的合理的合并成一张图片,还要留好只够的空间,防止板块内不会出现不必要的背景,如果留空间或拼合位置不合适,在布局时容易出现布局这个盒子对象时,设置背景出现拼合相邻图片,干扰图片的情况,所以使用时需要注意。
- 创建精灵图
下面来介绍一种快速生成精灵图
的方法。
首先需要安装以下插件,用来解析生成对应的文件。
"gulp": "^4.0.2",
"gulp-postcss": "^9.0.1",
"gulp.spritesmith": "^6.11.0",
"vinyl-buffer": "^1.0.1"
这里简单介绍一下gulp
:
gulp
是前端开发过程中一种基于流的代码构建工具,是自动化项目的构建利器;它不仅能对网站资源进行优化,而且在开发过程中很多重复的任务能够使用正确的工具自动完成;使用它,不仅可以很愉快的编写代码,而且大大提高我们的工作效率。
gulp
是基于Nodejs
的自动任务运行器, 它能自动化地完成 前端代码的测试、检查、合并、压缩、格式化、浏览器自动刷新、部署文件生成,并监听文件在改动后重复指定的这些步骤。
在src
文件夹下创建gulpfile.js
,加入以下代码。
const gulp = require('gulp')
const fs = require('fs')
const path = require('path')
const postcss = require('gulp-postcss')
const buffer = require('vinyl-buffer')
const spritemith = require('gulp.spritesmith')
const spritesPath = path.join(__dirname, 'src/assets/img')
let spritesArray = []
;(function(dir) {
let fileList = []
fs.readdirSync(dir).forEach((name) => {
const spritesFile = path.join(spritesPath, name)
const stats = fs.lstatSync(spritesFile)
if (stats.isFile() && /png$/.test(name)) {
fileList.push(spritesFile)
} else if (stats.isDirectory() && fs.readdirSync(spritesArray).length) {
const gulpTask = `sprites:${name}`
spritesArray.push(gulpTask)
gulp.task(gulpTask, (done) => {
let spritesData = gulp.src(path.join(spritesFile, '*.png')).pipe(
spritemith({
imgName: `${name}_icon.png`, //生成雪碧图的路径
imgPath: `/img/${name}_icon.png`, //手动指定路径,会直接出现在background的属性值中
cssName: `${name}_icon.scss`, //less生成scss文件,方便使用
cssTemplate: (data) => {
return cssTemplate2(data)
}
})
)
spritesData.css.pipe(gulp.dest(path.join(__dirname, 'src/assets/css')))
spritesData.img
.pipe(buffer())
.pipe(gulp.dest(path.join(__dirname, 'public/img/')))
done()
})
}
})
if (fileList.length) {
spritesArray.push('sprites: app')
gulp.task('sprites: app', (done) => {
let spritesData = gulp.src(fileList).pipe(
spritemith({
imgName: `app_icon.png`, //生成雪碧图的路径
imgPath: `/img/app_icon.png`, //手动指定路径,会直接出现在background的属性值中
cssName: `app_icon.scss`, //less生成scss文件,方便使用
cssTemplate: (data) => {
return cssTemplate2(data)
}
})
)
spritesData.css.pipe(gulp.dest(path.join(__dirname, 'src/assets/css')))
spritesData.img
.pipe(buffer())
.pipe(gulp.dest(path.join(__dirname, 'public/img/')))
done()
})
}
})(spritesPath)
var cssTemplate2 = function(data) {
let arr = []
let url = data.spritesheet.image
data.sprites.forEach(function(sprite) {
arr.push(
`.sprite-${sprite.name}{
display:inline-block;
vertical-align:middle;
width:${sprite.px.width};
height:${sprite.px.height};
background:url("${url}") no-repeat;
background-position:${sprite.px.offset_x} ${sprite.px.offset_y}
}`
)
})
return arr.join('\n')
}
gulp.task('css', function() {
var processors = []
return gulp
.src('./src/*.css')
.pipe(postcss(processors))
.pipe(gulp.dest('./dest'))
})
gulp.task('default', gulp.series(spritesArray))
- 生成精灵图
之后我们需要在package.js
中的scripts
中新增一条命令"start": "gulp default"
。
此时在终端中输入npm run start
后会自动读取src\assets\img
下的图片文件
然后在src\assets\css\app_icon.scss
目录下生成对应的scss
文件
以及在public\img\app_icon.png
目录下生成精灵图
文件。
- 使用精灵图
精灵图使用起来也非常简单
首先需要在main.js
中引入生成好的app_icon.scss
的文件
import '@/assets/css/index.css'
之后就可以在项目中的任何地方采用class类名
的方式来使用了。
<div class="sprite-logo"></div>
总结
这篇文章介绍了如何在项目中封装一个svg-icon
组件,以及精灵图
的生成使用。总的来说还是推荐使用svg
文件作为项目的图标来使用,因为svg
的本质是代码,加载速度、渲染速度都比图片快,而且体积小
、不失真
都是它的优点,具体使用还是要以项目实际开发情况为准🦁。