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 相关文章推荐
node.js中的path.extname方法使用说明
Dec 09 Javascript
Jquery实现仿京东商城省市联动菜单
Nov 19 Javascript
JavaScript实现下拉菜单的显示和隐藏
Jan 05 Javascript
去除html代码里面的script正则方法
May 19 Javascript
Javascript删除指定元素节点的方法
Jun 21 Javascript
详解XMLHttpRequest(二)响应属性、二进制数据、监测上传下载进度
Sep 14 Javascript
微信小程序 教程之wxapp视图容器 swiper
Oct 19 Javascript
JavaScript 中 apply 、call 的详解
Mar 21 Javascript
初识 Vue.js 中的 *.Vue文件
Nov 22 Javascript
微信小程序--获取用户地理位置名称(无须用户授权)的方法
Apr 29 Javascript
Vue.js实现大屏数字滚动翻转效果
Nov 29 Javascript
Vue + element 实现多选框组并保存已选id集合的示例代码
Jun 03 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的面向对象编程
2006/10/09 PHP
yii框架配置默认controller和action示例
2014/04/30 PHP
PHP对象的浅复制与深复制的实例详解
2017/10/26 PHP
PHP通过get方法获得form表单数据方法总结
2018/09/12 PHP
PHP7 错误处理机制修改
2021/03/09 PHP
javascript 嵌套的函数(作用域链)
2010/03/15 Javascript
改变文件域的样式实现思路同时兼容ie、firefox
2013/10/23 Javascript
jQuery表格列宽可拖拽改变且兼容firfox
2014/09/03 Javascript
JavaScript字符串对象substr方法入门实例(用于截取字符串)
2014/10/16 Javascript
理解jquery事件冒泡
2016/01/03 Javascript
JS动态创建元素的两种方法
2016/04/20 Javascript
jQuery插件扩展测试实例
2016/06/21 Javascript
ES6中Proxy与Reflect实现重载(overload)的方法
2017/03/30 Javascript
Vue.js实现文章评论和回复评论功能
2020/05/30 Javascript
jQuery动态追加页面数据以及事件委托详解
2017/05/06 jQuery
[30:00]完美世界DOTA2联赛PWL S2 Rebirth vs LBZS 第二场 11.28
2020/12/01 DOTA
Python学生信息管理系统修改版
2018/03/13 Python
python爬虫简单的添加代理进行访问的实现代码
2019/04/04 Python
Python Pandas中根据列的值选取多行数据
2019/07/08 Python
django数据库自动重连的方法实例
2019/07/21 Python
python 使用raw socket进行TCP SYN扫描实例
2020/05/05 Python
python redis存入字典序列化存储教程
2020/07/16 Python
Python中logger日志模块详解
2020/08/04 Python
python代数式括号有效性检验示例代码
2020/10/04 Python
你应该知道的30个css选择器
2014/03/19 HTML / CSS
前端H5 Video常见使用场景简介
2020/08/21 HTML / CSS
玩具反斗城美国官网:Toys"R"Us
2016/09/17 全球购物
固特异美国在线轮胎店:Goodyear Tire
2019/02/23 全球购物
在线实验室测试:HealthLabs.com
2020/05/03 全球购物
质检员岗位职责
2013/12/17 职场文书
文秘档案管理岗位职责
2014/03/06 职场文书
开学寄语大全
2014/04/08 职场文书
防邪知识进家庭活动方案
2014/08/26 职场文书
大学本科生职业生涯规划书范文
2014/09/14 职场文书
银行工作心得体会范文
2016/01/23 职场文书
Python识别花卉种类鉴定网络热门植物并自动整理分类
2022/04/08 Python