将svg对象化,并动态修改svg图标的颜色、尺寸等

批量处理 SVG 图标文件,最终自动生成可直接在前端项目中使用的 TypeScript 图标库,仅仅只是个思路。

入口代码

TypeScript 复制代码
import fs from 'fs-extra'
import path from 'path'
improt { optimize } from 'svgo'
import xml from 'xml-js'
import prettier from 'prettier'

 const iconsPath = path.resolve(basePath, type);
 let funcResult = `...`; // 初始导入语句
 fs.readdirSync(iconsPath).forEach((item) => {
   // 读取SVG
   const str = fs.readFileSync(...);
   // 压缩svg
   const temp = optimize(str, { plugins: ['preset-default', 'convertStyleToAttrs'] });
   // SVG 转 JSON 对象
   const ele = xml.xml2js(temp.data) as Element;
   // 自动生成可配置函数
   const { colors, funcStr, primaryColor, backgroundColor } = generateSvg(ele, type);
 });
 // 写入最终的 TS 文件
 fs.writeFileSync(path.resolve(basePath, `${type}-icons.ts`), prettier.format(funcResult,
{ parser: 'typescript' }));
  • readdirSync:同步读取目录内容,一次性读取指定目录下的所有文件 / 子目录名称,并以数组形式返回,执行时会阻塞后续代码,直到目录读取完成
  • readFileSync:同步读取文件内容,一次性读取指定文件的全部内容到内存中,并返回文件内容(字符串 / Buffer),执行时会阻塞后续代码,直到文件读取完成
  • optimizeoptimizesvgo 库的核心压缩方法,对 SVG 做针对性优化,核心目的是:去除冗余内容,精简 SVG 体积、统一格式、降低后续处理复杂度。preset-default是默认优化插件,convertStyleToAttrs是样式转属性插件
  • xml.xml2jsxml.xml2jsxml-js 库(你代码里简写为 xml)提供的核心方法,作用是:把 XML 格式的字符串(比如 SVG 文本)转换成 JavaScript 对象。

自动生成可配置函数(generateSvg)

接收一个 SVG 元素和类型标识,分析 SVG 内部的颜色、尺寸信息,然后生成一个可复用的 JavaScript 函数。这个生成的函数能根据传入的配置(如尺寸、主色、背景色)动态生成带 base64 编码的 SVG 数据 URL,让 SVG 图标可以灵活调整样式。

TypeScript 复制代码
// 遍历svg对象节点
interface Visitor {
  (temp: Element): void;
}

const svgVisitor = (svg: Element, visitor: Visitor): Element => {
  const clone = lodash.cloneDeep(svg);

  const visit = (temp: Element) => {
    visitor(temp);

    if (temp.elements) {
      temp.elements.forEach((item) => {
        visit(item);
      });
    }
  };

  visit(clone);
  return clone;
};
// 生成获取svg的base64函数
const generateSvg = (ele: Element, type: string) => {
  // 获取svg里所有的颜色
  const colors = getSvgAllColors(ele);
  let primaryColor;
  let backgroundColor;
  const result = svgVisitor(ele, (visitorEle) => {
    if (visitorEle.attributes?.fill) {
      const hex = color(visitorEle.attributes?.fill).hex();
      const index = colors.findIndex((item) => {
        return item.hex === hex;
      });
      // 设置主色
      if (index === 0) {
        primaryColor = hex;
        visitorEle.attributes.fill = '${ primaryColor }';
      }
      // 设置背景色
      if (index === 1 && colors.length === 2) {
        backgroundColor = hex;
        visitorEle.attributes.fill = '${ backgroundColor }';
      }
    }
    // 设置宽度
    if (visitorEle.attributes?.width) {
      visitorEle.attributes.width = type === 'pipe' ? '${ sizeNumber*2 }px' : '${ sizeNumber }px';
    }
    // 设置高度
    if (visitorEle.attributes?.height) {
      visitorEle.attributes.height = '${ size }';
    }
  });

  const funcStr = `
function svgFunction(options?: EntitySvgIconOptions) {
  const size = options?.size ?? '64px';
  const sizeNumber = Number(size.slice(0,-2))
  const primaryColor = options?.primaryColor ?? ${JSON.stringify(primaryColor)};
  ${
    backgroundColor
    ? `
      const background = options?.background ?? true;
      let backgroundColor = options?.backgroundColor ?? ${JSON.stringify(backgroundColor)};
      backgroundColor = background ? backgroundColor : 'rgba(255, 255, 255, 0)';
    `
    : ''
  }

  return \`data:image/svg+xml,${xml.js2xml(result)}\`.replace(/"/g, "'").replace(/#/g, '%23');
}
`;
  return {
    colors,
    funcStr,
    primaryColor,
    backgroundColor,
  };
};

获取svg里所有的颜色(getSvgAllColors )

获取svg里所有的颜色,这里根据业务判断,深色的为主色、浅色的为背景色,所以根据颜色深浅排了个序,好为后续的颜色设置做准备(这部分代码可以自定义)

TypeScript 复制代码
const getSvgAllColors = (ele: Element) => {
  const colors: Array<{
    hex: string;
    rgb: number[];
    grayLevel: number;
  }> = [];

  svgVisitor(ele, (visitorEle) => {
    if (visitorEle.attributes?.fill) {
      const res = color(visitorEle.attributes.fill);
      const hex = res.hex();
      const rgb = res.rgb().array();

      colors.push({
        hex,
        rgb,
        // 颜色深浅判断算法,数值越小颜色越深
        grayLevel: rgb[0] * 0.299 + rgb[1] * 0.587 + rgb[2] * 0.114,
      });
    }
  });

  // 根据颜色的深浅排序
  colors.sort((a, b) => {
    return a.grayLevel - b.grayLevel;
  });

  return colors;
};
相关推荐
Lee川2 小时前
React 快速入门:Vue 开发者指南
前端·vue.js·react.js
用户6158139695162 小时前
Elpis: 基于vue3+webpack5+nodejs搭建一个完整项目
前端
90后的晨仔2 小时前
S C:\WINDOWS\system32> pnpm i -g openclaw@latest pnpm : 无法加载文件 C:\xx\A
前端
蜡台2 小时前
Node 版本管理器NVM 安装配置和使用
前端·javascript·vue.js·node·nvm
狂奔蜗牛飙车3 小时前
Day3:HTML5 基础标签:h1-h6、p、hr、br、a、img
前端·html·html5·html常用标签的使用方法
木斯佳3 小时前
前端八股文面经大全:腾讯前端暑期提前批一、二、三面面经(下)(2026-03-04)·面经深度解析
前端
bluceli3 小时前
前端国际化(i18n)实战指南:构建多语言应用的完整方案
前端
hh随便起个名3 小时前
React组件通信
前端·react.js·前端框架
前端 贾公子3 小时前
vite-plugin-eruda-pro 在vite中使用eruda
前端