页面展示多个svg时有时显示异常的问题

前言

svg中的id,在整个node tree中不允许重复,不允许空格符号,不允许为空。

svg中的defs,W3规定,不会阻止其他元素来关联当前元素的defs的内容,因此全局node tree下的defs是公用的。

问题

在一个dom上下文中如果使用了多个相同的svg,比如一个tab组件的各个页面中,都用到了一个空数据的svg图片,该图片内部有定义defs和id的关联引用到一些填充或者渐变效果。当切换第一个tab之后的tab后,该svg图片会显示异常。

原因

第一个tab的svg一般会在dom的最上层位置,切换其他tab时,第一个tab可能会隐藏,比如css的display: none(当然,如果直接不渲染,比如vif,则判定第二个svg的状态)。该tab下的svg也会被隐藏。此时其他tab的svg引用的defs会是第一个svg下的,此时的效果显示状态也会以第一个svg的显示状态来决定,也就是隐藏。这样图片所有引用的渐变或者填充效果都无法显示,导致了异常。

解决方案
  1. 使用不同的svg图片

  2. 给svg的各个id添加动态定义的效果,比如用vue包装svg成组件后,动态生成id数组,保证每一个svg被使用时都产生新的id内容。

  3. 既然svg通过一个dom上下文来确定当前所有svg的信息,那么将不同的svg放入不同的dom上下文中就好了,比如通过iframeobject标签包装一层。

  4. 一般图标组件会有一种通过vue组件化的方式来调用。使用时直接以vue组件方式引入。

当从svg——>Vue Component时,可以在转化时,通过vue的特性,匹配替换svg内容中有通过url+id的方式引入公共元素的地方,一般有mask等。通过正则匹配,增加时间戳替换其id值和url内的内容,使用vue的组件props方式达到一个svg-vue组件内的id唯一的效果。

let content = svgData.inner // svg内所有元素形成的字符串
  // 匹配svg中所有id="任意字符"的内容
  const reg = /id="(.*?)"/g
  const matches = content.match(reg)
  const id2IdTimestampMap = new Map()
  if (matches) {
    matches.forEach((match) => {
      // 匹配id="任意字符"中的任意字符
      const id = match.match(/id="(.*?)"/)?.[1]
      if (id) {
        const replaceIdContent = `${id}`
        // 替换svg中所有id="任意字符"的内容为id="任意字符+时间戳"
        content = content.replace(
          match,
          `:id="'${replaceIdContent}' + timeStamp"`
        )
        id2IdTimestampMap.set(id, replaceIdContent)
      }
    })
  }
  // 匹配svg中所有\w+="url(#任意字符)"中的任意字符,同时替换成:\w+="`url(#${任意字符})`"
  const reg2 = /(\w+)="url\(#(.*?)\)"/g
  const matches2 = content.match(reg2)
  if (matches2) {
    matches2.forEach((match) => {
      // 匹配\w+="url(#任意字符)"中的任意字符
      const matches = match.match(/(\w+)="url\(#(.*?)\)"/)
      const id = matches?.[2]
      const attrName = matches?.[1]
      if (id) {
        const replaceIdContent = id2IdTimestampMap.get(id)
        // 替换svg中所有\w+="url(#任意字符)"的内容为\w+="`url(#${任意字符})`"
        content = content.replace(
          match,
          `:${attrName}="'url(#${replaceIdContent}'+timeStamp+')'"`
        )
      }
    })
  }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值