大致的流程是这样的:实现这个需求是首先通过一个工具(drawio)去自定义绘制图形,然后导出一个svg格式的文件,后端搞了一下drawio工具的源码,在导出的时候,为绘制的图形上每个节点都去绑定了一个id(具体是怎么搞得我一个前端也不是太清楚),最后导出,然后前端需要去加载svg,然后每个节点都会有对应的数据(就是根据绑定的id去获取),然后有些节点上还可能有图片,还需要替换,还可能为每个节点去绑定事件做一些事情。然后还使用了d3实现了让svg可以缩放拖拽。大概是这个亚子

先上一张自己测试用的svg

 如果使用 img标签加载出来的就是上图的效果,仅仅是一张静态图片,这样是无法实现咱们的需求的。
当时看到类似这样的需求的时候,一脸懵,之前也没做过类似的功能,不知道从何下手。。
没办法只能去找一些相关的资源、案例、百度等等,找了好多,最终还是搞出来了。

首先说下思路:

1. 首先咱们要通过XMLHttpRequest的方式去加载svg,因为这样才能去操作svg中的dom元素

2. 接下来就是拿到里面的dom元素集合,遍历为某些节点(当然也可以为整个svg)绑定事件,注意:这里绑定的事件是在window层上,我们要向window上挂载绑定的方法

3. 然后就可以把svg挂载到容器dom上,这里注意:不能通过DOM.appendChild的方式去追加,要先转成虚拟dom并挂载,否则绑定的事件失效

4. 挂载dom上之后就能看到正常的我们加上绑定事件的svg了,这时候也在dom上了,咱们可以去获取里面的dom,循环遍历去获取每个节点的id,并找到里面对应的font标签并将其数据进行修改,除了font标签外、如果有图片还会有image标签

然后下面是完整的代码,代码注释还是蛮详细的,希望可以帮到大家

<template><div><div id="svgTemplate" ref="svg"></div></div>
</template>
<script>
import wftSvg from "@/assets/img/wft.svg";
import Vue from 'vue/dist/vue.esm.js'
import * as d3 from "d3"; //在vue文件里面引入d3
export default {data() {return {svgDom: null,allDom: null};},created() {this.getSvg();},mounted() {//  svg 点击事件window['handleClick'] = function(e,currNodeId) {let tag = e.srcElement || e.target;console.log(e, '点击----->>>')},//  svg 鼠标滚动事件window['havcZooming'] = (e) => {console.log(e, 'havcZooming----->>>')this.zoomimg();}},methods: {getSvg() {const xhr = new XMLHttpRequest();xhr.open("GET", wftSvg, true);xhr.send();xhr.addEventListener("load", () => {const resXML = xhr.responseXML  //  this.stringToXml(xhr.responseXML)this.svgDom = resXML.documentElement.cloneNode(true); // 克隆节点// console.log(this.svgDom, '----->>>')// 为 svg - dom 设置宽高边框样式this.svgDom.style.width = "100%";this.svgDom.style.height = "80vh";this.svgDom.style.border = "1px solid yellow";// 为svg添加鼠标滚动缩放事件this.svgDom.setAttribute("v-on:mousewheel", "this.havcZooming($event)");// svg - alet adomNodeAll = this.svgDom.getElementsByTagName("a");//  循环修改节点样式 添加事件for(let i = 0; i < adomNodeAll.length; i++) {adomNodeAll[i].style.cursor = 'pointer' // 修改节点样式let currNodeId = adomNodeAll[i].getAttribute('id')adomNodeAll[i].setAttribute("v-on:click", "this.handleClick($event, '"+ currNodeId +"')"); // 为每个节点绑定点击事件let currNode = this.svgDom.getElementById(currNodeId)}//  设置 id 属性let gtag = this.svgDom.getElementsByTagName("g");gtag[0].setAttribute("id", "svgcanvas");/* 将svgDom对象转换成vue的虚拟dom */var oSerializer = new XMLSerializer();var sXML = oSerializer.serializeToString(this.svgDom);var Profile = Vue.extend({template: "<div>" + sXML + '</div>'});// 创建实例,并挂载到元素上new Profile().$mount('#svgTemplate');// document.getElementById('svgTemplate').appendChild(this.svgDom)//  svg - glet svgcanvasDom = document.getElementById("svgcanvas");this.allDom = svgcanvasDom.getElementsByTagName("a");for(let i = 0; i < this.allDom.length; i++) {// console.log(this.allDom[i].childNodes,'childNodes');let curraNodeId = this.allDom[i].id // 当前a标签节点的id,我们可以根据id获取对应节点数据并将其渲染对应的font标签上// console.log(curraNodeId, '当前a标签下的节点id----->>>')if(this.allDom[i].childNodes.length) { // 如果a标签下还有子元素//  修改节点数据(a 标签里面有 font 标签 即节点的数据)let fontDom = this.allDom[i].getElementsByTagName("font");if(fontDom.length) {// 可以根据 curraNodeId 获取该节点对应的数据并渲染到font标签上fontDom[0].innerHTML = 'self'}//  修改图片(a 标签中有 image 标签 , 即节点图片)let imageDom = this.allDom[i].getElementsByTagName("image");if(imageDom.length) {imageDom[0].attributes['xlink:href'].value = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAXCAYAAAALHW+jAAADUElEQVQ4jY2VzW8bRRiHn9kZ7/o7thPbbVGT8NUIQSDtja+ey4EiJFSJSnBBoP4LqBd6QhyQuFW5cUKCAwgu7V/AASkUVDWQFiq3gbYhdrCdxPs5M2gXg8ohZN/L7L6jffTO+/72N8JaS564dPEiFW/DdrtdavU6SZygtUUIwWg85NbNdWK7IlQuGtDvDxjbHicebfH8i08z2hmxs9UnSiyjwRa/3d1EVY6TGyiVhw0trhLMtZtIY/B3HmCMRSkH1y3ilhs4eYGN5jKIEmEUE4UxxgoMkrRlQRggC3VmWyv5gZX6C0wmitFoTBgESOkgpYu2DqPRgCSpUy6fRImvX89HXIJ31gRxWp3WIARCOBgjiKMYbRwQ5f9UuABcBu4A4XS9PM1nYW2EcJzsmFiNMSk8xqJIkj5R9MO/wDPAdeACMA+40/XCNH/m7KcPbLniY4WTkkFYtA6JIx/pCOYaksnwS5tOeRH4HKgdcNg0/8UTKy3mmVB0BUkcopSHEG7WyyOdOnNNhxs/Xctk8z5QP6SDtdunupyvHENIRWwsjhXUGm1UsUqr3UFYn+0/dzPgK3lmsuZannvpXSwGaywCSa1ts36qgkK6mrX1rQzYzQPcivZQ7hHAADod0UO7MstZqzLgFnD8MOAskp+/W8VY8zdCuVidQtJnhUkCere+z4BXgPcOAz65s8+3N69grINyXBCSKA4QQKlUJYp8fr93PwN+CLz5P1NOY/eZ69u1XuKQaloVPDy3iDapFjVuweD7Y4JQZTrsAefSjw6CpfvD3szoxsaQPwYBnaNHWXrqBJ12m0QX+KW3zY/rmwi1cOkfYV8FloFVYBOIpuvqNH/1s7fKDWPKPL44y9lXT3P65WVOLc9z8tlFqhWHMCrSfeTcBw/b153pn3FgtJsl5lplZuoVUq8pepLZRoV2q8R2E2q1x1D2ta8Om0cWH3/0DRveJ5lLR1FMQTqZF6bvUMAk9wj8a/kNtqJuQ6GAUi46FbbVGSzFeZ6H60Iw+TW/H+6Ot3GjPjMztQzq+wGJtpkGq9UyjmPZ2x/nrzC7lKymWCpQb1TRsZ8WjCckUgqSJEJYm7/CzrE3CPdb7N0fM7w7IByE6DHEg4igP8STS8wvvM1fZW5twKdzQs0AAAAASUVORK5CYII='}//  设置支路的移动动画 (有 getTotalLength 即为线节点)if(this.allDom[i].childNodes[0].getTotalLength) {// 使不同长度线路动画速度一致let length = this.allDom[i].childNodes[0].getTotalLength()let duration = length / 50let animationString = duration.toFixed(0) + "s " + "linear infinite hacvRun";// console.log(length, "length");this.allDom[i].childNodes[0].style.strokeDashoffset = length;this.allDom[i].childNodes[0].style.animation = animationString;}}}});},zoomimg(x, y) {// 放大缩小// 缩放事件绑定给svg,缩放结果设置给svg内部的g标签if (!x) {x = 0;}if (!y) {y = 0;}const svg = d3.select("svg");const g = d3.select("#svgcanvas");// console.log(svg, g, "in havcZooming");//节点的缩放function zoomActions() {// console.log(d3.event, '----->>>') // undefind// g.attr("transform", d3.event.transform);g.attr("transform", d3.zoomTransform(svg.node()));}let zoomHandler = d3.zoom().on("zoom", zoomActions).scaleExtent([0.5, 40]);// zoomHandler(svg)svg.call(zoomHandler);svg.transition().duration(750).call(zoomHandler.transform, d3.zoomIdentity.translate(-x, -y).scale(2));// // 点击按钮定位// d3.select("#reset").on("click", function () {//   svg//     .transition()//     .duration(750)//     .call(zoomHandler.transform, d3.zoomIdentity);// });// d3.select('#pos1').on('click',function(){//   svg.transition().duration(750).call(zoomHandler.transform, d3.zoomIdentity.translate(-10,-1500).scale(2));// });// d3.select('#pos2').on('click',function(){//   svg.transition().duration(750).call(zoomHandler.transform, d3.zoomIdentity.translate(-1200,-10).scale(2));// });},stringToXml(xmlString) {let xmlDoc = nullif (typeof xmlString == "string") {//FFif (document.implementation.createDocument) {var parser = new DOMParser();xmlDoc = parser.parseFromString(xmlString, "text/xml");} else if (window.ActiveXObject) {xmlDoc = new ActiveXObject("Microsoft.XMLDOM");xmlDoc.async = false;xmlDoc.loadXML(xmlString);}}else {xmlDoc = xmlString;}return xmlDoc;}}
};
</script>
<style>
@keyframes dash {to {stroke-dashoffset: 0;}
}@keyframes run {from {stroke-dasharray: 10, 5;}to {stroke-dasharray: 40, 5;}
}@keyframes hacvRun {from {stroke-width: 6;/* stroke-dashoffset: 0; */stroke-dasharray: 10, 8;}to {stroke-width: 6;stroke-dashoffset: 0;stroke-dasharray: 10, 8;}
}
</style>

最后是搞完之后的效果:

补充: 

上面代码通过

var Profile = Vue.extend({template: "<div>" + sXML + '</div>'
});
// 创建实例,并挂载到元素上
new Profile().$mount('#svgTemplate');

这个方式去挂载,如果使用错误警告或者有问题可以看下我上篇博文:

【解决】You are using the runtime-only build of Vue where the template compiler is not available

上面使用了d3,记得npm 装一下呢

npm install d3

Vue中动态加载SVG文件并绑定事件、修改节点数据相关推荐

  1. vue动态加载SVG文件并修改节点数据

    先上一个马赛克图片叭. 接领导需求,动态实现电路图, 并附带放大.缩小功能. 以及不同的回路点击能弹窗显示相关节点的更多信息, 通俗一点讲: 随着用户点击放大和缩小, 点击位置保持不变,而且能实现点击 ...

  2. Vue中怎么加载pdf文件

    Vue预览pdf文件,我觉得pdfh5方式比较简洁,还有vue-pdf也可以,但是如果文件内容较多的话,vue-pdf就需要做分页处理,就麻烦了:接下来,想分享下我使用pdfh5的代码逻辑.如下:(注 ...

  3. bpl文件java,在LoadLibrary中动态加载BPL失败

    我想在Delphi 10 Seattle(Update 1)或Delphi 10.1 Berlin项目(Enterprise版本)中动态加载BPL模块 . 但LoadPackage函数失败并显示消息( ...

  4. JavaScript动态加载js文件

    /********************************************************************** JavaScript动态加载js文件* 说明:* 之前没 ...

  5. linux 下创建并动态加载.so 文件

    最简单的生成, 动态加载.so 文件的例子 //test.cpp #ifndef _TEST_H    #define _TEST_H       #include <iostream> ...

  6. 在.Net framework中动态加载Assembly的loadFromRemoteSources配置

    简介 在插件类型的应用开发中,我们可能会在程序中动态加载一个assembly文件,创建其中的类对象并使用. 这时,就涉及到了CAS(code access security)和信任沙盒. 一般,我们的 ...

  7. php动态页面加载慢,通过动态加载JS文件提升网站访问速度

    相对与HTML,CSS,javascript是最影响浏览器性能的,因为浏览器在遇到<script>标签时,必须等待js代码下载和执行完毕后再执行后面的内容,因此当页面中js文件过多时,网站 ...

  8. 在VC中动态加载ODBC的方法

    在VC中动态加载ODBC的方法     在使用VC.VB.Delphi等高级语言编写数据库应用程序时,往往需要用户自己在控制面板中配置ODBC数据源.对于一般用户而言,配置ODBC数据源可能是一件比较 ...

  9. 动态加载JavaScript文件

    目录 配置 无脑方法! 逆袭之道! 一块蛋糕! 结论 源代码 JavaScript文件的动态加载是您必须拥有的非常有用的工具之一.它允许您通过将阻止脚本从加载过程中移出(通常称为"延迟加载& ...

最新文章

  1. python保存到固定文件夹的存储路径不能直接复制!
  2. SAP的Cloud Platform增加了多云支持和商业语义
  3. 【问链-Eos公开课】第二课 EOS环境搭建(Ubuntu系统下)
  4. 数据库相关中间件介绍
  5. 解决 PowerDesigner 错误 The generation has been cancelled…
  6. mysql pydev_pydev-python 链接mysql数据库(mac系统)
  7. 前端_网页编程 跨域与JSONP- 淘宝搜索案例
  8. IntelliJ IDEA 2017 MySQL5 绿色版 Spring 4 Mybatis 3 配置步骤详解(二)
  9. python从入门到放弃pdf下载-Python从入门到放弃(一): Python下载及打开世界之窗...
  10. mongoDB VS PostgreSQL dml performance use python (pymongo py-postgresql)
  11. 小米发布会之文案错误:大哥你先处罚自己!再处罚相关高管!
  12. [持续更新] Spring Boot -Maven 指令打包相关记录
  13. 计算机一级幻灯片样式,PPT怎么设置单个幻灯片为背景样式4?网友:原来这么简单!...
  14. 智慧水务ZWS云平台方案,共促水务行业数字化建设
  15. java突然无法加载主类_Java 找不到或无法加载主类的修复方法
  16. 基于stm32f103的俄罗斯方块游戏
  17. 33. Prometheus-报警-通知模板示例
  18. 折腾:如何让你的老电脑快起来
  19. 基于STM32单片机的篮球计时记分器proteus仿真原理图PCB
  20. UltraISO 制作U盘启动盘

热门文章

  1. 移动硬盘删除文件时提示“文件或目录损坏且无法读取”的解决方法-chkdsk 命令的巧用
  2. 阿里云,华为云,腾讯云三大公有云厂商,香港地区主机测评
  3. 教你九招提高睡眠质量
  4. 【Java】IO流 (超详细!!)
  5. 多媒体计算机技术在教学中的应用,浅谈多媒体计算机技术在教学中的应用
  6. 6.4应用实例:六度空间
  7. SolidWorks装配体中让弹簧随装配体运动的方法
  8. 前端学习2——CSS3
  9. 。INF文件格式说明
  10. 呼叫中心是企业实现全渠道客户服务的刚需