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 相关文章推荐
在IE 浏览器中使用 jquery的fadeIn() 效果 英文字符字体加粗
Jun 02 Javascript
JS基础之undefined与null的区别分析
Aug 08 Javascript
js中widow.open()方法使用详解
Jul 30 Javascript
JS中Date日期函数中的参数使用介绍
Jan 02 Javascript
js实现的二级横向菜单条实例
Aug 22 Javascript
JS判断输入的字符串是否是数字的方法(正则表达式)
Nov 29 Javascript
移动端脚本框架Hammer.js
Dec 15 Javascript
jQuery动态生成表格及右键菜单功能示例
Jan 13 Javascript
重新认识vue之事件阻止冒泡的实现
Aug 02 Javascript
layui 监听select选择 获取当前select的ID名称方法
Sep 24 Javascript
微信小程序保持session会话的方法
Mar 20 Javascript
uniapp 微信小程序 自定义tabBar 导航
Apr 22 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版本的cron定时任务执行器使用实例
2014/08/19 PHP
PHP中的Session对象如何使用
2015/09/25 PHP
php 实现简单的登录功能示例【基于thinkPHP框架】
2019/12/02 PHP
Javascript操纵Cookie实现购物车程序
2007/02/15 Javascript
[推荐]javascript 面向对象技术基础教程
2009/03/03 Javascript
JQuery自定义事件的应用 JQuery最佳实践
2010/08/01 Javascript
基于jquery的合并table相同单元格的插件(精简版)
2011/04/05 Javascript
浅谈JavaScript 的执行顺序
2015/08/07 Javascript
Windows下使用Nodejs运行js的方法
2017/09/02 NodeJs
JS面向对象的程序设计相关知识小结
2018/05/26 Javascript
Vue源码中要const _toStr = Object.prototype.toString的原因分析
2018/12/09 Javascript
jQuery选择器选中最后一个元素,倒数第二个元素操作示例
2018/12/10 jQuery
JavaScript学习笔记之DOM基础操作实例小结
2019/01/09 Javascript
详解vue实现坐标拾取器功能示例
2020/11/18 Vue.js
通过Python 获取Android设备信息的轻量级框架
2017/12/18 Python
Tensorflow实现卷积神经网络用于人脸关键点识别
2018/03/05 Python
python放大图片和画方格实现算法
2018/03/30 Python
Python3导入自定义模块的三种方法详解
2018/04/13 Python
Python开发网站目录扫描器的实现
2019/02/21 Python
浅谈Pytorch中的torch.gather函数的含义
2019/08/18 Python
django框架两个使用模板实例
2019/12/11 Python
Anaconda配置pytorch-gpu虚拟环境的图文教程
2020/04/16 Python
详解Python流程控制语句
2020/10/28 Python
python 用Matplotlib作图中有多个Y轴
2020/11/28 Python
实习会计求职自荐信范文
2014/03/10 职场文书
入党思想汇报怎么写
2014/04/03 职场文书
班组建设经验交流材料
2014/05/12 职场文书
婚前财产协议书范本
2014/10/19 职场文书
2015年社会实践个人总结
2015/03/06 职场文书
特此通知格式
2015/04/27 职场文书
法院答辩状格式
2015/05/22 职场文书
高中16字霸气押韵班级口号集锦!
2019/06/27 职场文书
python字符串常规操作大全
2021/05/02 Python
nginx服务器的下载安装与使用详解
2021/08/02 Servers
【2·13】一图读懂中国无线电发展
2022/02/18 无线电
基于docker安装zabbix的详细教程
2022/06/05 Servers