iconfont的一个坑(使用symbol方式引入多个icon导致覆盖)

问题发生

最近写项目的时候想用几个 icon,遂上 iconfont 寻找

在下载下来的 demo 文件中,我们可以看到官方推荐我们使用 Symbol 引用方式

于是我就是用了这种方式,但是当我引入第二个 icon 的时候,我发现我第一个 icon 不显示了

demo代码如下:

xml 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      .icon {
        width: 1em;
        height: 1em;
        vertical-align: -0.15em;
        fill: currentColor;
        overflow: hidden;
      }
    </style>
  </head>
  <body>
    <svg class="icon" aria-hidden="true">
      <use xlink:href="#icon-github"></use>
    </svg>
    <svg class="icon" aria-hidden="true">
      <use xlink:href="#icon-juejin"></use>
    </svg>
    <script src="./src/assets/github/iconfont.js"></script>
    <script src="./src/assets/juejin/iconfont.js"></script>
  </body>
</html>

显示结果:

可以看到只显示了掘金的 icon,没有 github 的 icon

解决

经过一番排查,我发现可能发生了覆盖,因为只有后导入的标签进行了显示。

use 的使用

这里 use 标签的在 SVG 文档内取得目标节点,并在别的地方复制它们,

通过它的 xlink 属性,实现了和 js 文件(也就是我们引入的文件)中 symbol 标签的 id 连结。

所以显示什么文件由这里的xlink:href后的 id 决定。

那照这么说,既然由 id 区分,怎么会出现覆盖冲突呢?

Js 文件

我们前往导入的 js 文件中,观察/github/iconfont.js/juejin/iconfont.js的区别

可以看到这里先是在 window 上定义了一个属性_iconfont_svg_string_然后立即执行后面的函数并把 windows 传入作为 n

然后在该函数中等待 document 加载好后会调用到赋值的函数 o,这里函数 o 赋值也是通过window._iconfont_svg_string_属性得到的

javascript 复制代码
(window._iconfont_svg_string_ =
  '<svg><symbol id="icon-github" viewBox="0 0 1024 1024"><path d="M511.957333 21.333333C241.024 21.333333 21.333333 240.981333 21.333333 512c0 216.832 140.544 400.725333 335.573334 465.664 24.490667 4.394667 32.256-10.069333 32.256-23.082667 0-11.690667 0.256-44.245333 0-85.205333-136.448 29.610667-164.736-64.64-164.736-64.64-22.314667-56.704-54.4-71.765333-54.4-71.765333-44.586667-30.464 3.285333-29.824 3.285333-29.824 49.194667 3.413333 75.178667 50.517333 75.178667 50.517333 43.776 75.008 114.816 53.333333 142.762666 40.789333 4.522667-31.658667 17.152-53.376 31.189334-65.536-108.970667-12.458667-223.488-54.485333-223.488-242.602666 0-53.546667 19.114667-97.322667 50.517333-131.669334-5.034667-12.330667-21.930667-62.293333 4.778667-129.834666 0 0 41.258667-13.184 134.912 50.346666a469.802667 469.802667 0 0 1 122.88-16.554666c41.642667 0.213333 83.626667 5.632 122.88 16.554666 93.653333-63.488 134.784-50.346667 134.784-50.346666 26.752 67.541333 9.898667 117.504 4.864 129.834666 31.402667 34.346667 50.474667 78.122667 50.474666 131.669334 0 188.586667-114.730667 230.016-224.042666 242.090666 17.578667 15.232 33.578667 44.672 33.578666 90.453334v135.850666c0 13.141333 7.936 27.605333 32.853334 22.869334C862.250667 912.597333 1002.666667 728.746667 1002.666667 512 1002.666667 240.981333 783.018667 21.333333 511.957333 21.333333z"  ></path></symbol></svg>'),
  (function (n) {
      //...省略
      (o = function () {
        var t,
          e = document.createElement("div");
        (e.innerHTML = n._iconfont_svg_string_),
          (e = e.getElementsByTagName("svg")[0]) &&
            (e.setAttribute("aria-hidden", "true"),
            (e.style.position = "absolute"),
            (e.style.width = 0),
            (e.style.height = 0),
            (e.style.overflow = "hidden"),
            (e = e),
            (t = document.body).firstChild
              ? a(e, t.firstChild)
              : t.appendChild(e));
      }),
        document.addEventListener
          ? ~["complete", "loaded", "interactive"].indexOf(document.readyState)
            ? setTimeout(o, 0)
            : ((i = function () {
                document.removeEventListener("DOMContentLoaded", i, !1), o();
              }),
              document.addEventListener("DOMContentLoaded", i, !1))
          : document.attachEvent &&
            ((c = o),
            (d = n.document),
            (s = !1),
            r(),
            (d.onreadystatechange = function () {
              "complete" == d.readyState &&
                ((d.onreadystatechange = null), l());
            }));
    }
    //...省略
  })(window);

而另一个 js 文件类似,除了 symbol 的 id 不一样之外

我们可以通过一个更简单的函数来模拟这两个 js 文件一起使用的情况:

lua 复制代码
let a = {};
(a.status = "unhappy"),
  (function (n) {
    setTimeout(function () {
      console.log(n.status);
    }, 0);
  })(a);
(a.status = "happy"),
  (function (n) {
    setTimeout(function () {
      console.log(n.status);
    }, 0);
  })(a);

答案显然是输出两个 happy,而我们在引入两个js文件的时候,window上的属性也会出现相同的情况。

解决方法

1.修改 js 文件中的_iconfont_svg_string_属性,防止两个重合

2.在 iconfont 里不要分开引用,把要用的图标同时放购物车里再下载,这样下载下来的图标声明都在同一个 js 文件,只要引用一次就行

相关推荐
WeiXiao_Hyy12 分钟前
成为 Top 1% 的工程师
java·开发语言·javascript·经验分享·后端
吃杠碰小鸡29 分钟前
高中数学-数列-导数证明
前端·数学·算法
kingwebo'sZone35 分钟前
C#使用Aspose.Words把 word转成图片
前端·c#·word
xjt_09011 小时前
基于 Vue 3 构建企业级 Web Components 组件库
前端·javascript·vue.js
我是伪码农1 小时前
Vue 2.3
前端·javascript·vue.js
夜郎king2 小时前
HTML5 SVG 实现日出日落动画与实时天气可视化
前端·html5·svg 日出日落
辰风沐阳2 小时前
JavaScript 的宏任务和微任务
javascript
夏幻灵3 小时前
HTML5里最常用的十大标签
前端·html·html5
冰暮流星3 小时前
javascript之二重循环练习
开发语言·javascript·数据库
Mr Xu_3 小时前
Vue 3 中 watch 的使用详解:监听响应式数据变化的利器
前端·javascript·vue.js