Ich habe einen seltsamen VueJS-Effekt: Wenn ich neue Objektdaten hinzufüge, rendert v-for alle Objekte neu, auch wenn sie bereits gerendert wurden.
Ich implementieren unendliches Scrollen wie Facebook.
Um diesen Code zu erklären, erhalte ich neue Daten von Firebase und schiebe sie dann in ein Datenobjekt, wenn es den unteren Bildschirmrand erreicht
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>
Schauen Sie sich diese Bildschirmaufnahme an, fokussierte Maus, sie ist so verzögert, dass ich nicht einmal auf die Schaltflächen klicken kann, während vuejs neue Daten hinzufügt und lädt
Dies ist der Code, den ich verwende
Ich vermute, dass VueJS jedes Mal, wenn neue Daten hinzugefügt werden, alle Daten neu rendert, was diesen Effekt verursacht. Wie kann man vueJS dazu zwingen, Daten, die bereits auf dem Bildschirm gerendert wurden, nicht erneut zu rendern?
你有两个不必要的异步IIFE;
forEach
中的第二个问题尤其严重,因为其中的异步代码将在每个循环迭代中同时执行,这会产生以下影响:getDocs()
将在每次循环迭代时立即触发,可能会向服务器发送垃圾邮件(假设这是执行网络请求)。这是你的意图吗?看来您最多只能获取 5 个新帖子,所以这可能没问题。也不要使用
var
;使用const
或let
代替。几乎没有充分的理由再使用var
了,让它死吧。我不能说这会显着提高您的性能,但我建议进行以下更改(未经测试):
在模板中执行
:post-content="truncateString(linkify(post.data().post_content))"
意味着linkify
将在每次重新渲染期间执行。我怀疑linkify
对于长列表可能会很慢?可以提前为每个帖子预先计算吗?当组件安装时,您正在注册一个窗口滚动事件侦听器。如果组件被销毁,您需要取消注册事件侦听器,否则每当窗口滚动时它仍然会触发。对于您的情况来说,这可能不是问题,但对于可重用组件来说,必须这样做。