SVG图标精灵图(雪碧图)可以通过将多个SVG图标合并成一个单独的SVG文件。这种方法可以减少HTTP请求,提高页面加载速度和性能。
一、使用vite-plugin-svg-spritemap生成雪碧图
1、安装依赖
css
npm i vite-plugin-svg-spritemap -D
2、配置
php
import { svgSpritemap } from 'vite-plugin-svg-spritemap'
{
plugins: [
...
svgSpritemap({
pattern: 'src/xxx/*.svg', // 需要处理的svg路径
filename: 'static/spritemap_home.svg', // 生成的精灵图路径
currentColor: false,
svgo: {
plugins: [
{
name: 'preset-default',
params: {
overrides: {
removeViewBox: false,
removeEmptyAttrs: false,
moveGroupAttrsToElems: false,
// collapseGroups: false,
removeDimensions: false,
cleanupIds: {
preservePrefixes: ['sprite-'],
},
},
},
},
],
},
}),
],
}
想要生成多个精灵图,配置多组plugin即可
3、使用
typescript
// name:原svg文件名
export const Icon: React.FC<{ name: string }> = ({ name }) => (
<svg xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
<use xlinkHref={`/static/spritemap_home.svg#${name}`} />
</svg>
);
const App = () => {
return <Icon name="arrow" />;
};
二、使用vite-plugin-svg-icons生成雪碧图
-
首先,安装
vite-plugin-svg-icons
:npm install vite-plugin-svg-icons -D
-
在Vite配置文件中(例如
vite.config.js
或vite.config.ts
),配置插件:import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'; export default {
plugins: [
createSvgIconsPlugin({
// 指定要搜索图标的文件夹
iconDirs: [path.resolve(process.cwd(), 'src/icons')], // 指定要忽略的文件
ignores: [],
// 生成的symbol id的前缀 symbolId: 'icon-[dir]-[name]', /** * 自定义插入位置 * @default: body-last */ inject?: 'body-last' | 'body-first'
css/** * custom dom id * @default: __svg__icons__dom__ */ customDomId: '__svg__icons__dom__', }), ],
};
确保你的项目中有一个包含SVG图标的目录(如src/icons
)。
- 使用图标时,可以像下面这样引入:
1)单独引入一个svg可以像如下方式引入
import IconUser from '~/icons/user.svg?svg'; // 在模板或组件中使用
在上述配置中,插件会扫描src/icons
目录下的所有SVG文件,并生成一个SVG雪碧图文件,在HTML中通过<use>
标签引用时会使用该雪碧图。
请注意,具体的配置可能会根据你的项目结构和需求有所不同,你可能需要根据vite-plugin-svg-icons
的文档调整配置。
2)组件中引入
-
在 src/main.ts 内引入注册脚本
import 'virtual:svg-icons-register'
vue方式
/src/components/SvgIcon.vue
xml
<template>
<svg aria-hidden="true">
<use :xlink:href="symbolId" :fill="color" />
</svg>
</template>
<script>
import { defineComponent, computed } from 'vue'
export default defineComponent({
name: 'SvgIcon',
props: {
prefix: {
type: String,
default: 'icon',
},
name: {
type: String,
required: true,
},
color: {
type: String,
default: '#333',
},
},
setup(props) {
const symbolId = computed(() => `#${props.prefix}-${props.name}`)
return { symbolId }
},
})
</script>
icons 目录结构
markdown
# src/icons
- icon1.svg
- icon2.svg
- icon3.svg
- dir/icon1.svg
/src/App.vue
xml
<template>
<div>
<SvgIcon name="icon1"></SvgIcon>
<SvgIcon name="icon2"></SvgIcon>
<SvgIcon name="icon3"></SvgIcon>
<SvgIcon name="dir-icon1"></SvgIcon>
</div>
</template>
<script>
import { defineComponent, computed } from 'vue'
import SvgIcon from './components/SvgIcon.vue'
export default defineComponent({
name: 'App',
components: { SvgIcon },
})
</script>
React 方式
/src/components/SvgIcon.jsx
javascript
export default function SvgIcon({
name,
prefix = 'icon',
color = '#333',
...props
}) {
const symbolId = `#${prefix}-${name}`
return (
<svg {...props} aria-hidden="true">
<use href={symbolId} fill={color} />
</svg>
)
}
获取所有 SymbolId
python
import ids from 'virtual:svg-icons-names'
// => ['icon-icon1','icon-icon2','icon-icon3']
配置说明
symbolId : icon-[dir]-[name]
[name]: svg 文件名
[dir]: 该插件的 svg 不会生成 hash 来区分,而是通过文件夹来区分. 如果iconDirs对应的文件夹下面包含这其他文件夹
例: 则生成的 SymbolId 为注释所写
bash
# src/icons
- icon1.svg # icon-icon1
- icon2.svg # icon-icon2
- icon3.svg # icon-icon3
- dir/icon1.svg # icon-dir-icon1
- dir/dir2/icon1.svg # icon-dir-dir2-icon1
Typescript 支持
如果使用 Typescript
,你可以在tsconfig.json
内添加
json
// tsconfig.json
{
"compilerOptions": {
"types": ["vite-plugin-svg-icons/client"]
}
}
注意
虽然用文件夹来区分已经可以很大程度避免重名问题了,但是也会出现iconDirs
包含多个文件夹,且文件名一样的 svg.
这个需要开发者自己规避下