【问题标题】:Does requestAnimationFrame bring advantages when adding/removing DOM elements?requestAnimationFrame 在添加/删除 DOM 元素时是否带来优势?
【发布时间】:2021-04-04 09:18:35
【问题描述】:

我有一个函数,它遍历 DOM 节点的直接子元素,并在它们符合要求时将它们附加到另一个新创建的节点。然后该函数将原来的 DOM 节点替换为我创建的那个。

由于将子节点附加到新的 DOM 节点也会将它们从原始 DOM 节点中删除,我想知道是否会在每次删除时触发重排,如果我将函数包装到 requestAnimationFrame() 中是否会带来优势。那么这会触发一次回流吗?

我问这个是因为MDN 只讨论动画而不是添加/删除 DOM 节点。

供参考,这是函数:

function fix_paragraphs(old){
    cleanup_whitespace(old) // library function

    let fixed = create('div') // library function
    copy_attribs(old, fixed) // library function
    let brs = []
    let p = create('p')

    while (old.hasChildNodes()) {
        const child = old.firstChild
        const childtype = child.nodeType

        if (childtype === Node.ELEMENT_NODE && child.tagName === 'BR') {
            brs.push(child)
            old.removeChild(child)
        }

        else if (childtype === Node.ELEMENT_NODE && child.tagName === 'DIV') {
            if (p.hasChildNodes()) {
                fixed.appendChild(p)
            }
            p = create('p')
            fixed.appendChild(child)
            brs = []
        }

        else if ( (brs.length > 1) && (p.hasChildNodes()) ) {
            fixed.appendChild(p)
            p = create('p')
            p.appendChild(child)
            brs = []
        }

        else if (brs.length === 1) {
            p.appendChild(brs[0])
            p.appendChild(child)
            brs = []
        }

        else {
            p.appendChild(child)
            brs = []
        }
    }

    if (p.hasChildNodes()) {
        fixed.appendChild(p)
    }

    replace_with(old, fixed) // library function
}

【问题讨论】:

  • 如果您担心速度,您可能应该检查开发工具中的性能选项卡并寻找“重新计算样式”或“绘制”任务:)
  • 不删除或添加 DOM 节点不会触发重排,它会在下一次重绘时导致重排,但如果您不询问计算值,例如元素的 offsetWidth,或者它的 innerText,那么它就不会“触发”它。

标签: javascript requestanimationframe


【解决方案1】:

我在开发工具中检查了该功能,并通过检查 rasterize paint 条目,通过首先弹出我从中删除节点的父元素(@ 987654321@ 在代码中)。更新后的代码如下:

function fix_paragraphs(old){
    let parent = old.parentNode
    let next = old.nextSibling

    old.remove() // pop it first
    cleanup_whitespace(old)

    let fixed = create('div')
    copy_attribs(old, fixed)

    let brs = []
    let p = create('p')

    while (old.hasChildNodes()) {
        const child = old.firstChild
        const childtype = child.nodeType

        if (childtype === ELEM && child.tagName === 'BR') {
            brs.push(child)
            old.removeChild(child)
        }

        else if (childtype === ELEM && child.tagName === 'DIV') {
            if (p.hasChildNodes()) {
                fixed.appendChild(p)
            }
            fixed.appendChild(child)
            p = create('p')
            brs = []
        }

        else if ( (brs.length > 1) && (p.hasChildNodes()) ) {
            fixed.appendChild(p)
            p = create('p')
            p.appendChild(child)
            brs = []
        }

        else if (brs.length === 1) {
            p.appendChild(brs[0])
            p.appendChild(child)
            brs = []
        }

        else {
            p.appendChild(child)
            brs = []
        }
    }

    if (p.hasChildNodes()) {
        fixed.appendChild(p)
    }

    parent.insertBefore(fixed, next) // now insert it again
}

感谢 dantechguy 和 Kaiido 的提示。

【讨论】:

    猜你喜欢
    • 2011-09-21
    • 2019-10-20
    • 1970-01-01
    • 1970-01-01
    • 2018-03-13
    • 2019-02-21
    • 2017-07-19
    • 2021-12-19
    • 2010-11-02
    相关资源
    最近更新 更多