vue动态渲染svg、添加点击事件的实现
业务需求(vue项⽬中)
1.页⾯展⽰svg内容
2.监听svg内部的点击事件
3.动态改变svg内部元素的属性和值
html标签
经多次实验,⽤embed、img等标签改变src属性的⽅式,均⽆法实现上述全部功能(尤其是svg内部点击事件),最终采⽤d()⽅法完整实现,代码也较为简洁,html结构如下:
<template>
<div>
<div id="svgTemplate"></div>
</div>
</template>
直接将svg⽂件的内容复制粘贴到.vue⽂件⾥,是可以在标签内直接添加@click事件完成需求的,⽅式简单但会造成⽂件过长,本⽂不多陈述
实现思路
1.创建xhr对象
const xhr = new XMLHttpRequest();
this.svgUrl = ...; // svg的绝对地址,在浏览器中打开能看到的那个
xhr.open("GET", this.svgUrl, true);
xhr.send();
2.监听xhr对象(获取svg的dom -> 添加事件 -> 修改dom -> 转成虚拟dom并挂载)
xhr.addEventListener("load", () => {
// ①获取svg的dom
const resXML = sponseXML;
this.svgDom = resXML.documentElement.cloneNode(true); // console.log(this.svgDom);
// ②添加click事件
let btn = ElementById("...");
btn.setAttribute("v-on:click", "this.handleClick()");
// ↑↑↑此处注意:原⽣事件handleClick此时在window层,解决办法见后⽂
// ③修改 dom
ElementById("...").childNodes[0].nodeValue = ...
ElementById("...").setAttribute("style",
`....; fill:${sultColor}; ...`);
// ↑↑↑⽤js操作dom的语法,动态设置svg部件的属性和值
/
/ ④将svgDom对象转换成vue的虚拟dom,创建实例并挂载到元素上
var oSerializer = new XMLSerializer();
var sXML = oSerializer.serializeToString(this.svgDom);
var Profile = d({
template: "<div id='svgTemplate'>" + sXML + "</div>"
});
new Profile().$mount("#svgTemplate");
});
3.将methods⾥要执⾏的事件绑定到window下⾯,供外部(刚添加的 handleClick 事件)调⽤
async mounted() {
window["handleClick"] = () => {
this.takePhoto();
};
},
methods:{
takePhoto(){ ... }
}
到这⾥就基本完成需求:动态渲染了svg、⽤js操作dom的语法修改svg部件的属性和值、给svg部件动态添加了事件handleClick,最后将 takePhoto() 事件绑定给了 window 对象的 handleClick,可以放⼼⼤胆的在 takePhoto() ⾥写你要执⾏
的内容了!
特殊注意
给svg的dom部件添加事件时:
1.经多次尝试,只有 setAttribute + v-on:click 写法有效
2.setAttribute 不⽀持 @click(⾮原⽣事件),会报语法错误
3.addEventListener 和 onclick 均会被 vue 拦截
将svgDom对象转换成vue的虚拟dom时:
1.如果报错如下
则将 import Vue from "vue" 改为 import Vue from "vue/dist/vue.esm.js"
其原因及其他解决办法本⽂不做探讨可⾃⾏百度。
d() ⽅法是 vue 的⼀个构造器,⽤来动态创建 vue 实例,template 组件模板只能有⼀个根元素
3.$mount ⼿动挂载到 id 为 svgTemplate的元素上,挂载后将替换原本的dom(替换原本的 <div id="svgTemplate">
</div>)。由于每次更新 svg 都要重新挂载,没有到 dom 元素是⽆法挂载的,因此 template ⾥⾯最
外层的 div 也要加上 id 的属性:
var Profile = d({
template: "<div id='svgTemplate'>" + sXML + "</div>"
// ↑↑↑最外层的 id 不能省略,否则⾸次渲染后不到 #svgTemplate
});
new Profile().$mount("#svgTemplate");
// ↑↑↑原本的 #svgTemplate 将被替换成 Profile 的 template
完整代码
<template>
<div>
<div id="svgTemplate"></div>
</div>
</template>
<script>
import Vue from "vue/dist/vue.esm.js";
// window.handleClick = () => {
// 原本的 handleClick 事件是 window 的
// };
export default {
name: "svg-drawing",
data() {
return {
/
* 全局 */
svgUrl: "", // svg的url
svgDom: null, // 获取到的svg元素
svg实例/* svg的变量 */
photoResult: {
resultVal: 0, // 测试结果 - 值
resultMsg: "未检测", // 测试结果 - 字段
resultColor: "#dcdee2" // 测试结果 - 字段背景⾊
}
};
},
async mounted() {
// 将takePhoto⽅法绑定到window下⾯,提供给外部调⽤
window["handleClick"] = () => {
this.takePhoto();
};
},
created() {
},
methods: {
// 初始化svg
getSvg() {
/* 创建xhr对象 */
const xhr = new XMLHttpRequest();
this.svgUrl = this.baseUrl + "/svgs/" + "test.svg";
xhr.open("GET", this.svgUrl, true);
xhr.send();
/* 监听xhr对象 */
xhr.addEventListener("load", () => {
/* 1. 获取 dom */
const resXML = sponseXML;
this.svgDom = resXML.documentElement.cloneNode(true);
/
* 2.SVG对象添加click事件 */
let btnTakePhotoDom = ElementById("...");
btnTakePhotoDom.setAttribute("v-on:click", "this.handleClick()");
/* 3. 修改 dom */
ElementById("...").childNodes[0].nodeValue = ...;
ElementById("...").setAttribute("style",
`....; fill:${sultColor}; ...`);
/* 4.将svgDom对象转换成vue的虚拟dom */
var oSerializer = new XMLSerializer();
var sXML = oSerializer.serializeToString(this.svgDom);
var Profile = d({
template: "<div id='svgTemplate'>" + sXML + "</div>"
});
// 创建实例,并挂载到元素上
new Profile().$mount("#svgTemplate");
});
},
// 事件
takePhoto() { ... },
},
beforeDestroy() {
this.svgDom = null;
},
watch: {
photoResult: {
handler(newVal, oldVal) {
},
deep: true
}
}
};
</script>
到此这篇关于vue动态渲染svg、添加点击事件的实现的⽂章就介绍到这了,更多相关vue动态渲染svg、添加点击事件内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论