原因
1 拿到的 svg 图片如果是自带颜色的,一般父元素的颜色设置就会无效。
2 想让 svg 图片的颜色跟随父元素的 color 值变化,可先用编辑器打开 svg 图片文件,修改fill属性。
注意,因为 path 标签中的 d=”..."很长,而 fill="..." 通常放在标签的末尾,容易看漏。
举个例子:
父元素设置 red 无效,因为<path>
标签的最后默认设置了 blue,此时该 svg 图片是 蓝色的
<div style="color: red">
<svg width="1em" height="1em" viewBox="0 0 1024 1024">
<path d="M863.1 518.5H505.5V160.9c0-4.4-3.6-8-8..." fill="blue" />
</svg>
</div>
解决方案
1 在 svg 标签中加上 fill="currentColor"
2 在 path 标签中去掉 fill="..."
,或者改为 fill="currentColor"
注意fill="white"
不能去掉否则svg显示不出来
改为以下代码即可,svg 图片 红色生效:
<div style="color: red">
<svg width="1em" height="1em" fill="currentColor" viewBox="0 0 1024 1024">
<path d="M863.1 518.5H505.5V160.9c0-4.4-3.6-8-8..." />
</svg>
</div>
脚本批量修改
const fs = require('fs')
const Spinnies = require('spinnies')
const spinnies = new Spinnies()
const inputFileDir = 'src/icons'
// 生成的文件不加入版本管理
const outputFileDir = 'src/assets/icons'
readdir(inputFileDir)
// 读取指定目录下的所有文件
function readdir(path) {
fs.readdir(path, async function (err, files) {
if (err) {
console.log('Error', err)
return
}
deleteFolder(outputFileDir)
fs.mkdirSync(outputFileDir, { recursive: true })
spinnies.add('file', { text: 'svg build...' })
const results = files.map(async (file) => {
const content: any = await readfile(`${path}/${file}`)
const result = await writefile(`${outputFileDir}/${file}`, content.data, file)
return result
})
// 所有都写入完成输出打印信息
Promise.all(results)
.then((res) => {
const str = `export default [${res}]`
fs.writeFile(`${outputFileDir}/index.ts`, str, function (error) {
if (error) {
console.log('Error', error)
}
})
spinnies.succeed('file', { text: `✨ svg create success in ${outputFileDir}` })
})
.catch((errs) => {
spinnies.fail('file', { text: errs })
})
})
}
// 写入文件
function writefile(path, data, file) {
return new Promise((resolve, reject) => {
fs.writeFile(path, data, function (errs) {
if (errs) reject(errs)
resolve(`"${file}"`)
})
})
}
// 读取单个文件
function readfile(path) {
return new Promise((resolve, reject) => {
fs.readFile(path, 'utf8', (err, data) => {
//正则替换全局fill="***" 除了fill="white"
data = data.replace(/fill="(?!white).*"/g, '')
if (err) reject(err)
resolve({ path, data })
})
})
}
// 递归删除文件
function deleteFolder(filePath) {
if (fs.existsSync(filePath)) {
const files = fs.readdirSync(filePath)
files.forEach((file) => {
const nextFilePath = `${filePath}/${file}`
const states = fs.statSync(nextFilePath)
states.isDirectory() ? deleteFolder(nextFilePath) : fs.unlinkSync(nextFilePath)
})
fs.rmdirSync(filePath)
}
}
在vite中使用svg
1 安装
npm i vite-plugin-svg-icons -D
2 配置
// vite.config.ts
import viteSvgIcons from 'vite-plugin-svg-icons';
import path from 'path';
export default () => {
return {
plugins: [
viteSvgIcons({
// 指定需要缓存的图标文件夹
iconDirs: [path.resolve(process.cwd(), 'src/icons')],
// 指定symbolId格式
symbolId: 'icon-[dir]-[name]',
}),
],
};
};
3 在 src/main.ts 内引入注册脚本
import 'virtual:svg-icons-register';
4 封装组件
// SvgIcon.vue
<template>
<svg
aria-hidden="true"
:class="[$attrs.class, 'svg-icon']"
:style="getStyle"
@mouseenter="color = hover"
@mouseleave="color = normal"
>
<use :href="symbolId" :fill="color" />
</svg>
</template>
<script setup lang="ts">
import type { CSSProperties } from 'vue'
const props = defineProps({
prefix: {
type: String,
default: 'icon'
},
name: {
type: String,
required: true
},
size: {
type: [Number, String],
default: 16
},
normal: {
type: String,
default: ''
},
hover: {
type: String,
default: ''
}
})
const { normal, hover } = toRefs(props)
const color = ref('')
onMounted(() => {
color.value = normal.value
})
const symbolId = computed(() => `#${props.prefix}-${props.name}`)
const getStyle = computed((): CSSProperties => {
const { size } = props
let s = `${size}`
s = `${s.replace('px', '')}px`
return {
width: s,
height: s
}
})
</script>
<style scoped>
.svg-icon {
display: inline-block;
overflow: hidden;
vertical-align: -0.15em;
fill: currentColor;
}
</style>
5 使用组件,只需要传入名字即可
// demo.vue
<SvgIcon :name="icon" size="16" normal="#409EFF" hover="#67C23A"></SvgIcon>
其他详细用法看官方文档 vite-plugin-svg-icons
崔学社
最后给大家安利一个神秘学习组织,崔学社,里面有大佬 阿崔 mini-vue 作者,github4k多的赞 ,b站地址,每天都在群里安利一些很硬的干货,真的很硬(手动害羞),希望更多小伙伴加入我们的团伙~