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 文件,只要引用一次就行

相关推荐
海威的技术博客4 分钟前
JS中的原型与原型链
开发语言·javascript·原型模式
雪落满地香11 分钟前
前端:改变鼠标点击物体的颜色
前端
余生H43 分钟前
前端Python应用指南(二)深入Flask:理解Flask的应用结构与模块化设计
前端·后端·python·flask·全栈
outstanding木槿1 小时前
JS中for循环里的ajax请求不数据
前端·javascript·react.js·ajax
酥饼~1 小时前
html固定头和第一列简单例子
前端·javascript·html
一只不会编程的猫1 小时前
高德地图自定义折线矢量图形
前端·vue.js·vue
所以经济危机就是没有新技术拉动增长了1 小时前
二、javascript的进阶知识
开发语言·javascript·ecmascript
m0_748250931 小时前
html 通用错误页面
前端·html
来吧~1 小时前
vue3使用video-player实现视频播放(可拖动视频窗口、调整大小)
前端·vue.js·音视频
Bubluu1 小时前
浏览器点击视频裁剪当前帧,然后粘贴到页面
开发语言·javascript·音视频