我有一个奇怪的 vuejs 效果,当我添加新的对象数据时,v-for 会重新渲染所有对象,即使它已经渲染了。
我正在实现像 face book 一样的无限滚动。
为了解释这段代码,我从 firebase 获取新数据,然后当数据到达屏幕底部时将其推送到数据对象中
var vueApp = new Vue({
el: '#root',
data: {
postList: [],
isOkaytoLoad: false,
isRoomPostEmpty: false,
},
mounted: function() {
// Everytime user scroll, call handleScroll() method
window.addEventLis tener('scroll', this.handleScroll);
},
methods: {
handleScroll: function()
{
var d = document.documentElement;
var offset = d.scrollTop + window.innerHeight;
var height = d.offsetHeight - 200;
// If the user is near the bottom and it's okay to load new data, get new data from firebase
if (this.isOkaytoLoad && offset >= height)
{
this.isOkaytoLoad = false;
(async()=>{
const lastPost = this.postList[this.postList.length - 1];
const room_id = PARAMETERS.get('room');
const q = query(collection(db, 'posts'), where('room', '==', room_id), orderBy("time", "desc"), limit(5), startAfter(lastPost));
const roomSnapshot = await getDocs(q);
roomSnapshot.forEach((doc) => {
const postID = doc.id;
(async()=>{
// Put the new data at the postList object
this.postList = [...this.postList, doc];
const q = query(collection(db, 'comments'), where('post_id', '==', postID));
const commentSnapshot = await getDocs(q);
doc['commentCount'] = commentSnapshot.size;
//this.postList.push(doc);
console.log(this.postList);
setTimeout(()=>{ this.isOkaytoLoad = true }, 1000);
})();
});
})();
}
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div v-if="postList.length > 0" class="card-containers">
<!-- I have a component `Postcard` in my js file and it works well -->
<Postcard
v-for="post in postList"
:key="post.id"
:post-id="post.id"
:owner-name="post.data().owner_displayName"
:owner-uid="post.data().owner_id"
:post-type="post.data().post_type"
:image-url="post.data().image_url"
:post-content="truncateString(linkify(post.data().post_content))"
:room="post.data().room"
:time="post.data().time.toDate()"
:likers="post.data().likers"
:comment-count="post.commentCount"
:file-url="post.data().file_url"
:file-name="post.data().file_name"
:downloads="post.data().downloads">
</Postcard>
</div>
看看这个屏幕记录,聚焦鼠标,它很滞后,当 vuejs 添加和加载新数据时我什至无法单击这些按钮
这是我使用的代码
我怀疑每次添加新数据时,VueJS 都会重新渲染所有数据,从而产生这种效果。如何强制 vueJS 不重新渲染那些已经在屏幕上渲染的数据?
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号
你有两个不必要的异步IIFE;
forEach中的第二个问题尤其严重,因为其中的异步代码将在每个循环迭代中同时执行,这会产生以下影响:getDocs()将在每次循环迭代时立即触发,可能会向服务器发送垃圾邮件(假设这是执行网络请求)。这是你的意图吗?看来您最多只能获取 5 个新帖子,所以这可能没问题。也不要使用
var;使用const或let代替。几乎没有充分的理由再使用var了,让它死吧。我不能说这会显着提高您的性能,但我建议进行以下更改(未经测试):
async handleScroll() { const d = document.documentElement; const offset = d.scrollTop + window.innerHeight; const height = d.offsetHeight - 200; // If the user is near the bottom and it's okay to load new data, get new data from firebase if (this.isOkaytoLoad && offset >= height) { // Prevent loading while we load more posts this.isOkaytoLoad = false; try { // Get new posts const lastPost = this.postList[this.postList.length - 1]; const room_id = PARAMETERS.get('room'); const q = query(collection(db, 'posts'), where('room', '==', room_id), orderBy("time", "desc"), limit(5), startAfter(lastPost)); const roomSnapshot = await getDocs(q); // Fetch comments of each post. Do this all at once for each post. // TODO: This can probably be optimized into a single query // for all the posts, instead of one query per post. await Promise.all(roomSnapshot.docs.map(async doc => { const postID = doc.id; const q = query(collection(db, 'comments'), where('post_id', '==', postID)); const commentSnapshot = await getDocs(q); doc.commentCount = commentSnapshot.size; })); // Append the new posts to the list this.postList.push(...roomSnapshot.docs); } catch (ex) { // TODO: Handle error } finally { // Wait a bit to re-enable loading setTimeout(() => { this.isOkaytoLoad = true }, 1000); } } }在模板中执行
:post-content="truncateString(linkify(post.data().post_content))"意味着linkify将在每次重新渲染期间执行。我怀疑linkify对于长列表可能会很慢?可以提前为每个帖子预先计算吗?当组件安装时,您正在注册一个窗口滚动事件侦听器。如果组件被销毁,您需要取消注册事件侦听器,否则每当窗口滚动时它仍然会触发。对于您的情况来说,这可能不是问题,但对于可重用组件来说,必须这样做。