vue中动态渲染svg、添加点击事件

825 阅读1分钟

ps:需求是有一个地图svg链接,需要点击某个板块,就以g对象为例添加点击事件,跳转到对应的链接;

1.页面引入Vue

import Vue from "vue/dist/vue.esm.js";

2.data中定义全局svgDome,主要是获取svg元素,以及定义svgLink就是svg网络链接;

3.在mounted中调取方法,以及写handleClick方法;

4.getSvg方法:

  • 创建xhr对象
  • 监听xhr对象
  • 获取 dom
  • 把style赋值到svg的DOM中(如果不把style赋值到dom中,fill会是全部为空),这里提取style运用了正则匹配,参考链接:blog.csdn.net/reembarkati…
  • SVG对象添加click事件 修改 dom
  • 将svgDom对象转换成vue的虚拟dom
  • 创建实例,并挂载到元素上
<template>
  <div id="svgTemplate"></div>
</template>
<script>

import Vue from "vue/dist/vue.esm.js";
export default {
 name: "svg-drawing", 
 data() {
  return {
   /* 全局 */   
   svgDom: null, // 获取到的svg元素
   /* svg的链接 */
   svgLink:'https://xxxx.com/svg.svg'
 },
 async mounted() {  
  console.log("svgLink",this.svgLink);
  if(this.svgLink) this.getSvg();
  window["handleClick"] = (i) => {   
    console.log(i,this.svgDom);     
  };
 },
 methods: {
  // 初始化svg
  getSvg() {
   /* 创建xhr对象 */
   const xhr = new XMLHttpRequest();   
   xhr.open("GET", this.svgLink, true);
   xhr.send();
   /* 监听xhr对象 */
   xhr.addEventListener("load", () => {
    /* 1. 获取 dom */
    const resXML = xhr.responseXML;
    this.svgDom = resXML.documentElement.cloneNode(true);    
    let style = this.svgDom.getElementsByTagName("style")[0];  //获取svg中的style
    style.parentNode.removeChild(style); //svg删除style,不删除会报错;     
    /*获取单个style*/
    let str=`${style.innerHTML}`;
    let classNames=[];
    let classes=[]
    let classObj={}
    var res=str.match(/\.[\w\-]+/ig); 
    if(res && res.length>0){
      for(let item of res){
        if(!classNames.includes(item)){
          classNames.push(item)
        }
      }    
    console.log('classNames',classNames)
    var res3=str.match(/(\.[\w\-\,]+(\s)*)*\{([^}\.])*}/ig); 
    classes.push(...res3)
    console.log('classes',classes)
    for(let name of classNames){
      let inname=classes.filter(x=>x.indexOf(name)>=0)
      let allstype=""
      if(inname && inname.length>0){
        
         for(let style of inname){
           let res4=style.match(/\{([^}\.])*}/g); 
           if(res4 && res4.length>0){
              allstype = allstype + res4[0].replace("{","").replace("}","")
           }
         }
         classObj[name]=allstype
      }
    }
    console.log('classObj',classObj)
    }
    console.log(this.svgDom )
    /* SVG对象添加click事件 修改 dom*/
    let btnTakePhotoDom = this.svgDom.getElementsByTagName("path") //path对象
    let getgDom = this.svgDom.getElementsByTagName("g") //g对象
    let rectBtn = this.svgDom.getElementsByTagName("rect");  //rect对象
    console.log(rectBtn)
    console.log(btnTakePhotoDom);
    for(let i=0,len=btnTakePhotoDom.length;i<len;i++){   //path对象的样式补全以及添加事件      
      for(let key in classObj){
        if(key==`.${hasClassName}`){
          btnTakePhotoDom[i].setAttribute("style",`${classObj[key]}`);         
        }
      }
    }   
    for(let i=0,len=getgDom.length;i<len;i++){   //g对象的样式补全
      for(let key in classObj){
      getgDom[i].setAttribute("svgchId", i);  
      getgDom[i].setAttribute("v-on:click", "this.handleClick("+getgDom[i].getAttribute('svgId')+")");
      let hasClassName = getgDom[i].getAttribute("class");
        let hasClassName = getgDom[i].getAttribute("class");
        if(key==`.${hasClassName}`){
          getgDom[i].setAttribute("style",`${classObj[key]}`);
        }
      }
    }
    /* 将svgDom对象转换成vue的虚拟dom */
    var oSerializer = new XMLSerializer();
    var sXML = oSerializer.serializeToString(this.svgDom);
    let that = this;
    var Profile = Vue.extend({
      template: "<div id='svgTemplate'>" + sXML + "</div>"
    });
    // 创建实例,并挂载到元素上
    new Profile().$mount(`#svgTemplate`);    
   });

  },

以上是vue2的方法,vue3的方法大致一样,只有两个方面略有不同;

1.在mounted中不需要写handleClick,而是在svgDom转换成虚拟dom的时候写方法;
2.引用vue也不同,直接引用import Vue from 'vue';

/* 将svgDom对象转换成vue的虚拟dom */
    var oSerializer = new XMLSerializer();
    var sXML = oSerializer.serializeToString(this.svgDom);
    let that = this;
    const Profile = createApp({
     template: "<div id='svgTemplate'>" + sXML + "</div>",
     methods:{
      handleClick(id) {
        console.log(id);
        //这里可以掉用metchods的方法,
        that.handleClick(id)
      }
     }
    });
    const parent = document.getElementById("svgTemplate"); 
    // 创建实例,并挂载到元素上
    Profile.mount(parent);