【发布时间】:2019-06-07 22:50:28
【问题描述】:
我有一个使用 attributeChangedCallback 的 Web 组件
attributeChangedCallback(name, oldValue, newValue) {
// TODO: use something like rxjs debounce time?
this.expensiveRenderer()
}
我正在为每个动画帧上的两个属性设置新值: 此外,这可以增加到设置 4 个属性。
component.setAttribute("att1", r);
component.setAttribute("att2", p);
这将触发attributeChangedCallback 两次,昂贵的渲染器也会触发两次。
有没有一种有效的方法可以将两个属性设置在一起,或者将更改的效果作为一个类似于去抖动时间的单个事件?
我对使用 setTimeout / clearTimeout 有点怀疑,因为它在每个动画帧 60 fps 上调用。
为了提供更好的概览,我的组件看起来有点像:
<mm-spirograph
fixed-circle-radius="100"
moving-circle-radius="10"
moving-circle-locus-length="30"
repeat-count="100"
></mm-spirograph>
它使用 webGL 渲染螺旋图,并计划用于生成艺术。 我喜欢它的简单性,有点不愿意使用 JSON 属性。
另外,spirograph 的动画与组件保持分离,想法是使用 spirograph 作为静态渲染或更改属性可以轻松地做动画。此处仅对两个属性进行动画处理,但在不同情况下会有所不同。
此外,还计划添加类似的组件,如果需要,可以通过设置属性来设置动画。
function animateSpirograph(spirograph, r, p, rIncrement, pIncrement) {
let v = r;
if (v + rIncrement > 100) rIncrement = -Math.abs(rIncrement);
if (v + rIncrement <= 0) rIncrement = Math.abs(rIncrement);
v = v + rIncrement;
r = v;
let w = p;
if (w + pIncrement > 200) pIncrement = -Math.abs(pIncrement);
if (w + pIncrement <= 0) pIncrement = Math.abs(pIncrement);
w = w + pIncrement;
p = w;
spirograph.setAttribute("moving-circle-radius", r);
spirograph.setAttribute("moving-circle-locus-length", p);
window.requestAnimationFrame(() =>
animateSpirograph(spirograph, r, p, rIncrement, pIncrement)
);
}
Danny 的建议很有趣,我可以有第三个属性,它可能是来自 requestAnimationFrame 的时间戳,并将其标记为仅用于动画的可选属性。因此,每次更改属性时,我们都需要设置这个额外的属性来实际触发渲染。但这听起来有点 hacky/patch。
【问题讨论】:
-
你需要观察
observedAttributes中的所有属性吗?它们是什么类型的属性?它们是原生 HTML 元素属性吗?否则,您可以简单地在一个数据属性中使用带有多个键值对的 JSON 字符串。 -
或者添加第三个观察到的属性来设置其他两个
-
或者只有在第二个属性发生变化时才触发渲染器
标签: javascript html web-component native-web-component