VueJs中動態更改svg的相關屬性

前端掃地僧發表於2023-02-18
公司專案中有一個關於圖示庫管理的需求,大致需要在頁面能夠動態去更改對應svg圖示的大小、顏色等(這裡的更改顏色限制線性圖示)。在網上查詢了相關資料,做了技術的預研及demo的編寫,在此記錄一下。

怎樣將一個遠端的svg圖示資源"下載"到本地

首頁我們可以利用XMLHttpRequest物件來請求對應的svg圖示的遠端資源連結地址,並監聽實現XMLHttpRequest物件的load事件,將返回的資源進行dom物件的轉換、string轉換為xml。

程式碼如下:

const xhr = new XMLHttpRequest();
      xhr.open('GET', 'https://www.xx.com/img/xxx.svg', true);
      xhr.send();
      /* 監聽xhr物件 */
      xhr.onreadystatechange = function () {
        if (xhr.readyState == 4 && xhr.status == 200) {
          console.log(xhr.responseXML, 'xhr.responseXML---------')
        }
      };
      xhr.addEventListener('load', () => {
        const resXML = stringToXml(xhr.response);
        this.svgDom = resXML.documentElement.cloneNode(true);
      });

這裡的工具函式stringToXml的完整程式碼如下:

//將字串轉化成dom物件;string轉換為xml
function stringToXml (xmlString) {
  let xmlDoc;
  if (typeof xmlString == "string") {
    //FF
    if (document.implementation.createDocument) {
      const parser = new DOMParser();
      xmlDoc = parser.parseFromString(xmlString, "text/xml");
    } else if (window.ActiveXObject) {
      // eslint-disable-next-line no-undef
      xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
      xmlDoc.async = false;
      xmlDoc.loadXML(xmlString);
    }
  }
  else {
    xmlDoc = xmlString;
  }
  return xmlDoc;
}

這樣就可以獲取到遠端svg資源對應的dom結構了。

怎樣更改svgdom結構裡面的相關屬性

產品的要求需要能夠動態更改對應svg圖示的寬、高、顏色值等。要實現這樣的功能有以下幾個小點:

  1. 將svgDom物件轉換成vue的虛擬dom,程式碼如下:const oSerializer = new XMLSerializer()
  2. 根據序列化的物件提供的serializeToString方法將svgDom物件進行字串化;
  3. 透過svgDom物件提供的寬、高屬性值,結合正則來遍歷svgDom字串化後的字串,進行寬高值的替換。程式碼如下:

    let sXML = oSerializer.serializeToString(this.svgDom);
    sXML = sXML.replace(`width="${this.svgDom.width.baseVal.value}"`, 'width="40"').replace(`height="${this.svgDom.height.baseVal.value}"`, 'height="40"')
  4. 根據sXML來擷取svg結構表示的字串裡對應的顏色值,並結合is-color這個外掛判斷是否是一個真正的顏色,是的話,根據想要替換的顏色值進行全域性替換就行。程式碼如下:
      let curColor = sXML.split('#')[1].substr(0, 6)
      if (!isColor(`#${curColor}`)) {
        curColor = sXML.split('#')[1].substr(0, 3)
      }
      sXML = sXML.replace(new RegExp(`#${curColor}`, "gm"), '#90EE90')
  1. 透過Vue例項提供的extend方法建立例項並掛載到某個元素上,程式碼如下:
        const Profile = Vue.extend({
          template: "<div id='svgTemplate'>" + sXML + '</div>'
        });
        // 建立例項,並掛載到元素上
        new Profile().$mount('#svgTemplate');

處理前的效果圖:

image.png

處理後的效果圖(將svg寬高由原來的20變為40,將顏色值改為"#90EE90"):

image.png

最終完整的程式碼如下:

    testSvg () {
      const xhr = new XMLHttpRequest();
      xhr.open('GET', 'https://www.xx.com/img/xxx.svg', true);
      xhr.send();
      /* 監聽xhr物件 */
      xhr.onreadystatechange = function () {
        if (xhr.readyState == 4 && xhr.status == 200) {
          console.log(xhr.responseXML, 'xhr.responseXML---------')
        }
      };
      xhr.addEventListener('load', () => {
        const resXML = stringToXml(xhr.response);
        this.svgDom = resXML.documentElement.cloneNode(true);
        /* 將svgDom物件轉換成vue的虛擬dom */
        const oSerializer = new XMLSerializer();
        let sXML = oSerializer.serializeToString(this.svgDom);
        let curColor = sXML.split('#')[1].substr(0, 6)
        if (!isColor(`#${curColor}`)) {
          curColor = sXML.split('#')[1].substr(0, 3)
        }
        sXML = sXML.replace(`width="${this.svgDom.width.baseVal.value}"`, 'width="40"').replace(`height="${this.svgDom.height.baseVal.value}"`, 'height="40"').replace(new RegExp(`#${curColor}`, "gm"), '#90EE90')
        const Profile = Vue.extend({
          template: "<div id='svgTemplate'>" + sXML + '</div>'
        });
        // 建立例項,並掛載到元素上
        new Profile().$mount('#svgTemplate');
      });
    },

相關文章