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代码格式化和语法着色V2
Oct 14 Javascript
javascript vvorld 在线加密破解方法
Nov 13 Javascript
javascript cookies 设置、读取、删除实例代码
Apr 12 Javascript
JavaScript NaN和Infinity特殊值 [译]
Sep 20 Javascript
js代码验证手机号码和电话号码是否合法
Jul 30 Javascript
JS操作JSON方法总结(推荐)
Jun 14 Javascript
总结AngularJS开发者最常犯的十个错误
Aug 31 Javascript
js生成随机颜色方法代码分享(三种)
Dec 29 Javascript
JQuery 进入页面默认给已赋值的复选框打钩
Mar 23 jQuery
Vue学习笔记进阶篇之单元素过度
Jul 19 Javascript
vue2.0 下拉框默认标题设置方法
Aug 22 Javascript
解决vant的Toast组件时提示not defined的问题
Nov 11 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
phpmyadmin配置文件现在需要绝密的短密码(blowfish_secret)的2种解决方法
2014/05/07 PHP
Thinkphp搭建包括JS多语言的多语言项目实现方法
2014/11/24 PHP
PHP实现无限极分类图文教程
2014/11/25 PHP
ThinkPHP自动完成中使用函数与回调方法实例
2014/11/29 PHP
详解WordPress开发中wp_title()函数的用法
2016/01/07 PHP
PHP实现微信网页授权开发教程
2016/01/19 PHP
PHP函数shuffle()取数组若干个随机元素的方法分析
2016/04/02 PHP
ecshop适应在PHP7的修改方法解决报错的实现
2016/11/01 PHP
Javascript的匿名函数小结
2009/12/31 Javascript
统计jQuery中各字符串出现次数的工具
2012/05/03 Javascript
jQuery实现加入购物车飞入动画效果
2015/03/14 Javascript
JQuery插件Marquee.js实现无缝滚动效果
2016/04/26 Javascript
Ajax异步获取html数据中包含js方法无效的解决方法
2017/02/20 Javascript
jQuery 实现双击编辑表格功能
2017/06/19 jQuery
Webpack打包字体font-awesome的方法示例
2018/04/26 Javascript
微信小程序wepy框架笔记小结
2018/08/08 Javascript
详解Vue.js在页面加载时执行某个方法
2018/11/20 Javascript
Vue 2.0双向绑定原理的实现方法
2019/10/23 Javascript
vue框架中props的typescript用法详解
2020/02/17 Javascript
JavaScript实现alert弹框效果
2020/11/19 Javascript
Python中的字典与成员运算符初步探究
2015/10/13 Python
python3使用scrapy生成csv文件代码示例
2017/12/28 Python
python+opencv轮廓检测代码解析
2018/01/05 Python
python 实时得到cpu和内存的使用情况方法
2018/06/11 Python
flask框架单元测试原理与用法实例分析
2019/07/23 Python
深入了解Python在HDA中的应用
2019/09/05 Python
python面向对象之类属性和类方法案例分析
2019/12/30 Python
python 轮询执行某函数的2种方式
2020/05/03 Python
详解python 条件语句和while循环的实例代码
2020/12/28 Python
使用css3 属性如何丰富图片样式(圆角 阴影 渐变)
2012/11/22 HTML / CSS
使用SVG实现提示框功能的示例代码
2020/06/05 HTML / CSS
入团者的自我评价分享
2013/12/02 职场文书
甲乙双方合作协议书
2014/10/13 职场文书
贫困证明书格式及范文
2014/10/15 职场文书
部队2015年终工作总结
2015/04/02 职场文书
2016入党积极分子党课培训心得体会
2016/01/06 职场文书