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);