今天来点儿6的.本文或许需要花费点时间才能理解.
目前是草稿阶段,比较凌乱,许多部分没有详细说明,日后有空更新补充.
本文主要提供解决思路,请按需调整.
很多时候我们在开发阶段是不能确定使用哪些图标的,它会随着开发不停的新增或调整.
所以我一般会从iconfont直接下载svg图标保存起来.
注意本段为废话可以跳过
一开始我是直接将svg代码直接插入dom中,但总觉得这么干会浪费内存影响效率之类的…后来我就好奇平时常见的图标字库是怎么构建的…查着查着就发现了svgtofont这件神器.
它可以自动寻找某个目录下的svg文件,随后一键生成.less .css .ttf .woff这一堆你要的文件,岂不美哉…
关于它的用法及原理本文不着重介绍,小伙伴可以自行查询,一抓一大把…
本文目的主要解决两大痛点
我写了一个vite.plugin.svgtofont.ts插件,以实现自动重编译.
它目前在我的UI库中工作的很好,很大程度提高了我编写该库的效率.
根目录下创建一个文件 vite.plugin.svgtofont.ts
//vite.plugin.svgtofont.ts
import { PluginOption } from "vite";
import path from 'path'
import chokidar from 'chokidar';
import svgtofont from 'svgtofont';
import fs from 'fs';
/* 注意 svg文件名不能存在空格 */
const plugin: PluginOption = {
name: 'svgtofont',
configureServer(server) {
// 监视 SVG 目录
const fontName = "mpui-icon"
const src = path.resolve(__dirname, 'svg');
const dist = path.resolve(__dirname, 'src/Components/Icon/font');
const watcher = chokidar.watch(src, { ignoreInitial: true });
console.log(`[vite.plugin.svgtofont]开始监视SVG目录文件变化:${src}`);
const rebuild = async () => {
// 当 SVG 文件变化时,使用 svgtofont 重新编译字体
await svgtofont({
fontName, src, dist,
css: {
fontSize: "1em",
},
// 其他 svgtofont 配置项...
});
//生成TS引用文件
console.log(`[vite.plugin.svgtofont]SVG图标重编译->生成TS引用文件...`);
const cssFilePath = path.resolve(dist, `${fontName}.css`);
const cssContent = fs.readFileSync(cssFilePath, 'utf-8');
// console.log("=>cssContent:", cssContent);
// 使用正则表达式匹配所有的图标名称
const iconNames = cssContent.match(/\.mpui-icon-(\w+):before/g) || [];
// 生成 TypeScript 文件的内容
let tsContent = `import "./${fontName}.less"\nexport type IconName =\n`;
iconNames.forEach((iconName, index) => {
iconName = iconName.replace(`.${fontName}-`, '').replace(':before', '');
tsContent += ` | '${iconName}'\n`;
});
//console.log("=>tsContent:", tsContent);
fs.writeFileSync(path.resolve(dist, `${fontName}.ts`), tsContent);
console.log(`[vite.plugin.svgtofont]SVG图标->重编译完成,重加载页面...`);
// 通知 Vite 重新加载页面
server.ws.send({ type: 'full-reload', });
console.log(`[vite.plugin.svgtofont]SVG图标->重载完成!`);
}
watcher.on("ready", async () => {
console.log(`[vite.plugin.svgtofont]SVG图标重编译->初始化...`);
await rebuild();
});
watcher.on('add', async (path) => {
console.log(`[vite.plugin.svgtofont]SVG图标重编译-新增文件:${path}`);
await rebuild();
});
watcher.on('unlink', async (path) => {
console.log(`[vite.plugin.svgtofont]SVG图标重编译-移除文件:${path}`);
await rebuild();
});
}
}
export default plugin
修改vite配置文件,新增我们刚才写的插件.
//vite.config.ts
import svgtofont from "./vite.plugin.svgtofont"
import { defineConfig } from "vite"
export default defineConfig({
...
plugins: [
svgtofont,
],
optimizeDeps: {
/* 设置不被Vite打包的包 */
exclude: ["fs", "path", "chokidar", "svgtofont"],
}
})
然后你需要制作一个Icon类负责实例化元素
这里使用到了CustomElements 没用过的话可以去补课一下
import { IconName } from '你插件上配置的输出路径';
export class Icon extends HTMLElement{
constructor(name: IconName ) {
super()
this.classList.add( `mpui-icon-${nameOrSVG}`)
}
}
export defalut Icon
if(!customElements.get("mpui-icon"))customElements.define("mpui-icon",Icon)
然后用起来就很简单了
import Icon from "./Icon"
document.body.appendChild(new Icon("MiragePulse"))
随后你会在dom中看到一个名为mpui-icon的元素
神奇吧.你可以在上面提到的Icon.ts结尾部分更改它叫啥
这个元素被渲染出来以后是这样的
这是我用Illustrator画的一个小图标,转存为了SVG文件生成的.
(Illustrator生成的SVG大多数情况不能直接使用,还需要进一步压缩处理,下次更新说明)