一种通过svg-sprite-loader引入svg图标的方法
2021-06-08 前端 webpack svg 386 字 1 分钟
svg-sprite-loader
可以将 svg icon文件整合到一起。利用 svg 的 symbol 元素,将每个 icon 包括在 symbol 中,
通过 use 元素使用该 symbol 。配合 SvgIcon 组件,可以方便的添加和引用 svg 图标文件。
安装并配置svg-sprite-loader
首先安装 svg-sprite-loader 插件,并在 webpack 构建文件中进行配置。
引入 svg-sprite-loader 依赖
npm install svg-sprite-loader -D
yarn add svg-sprite-loader -D
在 webpack 中增加配置
// 普通webpack
[
{
test: /\.svg$/,
include: paths.appIcons,
loader: require.resolve("svg-sprite-loader"),
options: {
symbolId: "icon-[name]",
},
}
]
// vue-cli
{
chainWebpack(config)
{
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文件
为了让 webpack 处理 svg 文件,还需要在 js 中显式引入(import/require)文件。这里使用一种批量导入方式。
- 新建存放 svg 图标的文件夹 ./src/icons
- 在其中创建一个 index.js 文件
const req = require.context('./svg', false, /\.svg$/);
const requireAll = requireContext => requireContext.keys().map(requireContext);
requireAll(req);
- 将准备好的 svg 图标文件放在 ./src/icons/svg 目录下
- 在入口文件处引入 ./src/icons/index.js 文件
编写SvgIcon组件
还需要一个组件可以方便的引入打包好的 svg 图标。
React模式
在 ./src/components/SvgIcon/index.tsx 创建组件。
import React from "react";
import "./svg-icon.css";
const SvgIcon = ({ iconClass, className }) => {
const styleExternalIcon = {
mask: `url(${iconClass}) no-repeat 50% 50%`,
WebkitMask: `url(${iconClass}) no-repeat 50% 50%`,
};
const isExternal = (path) => /^(https?:|mailto:|tel:)/.test(path);
const svgClass = className ? "svg-icon " + className : "svg-icon";
const iconName = `#icon-${iconClass}`;
return (
<span className="anticon">
{isExternal(iconClass) ? (
<div
style={styleExternalIcon}
className={`svg-external-icon ${svgClass}`}
/>
) : (
<svg className={svgClass} aria-hidden="true">
<use xlinkHref={iconName} />
</svg>
)}
</span>
);
};
export default SvgIcon;
PS:为了与 antd 的图标样式保持一致,这里使用了 anticon 类名。
在相同目录下 ./src/components/SvgIcon/svg-icon.css 创建样式文件。
.svg-icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
.svg-external-icon {
background-color: currentColor;
mask-size: cover !important;
display: inline-block;
}
Vue模式
创建 ./src/components/SvgIcon.vue 组件文件。
<template>
<div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-bind="$attrs"/>
<span v-else class="inline-block align-middle"><svg :class="svgClass" aria-hidden="true" v-bind="$attrs">
<use :xlink:href="iconName"/>
</svg></span>
</template>
<script>
import { computed, defineComponent } from 'vue'
function checkExternal (path) {
return /^(https?:|mailto:|tel:)/.test(path)
}
export default defineComponent({
name: 'SvgIcon',
props: {
iconClass: {
type: String,
required: true
},
className: {
type: String,
default: ''
}
},
setup (props) {
const isExternal = computed(() => {
return checkExternal(props.iconClass)
})
const iconName = computed(() => {
return `#icon-${props.iconClass}`
})
const svgClass = computed(() => {
if (props.className) {
return `svg-icon ${props.className}`
} else {
return 'svg-icon'
}
})
const styleExternalIcon = computed(() => {
return {
mask: `url(${props.iconClass}) no-repeat 50% 50%`,
'-webkit-mask': `url(${props.iconClass}) no-repeat 50% 50%`
}
})
return {
isExternal,
iconName,
svgClass,
styleExternalIcon
}
}
})
</script>
<style scoped>
.svg-icon {
width: 1.25em;
height: 1.25em;
vertical-align: -0.225em;
fill: currentColor;
overflow: hidden;
}
.svg-external-icon {
background-color: currentColor;
mask-size: cover !important;
display: inline-block;
}
</style>
使用图标
iconClass 属性是放置在 ./src/icons/svg 目录下文件的名称。
className 属性是补充的样式类名。
在 React 中使用
import React from 'react';
import './App.css';
import SvgIcon from '@/components/SvgIcon'
function App() {
return (
<div>
<SvgIcon iconClass='user' />
<SvgIcon iconClass='https://emoji.lonelyion.com/svg/1f418.svg' className='pink' />
</div>
);
}
export default App;
在 Vue 中使用
<template>
<div>
<div class="icon-custom">
<svg-icon icon-class="user" />
</div>
<div class="icon-custom">
<svg-icon icon-class="https://emoji.lonelyion.com/svg/1f418.svg" />
</div>
</div>
</template>
参考资料