如何在Svelte中绑定内存中的SVG DOM元素?
如何在Svelte中绑定内存中的SVG DOM元素
我有一个仅存在于内存中(未挂载到body、页面不可见)的SVG DOM Element对象,希望用Svelte语法管理它(比如添加类名),试了几种方法都没成功,具体情况如下:
尝试过的方法
1. 直接使用bind:this绑定
<script> // 创建内存SVG元素 let mySvg1 = document.createElementNS("http://www.w3.org/2000/svg", "svg"); mySvg1.setAttribute("width", "100"); mySvg1.setAttribute("height", "100"); let circle = document.createElementNS("http://www.w3.org/2000/svg", "circle"); circle.setAttribute("cx", "50"); circle.setAttribute("cy", "50"); circle.setAttribute("r", "40"); circle.setAttribute("fill", "red"); mySvg1.appendChild(circle); </script> <style> #myThing { width: 100px; height: 100px; background-color: blue; } </style> <svg id="myThing" bind:this={mySvg1}></svg>
问题:页面无内容,元素未出现在检查器中;手动执行document.body.appendChild(mySvg1)会生成第二个SVG,且内容与预期不一致。
2. 使用Action
<script> function generateSvg() { let svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); svg.setAttribute("width", "100"); svg.setAttribute("height", "100"); let circle = document.createElementNS("http://www.w3.org/2000/svg", "circle"); circle.setAttribute("cx", "50"); circle.setAttribute("cy", "50"); circle.setAttribute("r", "40"); circle.setAttribute("fill", "red"); svg.appendChild(circle); return svg; } function replaceSvg(svg) { let generatedSvg = generateSvg(); svg.parentNode.replaceChild(generatedSvg, svg); } </script> <svg id="myThing" use:replaceSvg />
问题:替换后无法保留对内存SVG的引用,后续无法用Svelte语法管理它。
3. 使用onMount
<script> import { onMount } from 'svelte'; let mySvg1; // 模拟第三方库返回内存SVG的函数(无法修改) function generateSvg() { let svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); svg.setAttribute("width", "100"); svg.setAttribute("height", "100"); let circle = document.createElementNS("http://www.w3.org/2000/svg", "circle"); circle.setAttribute("cx", "50"); circle.setAttribute("cy", "50"); circle.setAttribute("r", "40"); circle.setAttribute("fill", "red"); svg.appendChild(circle); return svg; } onMount(() => { mySvg1 = generateSvg(); // 不知道接下来该做什么 }); </script> <svg id="myThing" bind:this={mySvg1} />
问题:赋值后SVG未挂载到页面,也无法通过Svelte管理。
正确实现方案
核心思路:让Svelte先渲染一个占位元素,再将内存中的SVG插入/替换到该占位元素中,同时保留对SVG的引用,即可用Svelte语法管理它。
方案1:容器元素 + onMount
<script> import { onMount } from 'svelte'; let svgContainer; // 占位容器的引用 let mySvg; // 内存SVG的引用 // 模拟第三方库函数 function generateSvg() { const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); svg.setAttribute("width", "100"); svg.setAttribute("height", "100"); const circle = document.createElementNS("http://www.w3.org/2000/svg", "circle"); circle.setAttribute("cx", "50"); circle.setAttribute("cy", "50"); circle.setAttribute("r", "40"); circle.setAttribute("fill", "red"); svg.appendChild(circle); return svg; } onMount(() => { mySvg = generateSvg(); // 将内存SVG插入到Svelte渲染的容器中 svgContainer.appendChild(mySvg); // 示例:添加类名 mySvg.classList.add('custom-svg'); }); // 响应式修改示例:点击按钮改变颜色 function changeColor() { if (mySvg) { mySvg.querySelector('circle').setAttribute('fill', 'blue'); } } </script> <style> .custom-svg { border: 2px solid green; } </style> <!-- 占位容器 --> <div bind:this={svgContainer}></div> <button on:click={changeColor}>改变颜色</button>
方案2:Action替换占位SVG
<script> let mySvg; // 保存内存SVG的引用 // 模拟第三方库函数 function generateSvg() { const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); svg.setAttribute("width", "100"); svg.setAttribute("height", "100"); const circle = document.createElementNS("http://www.w3.org/2000/svg", "circle"); circle.setAttribute("cx", "50"); circle.setAttribute("cy", "50"); circle.setAttribute("r", "40"); circle.setAttribute("fill", "red"); svg.appendChild(circle); return svg; } function mountSvg(placeholderSvg) { mySvg = generateSvg(); // 替换占位SVG placeholderSvg.parentNode.replaceChild(mySvg, placeholderSvg); // 初始化添加类名 mySvg.classList.add('custom-svg'); } function addAnotherClass() { if (mySvg) { mySvg.classList.add('extra-style'); } } </script> <style> .custom-svg { box-shadow: 0 0 5px rgba(0,0,0,0.3); } .extra-style { transform: scale(1.1); } </style> <!-- 占位SVG,用action替换 --> <svg use:mountSvg /> <button on:click={addAnotherClass}>添加额外样式</button>
失败原因分析
- bind:this方向错误:
bind:this={mySvg1}是让Svelte将自己渲染的元素赋值给变量,而非将外部内存元素交给Svelte渲染,直接赋值会覆盖绑定逻辑,导致元素丢失。 - Action未保留引用:之前的Action仅替换元素,但未保存新SVG的引用,后续无法管理;且未处理Svelte重新渲染的情况。
- onMount赋值无效:直接给
bind:this变量赋值内存SVG,Svelte不会处理该赋值,因为它只负责获取自身渲染的元素。
内容的提问来源于stack exchange,提问作者shellwhale
相关产品推荐
相关产品推荐

