写代码的时候一定要注意一个
组件化的思想
我们封装一个icon组件 可以使得我们后面的代码变得精简(这样我们就不用单独的给每一个新添加的svg添加样式)
先一个svgsprites(类似于自制的vite插件)
import path from 'path'
import fs from 'fs'
import store from 'svgstore'
import { optimize } from 'svgo'
import type { Plugin, ViteDevServer } from 'vite'
interface Options {
id?: string
inputFolder?: string
inline?: boolean
}
export const svgsprites = (options: Options = {}): Plugin => {
const virtualModuleId = `virtual:svgsprites${options.id ? `-${options.id}` : ''}`
const resolvedVirtualModuleId = `\0${virtualModuleId}`
const { inputFolder = 'src/assets/icons', inline = false } = options
const generateCode = () => {
const sprites = store(options)
const iconsDir = path.resolve(inputFolder)
for (const file of fs.readdirSync(iconsDir)) {
if (!file.endsWith('.svg')) { continue }
const filepath = path.join(iconsDir, file)
const svgId = path.parse(file).name
const code = fs.readFileSync(filepath, { encoding: 'utf-8' })
sprites.add(svgId, code)
}
const { data: code } = optimize(sprites.toString({ inline }), {
plugins: [
'cleanupAttrs', 'removeDoctype', 'removeComments', 'removeTitle', 'removeDesc', 'removeEmptyAttrs',
{ name: 'removeAttrs', params: { attrs: '(data-name|fill)' } },
],
})
return code
}
const handleFileCreationOrUpdate = (file: string, server: ViteDevServer) => {
if (!file.includes(inputFolder)) { return }
const code = generateCode()
server.ws.send('svgsprites:change', { code })
const mod = server.moduleGraph.getModuleById(resolvedVirtualModuleId)
if (!mod) { return }
server.moduleGraph.invalidateModule(mod, undefined, Date.now())
}
return {
name: 'svgsprites',
configureServer(server) {
server.watcher.on('add', (file) => {
handleFileCreationOrUpdate(file, server)
})
server.watcher.on('change', (file) => {
handleFileCreationOrUpdate(file, server)
})
},
resolveId(id: string) {
if (id === virtualModuleId) {
return resolvedVirtualModuleId
}
},
load(id: string) {
if (id === resolvedVirtualModuleId) {
const code = generateCode()
return `!function(){
const div = document.createElement('div')
div.innerHTML = \`${code}\`
const svg = div.getElementsByTagName('svg')[0]
const updateSvg = (svg) => {
if (!svg) { return }
svg.style.position = 'absolute'
svg.style.width = 0
svg.style.height = 0
svg.style.overflow = 'hidden'
svg.setAttribute("aria-hidden", "true")
}
const insert = () => {
if (document.body.firstChild) {
document.body.insertBefore(div, document.body.firstChild)
} else {
document.body.appendChild(div)
}
}
updateSvg(svg)
if (document.body){
insert()
} else {
document.addEventListener('DOMContentLoaded', insert)
}
if (import.meta.hot) {
import.meta.hot.on('svgsprites:change', (data) => {
const code = data.code
div.innerHTML = code
const svg = div.getElementsByTagName('svg')[0]
updateSvg(svg)
})
}
}()`
}
},
}
}
然后我们就可以将组件icon函数用来每次引入svg
import c from 'classnames' //引入classnames库 可以同时引入两个classname
interface Props{
className:string,
name: string
}//说明类型 引入两个参数
export const Icon:React.FC<Props> = ({name,className}) =>{
return <svg className={c(className , 'q-icon')} >
<use xlinkHref={`#${name}`} ></use>
</svg>
};
//q-icon是给的一个默认的icon的样式 由下面用layer层级来调整优先级
//这样方便我们后面覆盖新的样式 xlinkHref是引入svg
当我们创建组建的时候,遇到 ‘新的样式无法替代’ 这个问题的时候 就需要改变CSS的层级
我们可以使用 preflight 和 layer 改变 CSS 顺序
方法就是可以直接在uno.config这个文件使用preflights
preflights: [
{
layer: 'components',
getCSS: ({ theme }) => `
.q-icon{
fill:currentColor;
width: 1.2em;
height: 1.2em;
}
`
}], //引号里面直接要写上原先需要被覆盖的原始样式 其原理就是利用不同的layer的优先层级不同 components: -1,default: 1,utilities: 2, 让我们原始的样式的优先级最低 这样我们就可以很容易的覆盖