这是一个示例,其中我使用方法element.appendChild()
,然后继续,就好像该元素已被同步附加一样。
但是,正如日志所示,事实并非如此。至少所有与渲染相关的浏览器计算都尚未完成。
在继续执行之前,如何等待元素完全加载?当然,在这种情况下,睡眠1000毫秒是可行的,但是在一般情况下,这是不可靠的。
const serializedSvg = `<svg style="width:100%;height:100%;">
<line x1="25%" y1="25%" x2="75%" y2="75%" style="stroke: rgb(234, 243, 234);stroke-width: 5;"></line>
</svg>`
const svgDom = new DOMParser().parseFromString(serializedSvg, 'text/html').querySelector('svg')
const container = document.querySelector("#container")
container.appendChild(svgDom)
const lineEl = document.querySelector('line')
console.log("fail:" + lineEl.x1.baseVal.value)
setTimeout(() => {
console.log("success:" + lineEl.x1.baseVal.value)
}, 1000)
<div id="container">
</div>
答案 0 :(得分:0)
为澄清起见,并不是说没有如关于回流和SVG属性的两个链接所解释的那样加载svg。这些值的行为符合规范中的规定。
一种可能的方法是,使用MutationObserver或ResizeObserver:
https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver
在实践中,我建议仅使用建议的setTimeout(0)并与之一起使用,因为基本上所有浏览器都将正常运行(有点像可以按顺序遍历对象属性)。只要您更新布局,就可以触发重排,以确保这些值在运行时正确无误,并确保SVG内容仅在渲染完所有内容并触发布局后才运行。
我猜setTimeout(1000)对您有用,因为其他一些影响代码的布局随后会运行,就像当由于布局更改而隐藏/显示控制台/预览时,这些代码片段的值在此处偏移了几个像素一样隐藏或显示控制台/预览div时。
是什么促使布局/重排:https://gist.github.com/paulirish/5d52fb081b3570c81e3a
SVG属性:https://trac.webkit.org/wiki/SVG%20properties
根据有关SVG属性的文档,这些属性是按延迟计算的,直到需要使用为止,并基于“撕下”快照(x1是SVGAnimatedLength对象)获取。
在下面强制进行流焊,这满足了“直到需要”的要求,以便在访问百分比之前先计算并更新百分比。
const serializedSvg = `<svg style="width:100%;height:100%;"">
<line x1="25%" y1="25%" x2="75%" y2="75%" style="stroke: rgb(234, 243, 234);stroke-width: 5;"></line>
</svg>`
const svgDom = new DOMParser().parseFromString(serializedSvg, 'text/html').querySelector('svg')
const container = document.querySelector("#container")
container.appendChild(svgDom)
const lineEl = svgDom.querySelector('line')
// force layout/reflow
lineEl.getBBox()
console.log("fail:" + lineEl.x1.baseVal.value)
setTimeout(() => {
console.log("success:" + lineEl.x1.baseVal.value)
}, 1000)
<div id="container">
</div>
答案 1 :(得分:-1)
您可以使用Promise.resolve().then()
来获取async
值。 .resolve()
将在完成后将数据传递到.then()
中。您可以执行以下操作:
const lineEl = document.querySelector('line');
Promise.resolve(lineEl).then(res => {
console.log(res.x1.baseVal.value);
});
答案 2 :(得分:-1)
您需要等待要插入文档的加载事件。
const serializedSvg = `<svg style="width:100%;height:100%;">
<line x1="25%" y1="25%" x2="75%" y2="75%" style="stroke: rgb(234, 243, 234);stroke-width: 5;"></line>
</svg>`
const svgDom = new DOMParser().parseFromString(serializedSvg, 'text/html').querySelector('svg')
const container = document.querySelector("#container")
container.appendChild(svgDom)
window.addEventListener("load", function(){
const lineEl = document.querySelector('line')
console.log("success:" + lineEl.x1.baseVal.value)
});
<div id="container">
</div>
答案 3 :(得分:-1)
已经在以下评论之一中提及:事件循环
阅读:https://dev.to/lydiahallie/javascript-visualized-event-loop-3dif
基本上,这取决于浏览器引擎优化写入DOM的内容。
这意味着将某些语句捆绑在一起,并且在将其写入DOM之后,您不能 读取 。
因此,您的代码是等待事件循环完成的有效方法
setTimeout(() => {
console.log("success:" + lineEl.x1.baseVal.value)
}, 1000)
AND 您可以将1000
更改为0
!!!
您还可以使用requestAnimationFrame
,它的作用相同:等待事件循环