Vue.js - 加载展示SVG图形,并动态给元素添加鼠标事件(附样例)
svg 是一种 XML 标记语言,它可以嵌入到网页中显示。Vue 页面中如果需要显示 svg 图形,只需要将其加载后把内容放到页面中即可。同时 svg 还支持事件处理器,不仅支持动画和鼠标触发事件,而且也支持 JavaScript 脚本响应事件。事件既可以写死在 svg 文件中,也可以动态添加。

下面通过样例演示如何加载显示 SVG 图形,并为图形上的元素自动添加鼠标事件。
1,效果图
(1)点击“加载”按钮会将 svg 图形显示在页面上。
(2)同时会自动为图形里的元素添加绑定鼠标移动、鼠标点击事件:
- 鼠标移动到某个元素上,会有个标签显示该元素的 id,并且标签跟随鼠标移动。
- 鼠标点击某个元素,会弹出对话框显示该元素的 id。

2,样例代码
给元素添加鼠标事件注意事项:可以通过 setAttribute 方法为元素添加事件。但由于 svg 上添加的鼠标事件无法直接调用 vue 里的 methods 方法,需要将这些方法绑定到 window 下面,提供给外部调用。
<template> <div id="home"> <section id="top-section"> <label for="">svg路径:</label> <el-input v-model="svgPath" size="small"></el-input> <el-button type="primary" size="small" @click='loadSvgData()'>加载</el-button> </section> <article> <!-- svg图形显示容器 --> <section id="svg-container"> </section> <!-- svg元件鼠标悬浮提示框 --> <div id="svgTipBox" v-show="svgTipBoxVisible && !svgControlBoxVisible" v-bind:style="{ left: svgTipBoxPositionX + 'px', top: svgTipBoxPositionY + 'px' }"> {{svgTipBoxData}} </div> </article> </div> </template> <script> import axios from 'axios' export default { name: 'Home', data () { return { svgPath: '/static/2d.svg', //svg文件路径 svgData:'', //svg文件内容 svgTipBoxData:'', //svg元件鼠标悬浮提示框内容 svgTipBoxVisible:false, //svg元件鼠标悬浮提示框显示状态 svgTipBoxPositionX:0, //svg元件鼠标悬浮提示框x坐标 svgTipBoxPositionY:0, //svg元件鼠标悬浮提示框y坐标 } }, // 由于svg上添加的鼠标事件无法直接调用vue里的methods方法,需要将这些方法绑定到window下面,提供给外部调用 async mounted() { // 将svgClick方法绑定到window下面,提供给外部调用 window["handleClick"] = (evt, id) => { this.svgClick(evt, id); }; // 将svgMouseOver方法绑定到window下面,提供给外部调用 window["handleMouseOver"] = (evt, id) => { this.svgMouseOver(evt, id); }; // 将svgMouseMove方法绑定到window下面,提供给外部调用ping 20. window["handleMouseMove"] = (evt, id) => { this.svgMouseMove(evt, id); }; // 将svgMouseOut方法绑定到window下面,提供给外部调用 window["handleMouseOut"] = (evt, id) => { this.svgMouseOut(evt, id); }; }, created() { }, methods:{ //加载按钮点击 loadSvgData() { // ajax请求数据,并携带参数 axios.get(this.svgPath) .then(response => { console.log(response.data) // 将svg平面图显示在制定容器中 var svgContainer = document.getElementById('svg-container'); svgContainer.innerHTML = response.data; // 遍历svg里面的元素,自动添加鼠标事件 this.addMouseEvent(svgContainer); }, err => { console.log(err) }) .catch((error) => { console.log(error) }) }, // 遍历svg里面的元素,自动添加鼠标事件 addMouseEvent(parent) { for (var i = 0; i < parent.childNodes.length; i++) { //循坏svg里面的元素 var child = parent.childNodes[i]; // 判断是不是g元素,并且具有id值,是的话,就添加鼠标事件 if (child.tagName == 'g' && child.id != null && child.id.length > 0 && child.id.indexOf("PD_")==0) { console.log(child.tagName + ":" + child.id); child.setAttribute("onclick", "handleClick(evt,'"+child.id+"')"); child.setAttribute("onmouseover", "handleMouseOver(evt,'"+child.id+"')"); child.setAttribute("onmousemove", "handleMouseMove(evt,'"+child.id+"')"); child.setAttribute("onmouseout", "handleMouseOut(evt,'"+child.id+"')"); } //继续递归遍历子元素 this.addMouseEvent(child); } }, // svg图元件点击事件 svgClick(evt, id) { console.log(evt); alert(id); }, // svg图元件鼠标移入事件 svgMouseOver(evt, id) { console.log("svgMouseOver"); console.log(evt); this.svgTipBoxData = id; this.svgTipBoxVisible = true; }, // svg图元件鼠标移动事件 svgMouseMove(evt, id) { console.log("svgMouseMove"); console.log(evt); this.svgTipBoxPositionX = evt.pageX; this.svgTipBoxPositionY = evt.pageY - 50; }, // svg图元件鼠标移出事件 svgMouseOut(evt, id) { console.log("svgMouseOut"); console.log(evt); this.svgTipBoxVisible = false; }, } } </script> <style scoped> #home { padding: 22px 34px 22px 34px; } #top-section { width: 100%; margin-bottom: 20px; } #top-section label { font-size: 14px; line-height: 32px; } #top-section .el-input { margin-right: 20px; width: 200px; } #svgTipBox { position: absolute; padding: 10px; background: rgba(0, 0, 0, .8); color: #ffffff; } #svgControlBox { position: absolute; } </style>
附:svg 样例文件(2d.svg)
<svg width="550" height="400" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
<defs>
<style type="text/css">
<![CDATA[symbol{overflow:visible}
.lkv1000 {fill:none;stroke:rgb(0,0,255)}
.kv1000 {fill:rgb(0,0,255);stroke:rgb(0,0,255);stroke-width:1}
.lkv750 {fill:none;stroke:rgb(250,128,10)}
.kv750 {fill:rgb(250,128,10);stroke:rgb(250,128,10);stroke-width:1}
.lkv500 {fill:none;stroke:rgb(255,0,0)}
.kv500 {fill:rgb(255,0,0);stroke:rgb(255,0,0);stroke-width:1}
.lkv330 {fill:none;stroke:rgb(30,144,255)}
.kv330 {fill:rgb(30,144,255);stroke:rgb(30,144,255);stroke-width:1}
.lkv220 {fill:none;stroke:rgb(128,0,128)}
.kv220 {fill:rgb(128,0,128);stroke:rgb(128,0,128);stroke-width:1}
.lkv110 {fill:none;stroke:rgb(240,65,85)}
.kv110 {fill:rgb(240,65,85);stroke:rgb(240,65,85);stroke-width:1}
.lkv66 {fill:none;stroke:rgb(255,204,0)}
.kv66 {fill:rgb(255,204,0);stroke:rgb(255,204,0);stroke-width:1}
.lkv35 {fill:none;stroke:rgb(255,255,0)}
.kv35 {fill:rgb(255,255,0);stroke:rgb(255,255,0);stroke-width:1}
.lkv20 {fill:none;stroke:rgb(226,172,6)}
.kv20 {fill:rgb(226,172,6);stroke:rgb(226,172,6);stroke-width:1}
.lkv15.75 {fill:none;stroke:rgb(0,128,0)}
.kv15.75 {fill:rgb(0,128,0);stroke:rgb(0,128,0);stroke-width:1}
.lkv13.8 {fill:none;stroke:rgb(0,210,0)}
.kv13.8 {fill:rgb(0,210,0);stroke:rgb(0,210,0);stroke-width:1}
.lkv10 {fill:none;stroke:rgb(185,72,66)}
.kv10 {fill:rgb(185,72,66);stroke:rgb(185,72,66);stroke-width:1}
.lkv6 {fill:none;stroke:rgb(0,0,139)}
.kv6 {fill:rgb(0,0,139);stroke:rgb(0,0,139);stroke-width:1}
.lkv3 {fill:none;stroke:rgb(0,100,0)}
.kv3 {fill:rgb(0,100,0);stroke:rgb(0,100,0);stroke-width:1}
.lv380 {fill:none;stroke:rgb(0,204,255)}
.v380 {fill:rgb(0,204,255);stroke:rgb(0,204,255);stroke-width:1}
.lv220 {fill:none;stroke:rgb(176,164,227)}
.v220 {fill:rgb(176,164,227);stroke:rgb(176,164,227);stroke-width:1}
.lv110 {fill:none;stroke:rgb(192,192,192)}
.v110 {fill:rgb(192,192,192);stroke:rgb(192,192,192);stroke-width:1}
.lvdc {fill:none;stroke:rgb(98,49,49)}
.vdc {fill:rgb(98,49,49);stroke:rgb(98,49,49);stroke-width:1}
]]>
</style>
<symbol id="Other_PMS25_0_0" viewBox="0 0 12.000000 11.938000">
<line x1="4.5" y1="-5.25" x2="3.75" y2="-5.25" fill="none" stroke="rgb(11,179,174)" stroke-width="0.1" id="svg_7"/>
<rect x="-6" y="-5.25" width="12" height="11.188" fill="rgb(138,219,253)" stroke="rgb(138,219,253)" id="svg_8"/>
<rect x="4" y="-6" width="1" height="0.75" fill="rgb(138,219,253)" stroke="rgb(138,219,253)" id="svg_9"/>
<rect x="-3.25" y="-6" width="6.5" height="0.75" fill="rgb(138,219,253)" stroke="rgb(138,219,253)" id="svg_10"/>
<rect x="-5" y="-6" width="1" height="0.75" fill="rgb(138,219,253)" stroke="rgb(138,219,253)" id="svg_11"/>
</symbol>
<symbol id="Sensor_PMS25_0_0" viewBox="0 0 12.400000 12.400000">
<circle cx="0" cy="0" r="6" fill="rgb(0,0,128)" stroke="rgb(0,0,128)" stroke-width="0.4" id="svg_12"/>
<circle cx="0" cy="0" r="4.875" fill="rgb(255,255,255)" stroke="rgb(0,0,128)" stroke-width="0.4" id="svg_13"/>
<rect x="-3.5" y="-2" width="7" height="4.5" fill="none" stroke="rgb(0,0,128)" stroke-width="0.4" id="svg_14"/>
<line x1="-2.75" y1="-2.75" x2="-0.75" y2="-2.75" fill="none" stroke="rgb(0,0,128)" stroke-width="0.4" id="svg_15"/>
<line x1="0.75" y1="-2.75" x2="2.75" y2="-2.75" fill="none" stroke="rgb(0,0,128)" stroke-width="0.4" id="svg_16"/>
<line x1="-2.5" y1="0.25" x2="-1" y2="0.25" fill="none" stroke="rgb(0,0,128)" stroke-width="0.4" id="svg_17"/>
<line x1="1" y1="0.25" x2="2.5" y2="0.25" fill="none" stroke="rgb(0,0,128)" stroke-width="0.4" id="svg_18"/>
<line x1="1.75" y1="-0.5" x2="1.75" y2="1" fill="none" stroke="rgb(0,0,128)" stroke-width="0.4" id="svg_19"/>
</symbol>
<symbol id="Sensor_PMS25_211_2110" viewBox="0 0 12.400000 12.400000">
<circle cx="0" cy="0" r="6" fill="rgb(0,0,128)" stroke="rgb(0,0,128)" stroke-width="0.4" id="svg_20"/>
<circle cx="0" cy="0" r="5" fill="rgb(255,255,255)" stroke="rgb(0,0,128)" stroke-width="0.4" id="svg_21"/>
<rect x="-2.5" y="-2" width="5" height="3.5" fill="rgb(0,0,128)" stroke="rgb(0,0,128)" id="svg_22"/>
<circle cx="0" cy="-3" r="0.5" fill="rgb(0,0,128)" stroke="rgb(0,0,128)" id="svg_23"/>
<line x1="0" y1="-2" x2="0" y2="-2.5" fill="none" stroke="rgb(0,0,128)" stroke-width="0.2" id="svg_24"/>
<circle cx="-1" cy="-0.5" r="0.5" fill="rgb(255,255,255)" stroke="rgb(0,204,255)" stroke-width="0.05" id="svg_25"/>
<circle cx="1" cy="-0.5" r="0.5" fill="rgb(255,255,255)" stroke="rgb(0,204,255)" stroke-width="0.05" id="svg_26"/>
<rect x="-1" y="1.5" width="2" height="0.25" fill="rgb(0,0,128)" stroke="rgb(0,0,128)" id="svg_27"/>
<rect x="-1.75" y="1.75" width="3.5" height="1.25" fill="rgb(0,0,128)" stroke="rgb(0,0,128)" id="svg_28"/>
</symbol>
</defs>
<g class="layer">
<title>Layer 1</title>
<g id="Other_Layer">
<g id="PD_0302_4e97f511-ccc9-4aad-adb3-2d121c712971">
<use x="505.928423" y="405.459429" width="12" height="11.9375" xlink:href="#Other_PMS25_0_0"
transform="matrix(5.7540640830993635,0,0,5.7540640830993635,-2828.310858687968,-2242.3475525183167) "
class="lkv10" id="svg_34"/>
<metadata transform="translate(-127,-172) translate(0,24) translate(-6,-48) "/>
</g>
<g id="PD_0302_1721693f-4d9e-4ce3-a9a9-3daa1c1ff653">
<use x="586.485323" y="405.459429" width="12" height="11.9375" xlink:href="#Other_PMS25_0_0"
transform="matrix(5.7540640830993635,0,0,5.7540640830993635,-3211.2837413636444,-2242.3475525183167) "
class="lkv10" id="svg_35"/>
<metadata transform="translate(-127,-172) translate(0,24) translate(-6,-48) "/>
</g>
<g id="PD_0302_7227f068-9002-40f6-9104-24a1480ac2c6">
<use x="667.042223" y="405.459429" width="12" height="11.9375" xlink:href="#Other_PMS25_0_0"
transform="matrix(5.7540640830993635,0,0,5.7540640830993635,-3594.256333874276,-2242.3475525183167) "
class="lkv10" id="svg_36"/>
<metadata transform="translate(-127,-172) translate(0,24) translate(-6,-48) "/>
</g>
</g>
<g id="Sensor_Layer">
<g id="PD_0903003_1ce58c23-6f07-4187-86d3-2679fd279b57">
<use x="389.328792" y="282.903918" width="12.4" height="12.4" xlink:href="#Sensor_PMS25_0_0"
transform="matrix(2.0139224529266357,0,0,2.0139224529266357,-706.1955184044637,-485.4792508401297) "
class="v0" id="svg_38"/>
<metadata transform="translate(-127,-172) translate(9,-4) translate(-3,8) translate(0,24) translate(-6,-48) "/>
</g>
<g id="PD_0903003_0ccce317-9557-421e-8e92-7feeeec4f648">
<use x="469.153752" y="284.289578" width="12.4" height="12.4" xlink:href="#Sensor_PMS25_0_0"
transform="matrix(2.0139224529266357,0,0,2.0139224529266357,-787.1318287014001,-486.8841931306306) "
class="v0" id="svg_39"/>
<metadata transform="translate(-127,-172) translate(9,-4) translate(-3,8) translate(0,24) translate(-6,-48) "/>
</g>
<g id="PD_0903005_d046c637-9c90-423c-8827-3b59fde21b1f">
<use x="496.598656" y="180.179489" width="12.4" height="12.4" xlink:href="#Sensor_PMS25_211_2110"
transform="matrix(2.0139224529266357,0,0,2.0139224529266357,-754.5440367873816,-276.1022221085732) "
class="v0" id="svg_40"/>
<metadata transform="translate(-127,-172) translate(120,209) translate(9,-4) translate(-3,8) translate(0,24) translate(-6,-48) "/>
</g>
</g>
</g>
</svg>