我有一个 SVG 字符串集合,所有字符串都具有不同的 viewBox 属性。我试图将所有这些 SVG 嵌套在父 SVG 中,以便我可以动态设置它们的 x
和 y
属性。下面是我提出的解决方案的一个最小示例。它最初不会渲染,但是如果在浏览器开发工具中我向 HTML 添加类似空行的内容,这似乎会导致重新渲染,并且圆圈会按预期渲染。所以 HTML 生成的结构是正确的,在我的代码“完成”之前,LitElement/lit-html 渲染似乎存在问题。
我怀疑问题归结为我使用 lit-html 模板的方式,而 LitElement 和 SVG 方面是不相关的。
<my-example></my-example>
import { LitElement, svg } from "https://unpkg.com/lit-element?module";
const circles = {
big: `<svg viewBox="0 0 100 100" width="300px" height="300px">
<circle cx="50" cy="50" r="50"/>
</svg>`,
small: `<svg viewBox="0 0 200 200" width="300px" height="300px">
<circle cx="100" cy="100" r="60"/>
</svg>`
};
class MyExample extends LitElement {
render() {
return svg`
<div class="ingredients">
<svg height="50vh" width="100%" viewBox="0 0 100 100">
${Object.keys(circles).map((circle, i) => {
// create template from svg string
const template = document.createElement("template");
template.innerHTML = circles[circle];
const clone = template.content.cloneNode(true);
const svgNode = clone.querySelector("svg");
const viewBoxAtt = clone
.querySelector("svg")
.getAttribute("viewBox");
// create template from svg's contents (circle element)
const template2 = document.createElement("template");
template2.innerHTML = svgNode.innerHTML;
const clone2 = template2.content.cloneNode(true);
// place circle element in a new svg with dynamically set attributes
return svg`<svg viewBox=${viewBoxAtt} x=${i * 20} y=${i *
20} height="30" width="30">${svg`${clone2}`}</svg>`;
})}
</svg>
</div>
`;
}
}
window.customElements.define("my-example", MyExample);
最佳答案
这实际上取决于你的圆圈来自哪里......假设所有圆圈的宽度和高度都是“300px”,你可以简单地将你的 SVG 包装到另一个 SVG 中,该 SVG 会在循环中分配位置和大小。然后只需使用 unsafeHTML
添加您的 SVG(假设您信任 SVG 字符串的来源)
import { LitElement, svg } from 'https://unpkg.com/lit-element?module'
import { unsafeHTML } from 'https://unpkg.com/lit-html/directives/unsafe-html.js?module'
const circles = {
big: `<svg viewBox="0 0 100 100" width="300px" height="300px">
<circle cx="50" cy="50" r="50"/>
</svg>`,
small: `<svg viewBox="0 0 200 200" width="300px" height="300px">
<circle cx="100" cy="100" r="60"/>
</svg>`
}
class MyExample extends LitElement {
doSomething(evt){
const index = evt.target.getAttribute("data-index")
// do something with circle i
}
render () {
return svg`
<div class="ingredients">
<svg height="50vh" width="100%" viewBox="0 0 100 100">
${Object.values(circles).map((circle, i) => {
return svg`<svg @click="${this.doSomething}" data-index="${i}" viewBox="0 0 300 300" x=${i * 20} y=${i * 20} height="30" width="30">
${unsafeHTML(circle)}
</svg>`
})}
</svg>
</div>
`
}
}
window.customElements.define('my-example', MyExample)
另一种方法是使用 DOMParser
将字符串解析为 DOM,操作该 DOM,然后将结果转回字符串以在渲染函数中渲染它(即如果您的 SVG 没有设置相同的宽度和高度,并且无法删除宽度和高度属性):
import { LitElement, svg } from 'https://unpkg.com/lit-element?module'
import { unsafeHTML } from 'https://unpkg.com/lit-html/directives/unsafe-html.js?module'
const circles = {
big: `<svg viewBox="0 0 100 100" width="300px" height="300px">
<circle cx="50" cy="50" r="50"/>
</svg>`,
small: `<svg viewBox="0 0 200 200" width="300px" height="300px">
<circle cx="100" cy="100" r="60"/>
</svg>`
}
function setPosition (node, x, y, width, height) {
node.setAttribute('x', x)
node.setAttribute('y', y)
node.setAttribute('width', width)
node.setAttribute('height', height)
}
class MyExample extends LitElement {
render () {
const parser = new DOMParser()
return svg`
<div class="ingredients">
<svg height="50vh" width="100%" viewBox="0 0 100 100">
${Object.values(circles).map((circle, i) => {
const doc = parser.parseFromString(circle, 'image/svg+xml')
setPosition(doc.documentElement, i * 20, i * 20, 30, 30)
return unsafeHTML(doc.documentElement.outerHTML)
})}
</svg>
</div>
`
}
}
window.customElements.define('my-example', MyExample)
这实际上取决于数据来自哪里以及您可以执行哪些步骤来准备数据...最优雅的解决方案是将 SVG 字符串转换为模板字符串返回函数。那么渲染函数就变得非常简单:
import { LitElement, svg } from 'https://unpkg.com/lit-element?module'
const circles = {
big: (x, y, w, h) => svg`<svg viewBox="0 0 100 100" x="${x}" y="${y}"" width="${w}" height="${h}">
<circle cx="50" cy="50" r="50"/>
</svg>`,
small: (x, y, w, h) => svg`<svg viewBox="0 0 200 200" x="${x}" y="${y}"" width="${w}" height="${h}">
<circle cx="100" cy="100" r="60"/>
</svg>`
}
class MyExample extends LitElement {
render () {
const parser = new DOMParser()
return svg`
<div class="ingredients">
<svg height="50vh" width="100%" viewBox="0 0 100 100">
${Object.values(circles).map((circle, i) => circle(i * 20, i * 20, 30, 30))}
</svg>
</div>
`
}
}
window.customElements.define('my-example', MyExample)
遵循您在示例中使用的逻辑(创建新的 svg 元素并从 svg 字符串附加圆圈)仅适用于全新的 unsafeSVG()
指令,该指令是未完成的 lit-html 版本 1.2.0...我正在托管该版本的构建,因此您也可以尝试一下:
import { LitElement, svg } from 'https://cdn.klimapartner.net/modules/lit-element/lit-element.js'
import { unsafeSVG } from 'https://cdn.klimapartner.net/modules/lit-html/directives/unsafe-svg.js'
const circles = {
big: `<svg viewBox="0 0 100 100" width="300px" height="300px">
<circle cx="50" cy="50" r="50"/>
</svg>`,
small: `<svg viewBox="0 0 200 200" width="300px" height="300px">
<circle xmlns="http://www.w3.org/2000/svg" cx="100" cy="100" r="60"/>
</svg>`
}
class MyExample extends LitElement {
render () {
const parser = new DOMParser()
return svg`
<div class="ingredients">
<svg height="50vh" width="100%" viewBox="0 0 100 100">
${Object.values(circles).map((circle, i) => {
const doc = parser.parseFromString(circle, 'image/svg+xml')
return svg`<svg viewBox="${doc.documentElement.getAttribute('viewBox')}" x=${i * 20} y=${i * 20} height="30" width="30">
${unsafeSVG(doc.documentElement.innerHTML)}
</svg>`
})}
</svg>
</div>
`
}
}
window.customElements.define('my-example', MyExample)
关于javascript - 使用 SVG 字符串构建嵌套 SVG 的 LitElement 渲染问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60391454/