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 相关文章推荐
JavaScript脚本性能的优化方法
Feb 02 Javascript
JS控制显示隐藏兼容问题(IE6、IE7、IE8)
Apr 01 Javascript
jQuery下通过replace字符串替换实现大小图片切换
May 22 Javascript
JavaScript生成随机数的4种自定义函数分享
Feb 28 Javascript
JavaScript实现当网页加载完成后执行指定函数的方法
Mar 21 Javascript
jQuery插件slider实现拖动滑块选取价格范围
Apr 30 Javascript
使用jQuery+EasyUI实现CheckBoxTree的级联选中特效
Dec 06 Javascript
javascript实现任务栏消息提示的简单实例
May 31 Javascript
jQuery length 和 size()区别总结
Apr 26 jQuery
vue实现侧边栏导航效果
Oct 21 Javascript
vue+axios 拦截器实现统一token的案例
Sep 11 Javascript
解决iView Table组件宽度只变大不变小的问题
Nov 13 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
晶体管来复再生式二管收音机
2021/03/02 无线电
php通过文件头检测文件类型通用代码类(zip,rar等)
2010/10/19 PHP
PHP开发规范手册之PHP代码规范详解
2011/01/13 PHP
php文件打包 下载之使用PHP自带的ZipArchive压缩文件并下载打包好的文件
2012/06/13 PHP
Yii的CDbCriteria查询条件用法实例
2014/12/04 PHP
PHP实现生成带背景的图形验证码功能
2016/10/03 PHP
PHP随机生成中文段落示例【测试网站内容时使用】
2020/04/26 PHP
仿校内登陆框,精美,给那些很厉害但是没有设计天才的程序员
2008/11/24 Javascript
jquery实现仿Flash的横向滑动菜单效果代码
2015/09/17 Javascript
通过js获取上传的图片信息(临时保存路径,名称,大小)然后通过ajax传递给后端的方法
2015/10/01 Javascript
基于JS实现回到页面顶部的五种写法(从实现到增强)
2016/09/03 Javascript
简单谈谈Vue 模板各类数据绑定
2016/09/25 Javascript
微信小程序网络请求wx.request详解及实例
2017/05/18 Javascript
用JS实现一个简单的打砖块游戏
2019/12/11 Javascript
js实现表格数据搜索
2020/08/09 Javascript
[02:08]什么藏在DOTA2 TI9“小紫本”里?斧王历险记告诉你!
2019/05/17 DOTA
[46:23]完美世界DOTA2联赛PWL S2 FTD vs Magma 第一场 11.20
2020/11/23 DOTA
使用Python对Access读写操作
2017/03/30 Python
python 中的int()函数怎么用
2017/10/17 Python
python 内置模块详解
2019/01/01 Python
Python3获取电脑IP、主机名、Mac地址的方法示例
2019/04/11 Python
python ChainMap 合并字典的实现步骤
2019/06/11 Python
用pytorch的nn.Module构造简单全链接层实例
2020/01/14 Python
解决Python在导入文件时的FileNotFoundError问题
2020/04/10 Python
python numpy库np.percentile用法说明
2020/06/08 Python
详解利用canvas实现环形进度条的方法
2019/06/12 HTML / CSS
Richards网上商店:当代时尚,遍布巴西
2019/11/03 全球购物
俄罗斯天然和有机产品、健康生活网上商店:Fitomarket.ru
2020/10/09 全球购物
领导干部培训感言
2014/01/23 职场文书
国土资源局开展党的群众路线教育实践活动整改措施
2014/09/26 职场文书
2015元旦节寄语
2014/12/08 职场文书
2015年个人实习工作总结
2014/12/12 职场文书
文明单位创建材料
2014/12/24 职场文书
行政助理岗位职责
2015/02/10 职场文书
在HTML5 localStorage中存储对象的示例代码
2021/04/21 Javascript
php实现自动生成验证码的实例讲解
2021/11/17 PHP