• 0
  • 0
  • 0
  • 一个即插即用的 SVG 图标组件库:svg-icons.js 使用指南

  • 小小baby
  • 5
  • 2026-10-31 22:06
  • 写这篇文章的起因:团队里越来越多人往页面里塞 <img>、emoji、字体图标来占位,导致样式五花八门、加载慢、颜色对不齐。于是我开发了一个极简的 SVG 图标封装库,一个脚本文件 + 一行 data- 属性就能用,分享给各位作者。

    一、它是什么

    svg-icons.js 是一个基于 jQuery 的轻量级 SVG 图标渲染器,核心特性:

    • 📦 单文件,零依赖(除了 jQuery)
    • 🎨 图标颜色跟随 currentColor,自动继承父元素文字颜色
    • 🔁 幂等渲染,重复调用不会插入多个 SVG
    • 🧩 保留占位元素原有内容(文字、子元素都不动)
    • 🚀 支持动态内容(AJAX 插入后调用一次 render 即可)
    • ➕ 可热插拔新图标(addIcon)

    整个库就 200 来行,把 comment、like、save、share、more、search、message、heat、view、time 等常用图标都内置好了。

    二、快速开始

    1. 引入脚本

    <!-- 先 jQuery,再图标库 -->
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script src="script/svg-icons.js"></script>

    2. 在 HTML 里占位

    <!-- 空元素:只放图标 -->
    <i data-svg-icon="comment"></i>
    
    <!-- 带文字:图标插在文字前面,文字保留 -->
    <a data-svg-icon="featured">精选</a>
    
    <!-- 带数字:常见于点赞 / 评论 -->
    <li data-svg-icon="like">128</li>

    3. 打开页面

    脚本在 DOMContentLoaded 时自动扫描 [data-svg-icon] 并渲染,无需任何 JS 调用。

    效果等价于:

    <i data-svg-icon="comment">
      <svg class="icon" viewBox="0 0 1024 1024" ...>...</svg>
    </i>

    图标会自动继承父元素的字体大小(1.1em)和颜色(currentColor)。

    三、内置图标速查表

    图标名用途尺寸
    comment评论气泡1.1em
    like点赞拇指1.1em
    save收藏 / 星标1.1em
    share分享1.1em
    more更多(三个点)1.1em
    featured精选徽章(自带配色)1.8em
    menu汉堡菜单24px
    search搜索放大镜1.2rem
    message消息铃铛1.5em
    heat热度火焰1em
    view阅读量眼睛1.1em
    time时钟1.1em
    close / prev / next弹窗关闭 / 翻页自适应
    注意:收藏图标注册名是 save,不是 favorite。如果项目里习惯写 favorite,可以在脚本里加一行别名(见第七节)。

    四、核心用法

    4.1 静态页面:什么都不用做

    <div class="action-bar">
      <span data-svg-icon="comment">12</span>
      <span data-svg-icon="like">88</span>
      <span data-svg-icon="save">6</span>
    </div>

    打开就有图标,DOMContentLoaded 后自动渲染。

    4.2 动态内容:插入后调用一次 render

    这是最容易踩坑的地方。 AJAX 拉数据后用 html() / append() 插入的 [data-svg-icon] 不会自动渲染,因为自动渲染只跑一次。

    正确姿势:

    $.ajax({
      url: '/api/posts',
      success: function (res) {
        var html = '';
        res.data.forEach(function (item) {
          html += '<li>' +
            '<span data-svg-icon="like">' + item.like_count + '</span>' +
            '<span data-svg-icon="comment">' + item.comment_count + '</span>' +
            '</li>';
        });
    
        var $container = $('#list');
        $container.html(html);
    
        // ★ 关键一行:手动渲染动态插入的图标
        window.svgIcon.render($container);
      }
    });

    render(container) 支持传:

    • 不传 / document → 全文档扫描
    • DOM 节点 → 只扫这个节点内部
    • jQuery 对象 → 同上
    • CSS 选择器字符串 → 转成 DOM 再扫

    4.3 手动指定渲染范围

    // 只渲染某个卡片
    svgIcon.render('.card');
    
    // 只渲染某个 DOM
    svgIcon.render(document.getElementById('content'));

    五、API 参考

    svgIcon 暴露两个方法:

    svgIcon.render(container?)

    在指定容器内扫描 [data-svg-icon],把对应 SVG 前置插入到占位元素内。

    • 幂等:元素内已有 <svg> 直接跳过,多次调用无副作用
    • 保留内容:用 prepend 插入,原有文字/子元素全部保留
    • 缺图告警:图标名不存在时 console.warn('SVG icon not found: xxx')

    svgIcon.addIcon(name, svgString)

    运行时注册新图标,适用于业务自定义图标或临时补齐:

    svgIcon.addIcon('star', '<svg viewBox="0 0 24 24" width="1em" height="1em" fill="currentColor"><path d="..."/></svg>');
    
    // 之后即可使用
    svgIcon.render();
    <i data-svg-icon="star"></i>

    六、样式控制

    6.1 颜色:靠 currentColor

    图标统一使用 fill="currentColor",所以只要设置父元素的 color,图标自动变色:

    css

    .tab.active { color: #4510E6; }   /* 图标同步变色 */
    .btn-danger  { color: #e33; }

    不需要给 SVG 单独写 fill。

    6.2 尺寸:靠 font-size

    默认尺寸是 1.1em,同样跟随父元素字体大小:

    .comment-item .icon { font-size: 14px; }

    或者用 em:

    span[data-svg-icon] { font-size: 1.2em; }

    6.3 对齐

    图标默认和文字在基线附近,建议给占位元素加 display:inline-flex; align-items:center;:

    [data-svg-icon] {
      display: inline-flex;
      align-items: center;
      gap: 4px;
      vertical-align: middle;
    }

    七、常见坑与解决方案

    坑 1:图标名对不上(favorite vs save)

    如果你在业务里习惯写 data-svg-icon="favorite",但库里只有 save,就会报 SVG icon not found: favorite。

    解决:在 svg-icons.js 的 icons 对象后加一行别名:

    var icons = { /* ... */ };
    
    // 别名:favorite → save
    icons.favorite = icons.save;

    addIcon 也行:

    svgIcon.addIcon('favorite', window.svgIcon.icons.save); // 不推荐,icons 未暴露

    所以推荐直接改源码加别名。

    坑 2:动态渲染后图标不出来

    就是第四节说的:AJAX 插入后必须调用一次 svgIcon.render($container)。

    建议封装一个小助手:

    function renderIcons(container) {
      if (window.svgIcon) window.svgIcon.render(container);
    }

    坑 3:重复渲染

    不需要防抖。render 内部有幂等判断:

    if ($el.children('svg').length > 0) return;

    滚动加载、重复调用都安全。

    坑 4:图标带了固定颜色

    featured 图标里有写死的 fill="#50E3C2" / fill="#4510E6",不跟随 currentColor,这是有意设计的——精选徽章要固定配色。

    如果需要它跟着文字变色,自己替换 SVG 里的 fill 即可。

    八、扩展:添加自己的图标

    方式 1:改源码(推荐,长期维护)

    打开 svg-icons.js,在 icons 对象里加一条:

    var icons = {
      // ... 现有图标
      bell: '<svg viewBox="0 0 24 24" width="1.1em" height="1.1em" fill="currentColor"><path d="..."/></svg>'
    };

    方式 2:运行时注册(适合插件化、按需加载)

    // 从后端或图标 API 拿到 SVG
    fetch('/icons/star.svg')
      .then(r => r.text())
      .then(svg => {
        svgIcon.addIcon('star', svg);
        svgIcon.render();
      });

    方式 3:批量注册

    var customIcons = {
      star: '<svg ...>',
      heart: '<svg ...>',
      bell: '<svg ...>'
    };
    Object.keys(customIcons).forEach(function (name) {
      svgIcon.addIcon(name, customIcons[name]);
    });
    svgIcon.render();

    九、打包/模块化说明

    当前是 IIFE + 全局变量写法,适合传统多页应用(<script> 直接引入)。

    • 依赖:jQuery,通过 IIFE 参数传入
    • 暴露:window.svgIcon
    • 严格模式:内部 'use strict',不会污染全局

    如果未来要接 Vue / React / 原生 ESM,可以按这个思路改造:

    // ESM 版本伪代码
    export function renderIcons(container = document) { /* ... */ }
    export function addIcon(name, svg) { /* ... */ }

    但在迁移前,现有全局 API 已足够覆盖绝大多数场景。

    十、最佳实践清单

    • 占位元素只放 data-svg-icon 属性,不写死 <svg>
    • 动态内容插入后,务必调用 svgIcon.render(container)
    • 颜色靠父元素 color,尺寸靠父元素 font-size
    • 图标名统一团队命名规范(推荐 kebab-case 或单词)
    • 自定义图标加在源码 icons 里,方便统一维护
    • 不要在 [data-svg-icon] 里塞 JS 事件——图标是 <i>/<span> 占位,事件应该绑在外层容器上
    • 不要用 svgIcon.render() 全局扫描做高频操作(比如每 100ms 刷新一次列表),性能不划算

    十一、一句话总结

    一个属性 data-svg-icon="xxx" 就能把任意元素变成 SVG 图标容器,动态内容插入后补一次 svgIcon.render(el) 就完事。

    如果你也在维护一个多作者协作的前端项目,把这篇甩到群里,可以省掉 80% 关于"图标怎么用"的沟通成本。

    附:一个完整示例

    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="UTF-8">
      <style>
        [data-svg-icon] {
          display: inline-flex;
          align-items: center;
          gap: 4px;
          color: #666;
          font-size: 14px;
        }
        [data-svg-icon]:hover { color: #4510E6; }
      </style>
    </head>
    <body>
      <ul id="post-list"></ul>
    
      <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
      <script src="script/svg-icons.js"></script>
      <script>
        // 模拟数据
        var posts = [
          { id: 1, likes: 128, comments: 32 },
          { id: 2, likes: 456, comments: 88 }
        ];
    
        var html = posts.map(function (p) {
          return '<li>' +
            '<span data-svg-icon="like">' + p.likes + '</span>' +
            '<span data-svg-icon="comment">' + p.comments + '</span>' +
            '<span data-svg-icon="save"></span>' +
            '<span data-svg-icon="share"></span>' +
            '</li>';
        }).join('');
    
        $('#post-list').html(html);
        svgIcon.render('#post-list'); // ← 动态内容关键一行
      </script>
    </body>
    </html>

    希望这篇文章能让你在团队协作里少踩坑。有问题或想贡献新图标,欢迎在脚本里提 PR 👋

    附:本文基于 svg-icons.js v1.0 编写,后续新增图标或 API 变更请同步更新本文档。

    源码:

    /**
     * SVG 图标封装库
     * 依赖: jQuery
     * 用法:
     *   1. 在页面中放置占位元素:<span data-svg-icon="comment"></span>
     *      或带文字:<a data-svg-icon="featured">精选</a>
     *   2. 引入 jQuery 和本文件,图标会自动渲染(不会清空元素内的文字或HTML)
     *   3. 也可手动调用:window.svgIcon.render(selector)
     *   4. 已渲染过的元素不会重复插入图标
     */
    
    ; (function ($, window, document, undefined) {
        'use strict';
    
        // ==================== 图标表 ====================
        // 自行添加:key 是图标名,value 是完整 <svg> 字符串
        // 建议:viewBox="0 0 1024 1024"、width/height="1.1em"、fill="currentColor"
        var icons = {
            // 示例:评论图标
            comment: '<svg class="icon" viewBox="0 0 1024 1024" width="1.1em" height="1.1em" fill="currentColor"><path d="...在这里粘贴你的 path 数据..."/></svg>',
    
            // 示例:更多(三个点)
            more: '<svg class="icon" viewBox="0 0 1024 1024" width="1.1em" height="1.1em" fill="currentColor"><path d="..."/></svg>'
    
            // 继续按上面的格式添加 like / save / share / search ...
        };
    
        // ==================== 渲染函数 ====================
        // 将指定容器内所有 [data-svg-icon] 占位元素前置插入对应 SVG
        function render(container) {
            container = container || document;
            $(container).find('[data-svg-icon]').each(function () {
                var $el = $(this);
                var iconName = $el.data('svg-icon');
    
                // 幂等:元素内已插入过 svg 则跳过,重复调用不会叠图
                if ($el.children('svg').length > 0) {
                    return;
                }
    
                if (icons[iconName]) {
                    // prepend:图标在前,原有文字/子元素全部保留
                    $el.prepend($(icons[iconName]));
                } else {
                    console.warn('SVG icon not found: ' + iconName);
                }
            });
        }
    
        // ==================== 对外 API ====================
        window.svgIcon = {
            render: render,
            // 运行时注册新图标
            addIcon: function (name, svgString) {
                icons[name] = svgString;
            }
        };
    
        // ==================== 自动渲染 ====================
        // DOM 就绪后扫描全文档,渲染初始占位元素
        $(function () {
            render();
        });
    
    })(jQuery, window, document);


    评论

  • 0
    /1000
    最热
  • 最新
    • 目录
    • 0
    • 0
    • 0
    登录后参与评论