【问题标题】:Change element attributes (datasets) in one operation - avoid Reflows在一次操作中更改元素属性(数据集) - 避免回流
【发布时间】:2021-11-22 17:06:57
【问题描述】:

我试图避免CSS Reflows, 通常DocumentFragment 足以满足我的需求。

当我修改/添加/删除datasets时,我有一些案例, 问题是每个dataset 都需要一个导致回流的操作..

element.dataset 是一个只读对象,所以我想知道如何在这个例子中只用一个回流而不是 3 个来做到这一点?

element.dataset.a='1'
delete element.b
element.dataset.c='2'

完全替换元素是实现此目的的唯一方法吗?

【问题讨论】:

  • 在观看了here 关于 CSS 回流的视频后,我不确定他们甚至不知道他们在说什么。根据我的编程逻辑,我很确定 DOM 是循环的,所以任何更具体的内容实际上都会阻止绘制 DOM 树。太多的动画或变换可能是一个问题。 DocumentFragment 仅用于将内容附加到document。我不建议使用它,因为在将事件附加到 DOM 之前,您不能将事件附加到 DocumentFragment 中的节点。

标签: javascript css reflow


【解决方案1】:

更改元素的数据集不会导致同步回流。您可以在同一任务中多次执行此操作。

要测试某些东西是否会导致回流,您可以使用 CSS 过渡。
从已知状态开始,然后设置中间状态,触发应该导致回流的原因,最后恢复原始状态。
如果测试的操作确实触发了重排,那么将发生从中间状态到最终状态的新转换。如果没有发生回流,则不会发生转换。

function testReflow(func) {
  return new Promise( (res, rej) => {
    const elem = document.querySelector(".reflow-tester");
    // set "intermediary" values
    elem.style.opacity = 1;
    elem.style.transition = "none";
    try { func(elem); } catch(err) { rej(err) }
    elem.style.opacity = 0;
    elem.style.transition = "opacity 0.01s";

    // if the tested func does trigger a reflow
    // the transition will start from 1 to 0
    // otherwise it won't happen (from 0 to 0)    
    elem.addEventListener("transitionstart", (evt) => {
      res(true); // let the caller know the result
    }, { once: true });
    // if the transition didn't start in 100ms, it didn't cause a reflow
    setTimeout(() => res(false), 100);
  });
}

(async () => {
  // wait 1s before executing the tests to be sure we're not in weird first paint
  await new Promise((res) => setTimeout(res, 1000));
  // first testing with a well known reflow trigger
  const offsetWidth = await
  testReflow((elem)=>elem.offsetWidth);
  console.log("offsetWidth getter:", offsetWidth);
  // now with dataset
  const dataset = await testReflow((elem) => {
    elem.dataset.foo = "bar";
    elem.dataset.bar = "baz";
    elem.dataset.baz = "bla";
  });
  console.log("dataset:", dataset);
})().catch(console.error);
.reflow-tester {
  opacity: 0;
}
<div class="reflow-tester">Tester</div>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多