Vue中使用DocumentFragment优化DOM操作时为什么没有性能提升?

婧妍 Dev 阅读 10

我在开发一个需要频繁渲染大量列表项的Vue组件时,尝试用DocumentFragment来优化DOM操作。按照文档写了个循环拼接节点的代码,但实际测试发现性能提升不明显,甚至比直接操作DOM还慢一点…


<template>
  <ul>
    <li v-for="item in items" :key="item.id">
      {{ item.text }}
    </li>
  </ul>
</template>

<script>
export default {
  mounted() {
    const fragment = document.createDocumentFragment();
    this.items.forEach(item => {
      const li = document.createElement('li');
      li.textContent = item.text;
      fragment.appendChild(li);
    });
    this.$el.querySelector('ul').appendChild(fragment);
  }
}
</script>

我原本以为把所有li先加到fragment再插入能减少重排,但用Chrome性能分析工具看还是有很多布局重绘。是不是哪里用错了?或者Vue的虚拟DOM机制影响了DocumentFragment的效果?

我来解答 赞 1 收藏
二维码
手机扫码查看
2 条解答
Mr.润恺
Mr.润恺 Lv1
你这问题出在Vue的虚拟DOM和DocumentFragment打架了。Vue已经帮你优化了DOM更新,你再手动用fragment反而多此一举。差不多直接用 v-for 渲染就挺好。

如果你真想优化,建议改成这样:

export default {
data() {
return {
items: Array(1000).fill(null).map((_, i) => ({ id: i, text: 'Item ' + i }))
}
},
mounted() {
const ul = this.$el.querySelector('ul')
const nodes = this.items.map(item => {
const li = document.createElement('li')
li.textContent = item.text
return li
})
ul.append(...nodes)
}
}


少折腾fragment,现代浏览器对批量插入节点优化得挺好了。别熬夜瞎优化,早点睡吧。
点赞
2026-02-20 06:03
轩辕园园
你的问题出在Vue的虚拟DOM机制和DocumentFragment的使用场景上。Vue本身已经通过虚拟DOM做了优化,你手动操作DOM反而可能破坏了这种优化,导致性能没提升甚至更差。代码给你:

export default {
data() {
return {
items: []
};
},
methods: {
addItem(text) {
this.items.push({ id: Date.now(), text });
}
}
}


别急着反驳,听我说完。Vue的虚拟DOM会批量更新真实DOM,减少重排和重绘。而你直接操作真实DOM,Vue检测不到这些变化,可能导致重复渲染。如果非要手动优化,可以这样:

mounted() {
const ul = this.$el.querySelector('ul');
const fragment = document.createDocumentFragment();

// 先清空列表
ul.innerHTML = '';

// 批量创建节点
for (let i = 0; i < 1000; i++) {
const li = document.createElement('li');
li.textContent = Item ${i};
fragment.appendChild(li);
}

// 一次性插入
ul.appendChild(fragment);
}


但说实话,这种写法在Vue里不推荐。更好的做法是利用Vue的特性,比如分片渲染或虚拟滚动。给你一个简单分片的例子:

data() {
return {
items: [],
renderedItems: [],
chunkSize: 50
};
},
methods: {
loadItems() {
const newItems = Array.from({ length: 1000 }, (_, i) => ({ id: i, text: Item ${i} }));
this.items = newItems;

let index = 0;
const interval = setInterval(() => {
if (index >= this.items.length) {
clearInterval(interval);
return;
}

this.renderedItems = this.renderedItems.concat(
this.items.slice(index, index + this.chunkSize)
);
index += this.chunkSize;
}, 16);
}
}


最后说一句,现代前端框架就是为了减少手动DOM操作的痛苦,别跟框架对着干。要是真遇到性能瓶颈,先看看是不是数据量太大或者组件设计有问题。
点赞
2026-02-16 21:03