我有一個奇怪的 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
對於長列表可能會很慢?可以提前為每個帖子預先計算嗎?當元件安裝時,您正在註冊一個視窗滾動事件偵聽器。如果元件被銷毀,您需要取消註冊事件偵聽器,否則每當視窗滾動時它仍然會觸發。對於您的情況來說,這可能不是問題,但對於可重複使用元件來說,必須這樣做。