我有一个奇怪的 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 不重新渲染那些已经在屏幕上渲染的数据?
你有两个不必要的异步IIFE;
forEach
中的第二个问题尤其严重,因为其中的异步代码将在每个循环迭代中同时执行,这会产生以下影响:getDocs()
将在每次循环迭代时立即触发,可能会向服务器发送垃圾邮件(假设这是执行网络请求)。这是你的意图吗?看来您最多只能获取 5 个新帖子,所以这可能没问题。也不要使用
var
;使用const
或let
代替。几乎没有充分的理由再使用var
了,让它死吧。我不能说这会显着提高您的性能,但我建议进行以下更改(未经测试):
在模板中执行
:post-content="truncateString(linkify(post.data().post_content))"
意味着linkify
将在每次重新渲染期间执行。我怀疑linkify
对于长列表可能会很慢?可以提前为每个帖子预先计算吗?当组件安装时,您正在注册一个窗口滚动事件侦听器。如果组件被销毁,您需要取消注册事件侦听器,否则每当窗口滚动时它仍然会触发。对于您的情况来说,这可能不是问题,但对于可重用组件来说,必须这样做。