vue动态渲染svg、添加点击事件的实现


Posted in Javascript onMarch 13, 2020

业务需求(vue项目中)

1.页面展示svg内容
2.监听svg内部的点击事件
3.动态改变svg内部元素的属性和值

html标签

经多次实验,用embed、img等标签改变src属性的方式,均无法实现上述全部功能(尤其是svg内部点击事件),最终采用Vue.extend()方法完整实现,代码也较为简洁,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 = xhr.responseXML;
  this.svgDom = resXML.documentElement.cloneNode(true);   // console.log(this.svgDom);
  
  // ② 添加click事件
  let btn = this.svgDom.getElementById("...");
  btn.setAttribute("v-on:click", "this.handleClick()");
  // ↑↑↑ 此处注意:原生事件handleClick此时在window层,解决办法见后文

  // ③ 修改 dom
  this.svgDom.getElementById("...").childNodes[0].nodeValue = ...
  this.svgDom.getElementById("...").setAttribute("style",
     `....; fill:${this.photoResult.resultColor}; ...`);
  // ↑↑↑ 用js操作dom的语法,动态设置svg部件的属性和值
  
  // ④ 将svgDom对象转换成vue的虚拟dom,创建实例并挂载到元素上
  var oSerializer = new XMLSerializer();
  var sXML = oSerializer.serializeToString(this.svgDom);
  var Profile = Vue.extend({
    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"
其原因及其他解决办法本文不做探讨可自行百度。
2.vue.extend() 方法是 vue 的一个构造器,用来动态创建 vue 实例,template 组件模板只能有一个根元素
3.$mount 手动挂载到 id 为 svgTemplate的 元素上,挂载后将替换原本的dom(替换原本的 <div id="svgTemplate"></div>)。由于每次更新 svg 都要重新挂载,没有找到 dom 元素是无法挂载的,因此 template 里面最外层的 div 也要加上 id 的属性:

var Profile = Vue.extend({
   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的变量 */
   photoResult: {
    resultVal: 0, // 测试结果 - 值
    resultMsg: "未检测", // 测试结果 - 字段
    resultColor: "#dcdee2" // 测试结果 - 字段背景色
   }
  };
 },
 async mounted() {
  // 将takePhoto方法绑定到window下面,提供给外部调用
  window["handleClick"] = () => {
   this.takePhoto();
  };
 },
 created() {
  this.getSvg();
 },
 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 = xhr.responseXML;
    this.svgDom = resXML.documentElement.cloneNode(true);

    /* 2.SVG对象添加click事件 */
    let btnTakePhotoDom = this.svgDom.getElementById("...");
    btnTakePhotoDom.setAttribute("v-on:click", "this.handleClick()");

    /* 3. 修改 dom */
    this.svgDom.getElementById("...").childNodes[0].nodeValue = ...;
    this.svgDom.getElementById("...").setAttribute("style",
     `....; fill:${this.photoResult.resultColor}; ...`);

    /* 4.将svgDom对象转换成vue的虚拟dom */
    var oSerializer = new XMLSerializer();
    var sXML = oSerializer.serializeToString(this.svgDom);
    var Profile = Vue.extend({
     template: "<div id='svgTemplate'>" + sXML + "</div>"
    });
    // 创建实例,并挂载到元素上
    new Profile().$mount("#svgTemplate");
   });
  },
  // 事件
  takePhoto() { ... },
 },
 beforeDestroy() {
  this.svgDom = null;
 },
 watch: {
  photoResult: {
   handler(newVal, oldVal) {
    this.getSvg();
   },
   deep: true
  }
 }
};
</script>

到此这篇关于vue动态渲染svg、添加点击事件的实现的文章就介绍到这了,更多相关vue动态渲染svg、添加点击事件内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
JS中剪贴板兼容性、判断复制成功或失败
Mar 09 Javascript
两个Javascript小tip资料
Nov 23 Javascript
JQuery伸缩导航练习示例
Nov 13 Javascript
原生JS查找元素的方法(推荐)
Nov 22 Javascript
轻松理解JavaScript闭包
Mar 14 Javascript
如何使用Bootstrap 按钮实例详解
Mar 29 Javascript
bootstrap如何让dropdown menu按钮式下拉框长度一致
Apr 10 Javascript
jQuery实现滚动到底部时自动加载更多的方法示例
Feb 18 jQuery
详解微信UnionID作用
May 15 Javascript
Element Tooltip 文字提示的使用示例
Jul 26 Javascript
vue实现图片按比例缩放问题操作
Aug 11 Javascript
vue项目开启Gzip压缩和性能优化操作
Oct 26 Javascript
创建nuxt.js项目流程图解
Mar 13 #Javascript
微信小程序中的上拉、下拉菜单功能
Mar 13 #Javascript
JavaScript实现公告栏上下滚动效果
Mar 13 #Javascript
使用vue实现HTML页面生成图片的方法
Mar 12 #Javascript
JavaScript实现随机点名器
Mar 25 #Javascript
JavaScript碰撞检测原理及其实现代码
Mar 12 #Javascript
JavaScript实现多个物体同时运动
Mar 12 #Javascript
You might like
php对gzip文件或者字符串解压实例参考
2008/07/25 PHP
PHP查询MySQL大量数据的时候内存占用分析
2011/07/22 PHP
基于jquery &amp; json的省市区联动代码
2012/06/26 Javascript
javascript获取设置div的高度和宽度兼容任何浏览器
2013/09/22 Javascript
js中小数转换整数的方法
2014/01/26 Javascript
jQuery操作DOM之获取表单控件的值
2015/01/23 Javascript
JS控制表格实现一条光线流动分割行的方法
2015/03/09 Javascript
jQuery手机拨号界面特效代码分享
2015/08/27 Javascript
jquery判断复选框是否选中进行答题提示特效
2015/12/10 Javascript
基于JavaScript实现div层跟随滚动条滑动
2016/01/12 Javascript
使用JQuery实现智能表单验证功能
2016/03/08 Javascript
js 实现省市区三级联动菜单效果
2017/02/20 Javascript
vue拦截器Vue.http.interceptors.push使用详解
2017/04/22 Javascript
JS点击图片弹出文件选择框并覆盖原图功能的实现代码
2017/08/25 Javascript
vue.js2.0点击获取自己的属性和jquery方法
2018/02/23 jQuery
Vue.js实现可配置的登录表单代码详解
2018/03/29 Javascript
监听angularJs列表数据是否渲染完毕的方法示例
2018/11/07 Javascript
Vue2 添加数据可视化支持的方法步骤
2019/01/02 Javascript
[04:31]2016国际邀请赛中国区预选赛妖精采访
2016/06/27 DOTA
python threading模块操作多线程介绍
2015/04/08 Python
Python实现类似jQuery使用中的链式调用的示例
2016/06/16 Python
python机器学习之决策树分类详解
2017/12/20 Python
Python实现微信消息防撤回功能的实例代码
2019/04/29 Python
jupyter notebook 中输出pyecharts图实例
2020/04/23 Python
对pytorch中x = x.view(x.size(0), -1) 的理解说明
2021/03/03 Python
印度尼西亚最好的小工具在线商店:Erafone.com
2019/03/26 全球购物
老同学聚会感言
2014/02/23 职场文书
班组长岗位职责
2014/03/03 职场文书
学习雷锋倡议书
2014/04/15 职场文书
信息管理专业自荐书
2014/06/05 职场文书
化工专业求职信
2014/07/01 职场文书
2014年高数考试作弊检讨书
2014/12/14 职场文书
Pytest实现setup和teardown的详细使用详解
2021/04/17 Python
pytorch 中autograd.grad()函数的用法说明
2021/05/12 Python
FFmpeg视频处理入门教程(新手必看)
2022/01/22 杂记
javascript中Set、Map、WeakSet、WeakMap区别
2022/12/24 Javascript