cari

Rumah  >  Soal Jawab  >  teks badan

Vuejs v-for sangat lambat pada tatal yang tidak terhingga

Saya mempunyai kesan vuejs yang pelik, apabila saya menambah data objek baharu, v-for memaparkan semula semua objek, walaupun ia telah diberikan.

Saya sedang melaksanakan tatal tak terhingga seperti buku muka.

Kod

Untuk menerangkan kod ini, saya mendapat data baharu daripada firebase dan kemudian menolaknya ke objek data apabila ia mencapai bahagian bawah skrin


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>


Sekarang, inilah perkaranya…

Lihat rakaman skrin ini, tetikus fokus, ia sangat lembap, saya tidak boleh klik pada butang semasa vuejs menambah dan memuatkan data baharu

Ini adalah kod yang saya gunakan

Apa yang saya syak

Saya mengesyaki bahawa setiap kali data baharu ditambahkan, VueJS memaparkan semula semua data, menyebabkan kesan ini. Bagaimana untuk memaksa vueJS tidak memaparkan semula data yang telah diberikan pada skrin?

P粉301523298P粉301523298330 hari yang lalu382

membalas semua(1)saya akan balas

  • P粉567112391

    P粉5671123912023-12-29 16:34:20

    Anda mempunyai dua async IIFE yang tidak perlu; yang kedua dalam forEach amat bermasalah kerana kod tak segerak di dalamnya akan dilaksanakan secara serentak pada setiap lelaran gelung, yang mempunyai kesan berikut:

    1. getDocs() akan menyala serta-merta pada setiap lelaran gelung, mungkin menghantar spam kepada pelayan (dengan andaian ini melaksanakan permintaan rangkaian). Adakah ini niat anda? Nampaknya anda hanya boleh mendapat maksimum 5 siaran baharu, jadi tidak mengapa.
    2. Fungsi async mengemas kini beberapa keadaan, yang akan mencetuskan Vue untuk memaparkan semula bagi setiap dokumen. Ini harus dikumpulkan bersama pada penghujung supaya Vue mengemas kini sesedikit mungkin.

    Jangan guna var;使用 constlet 代替。几乎没有充分的理由再使用 var pun, biarkan ia mati.

    Saya tidak boleh mengatakan ini akan meningkatkan prestasi anda dengan ketara, tetapi saya mengesyorkan perubahan berikut (belum diuji):

    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);
        }
      }
    }
    

    Pelaksanaan dalam templat :post-content="truncateString(linkify(post.data().post_content))" 意味着 linkify 将在每次重新渲染期间执行。我怀疑 linkify Mungkin lambat untuk senarai panjang? Bolehkah ia dikira terlebih dahulu untuk setiap jawatan?

    Apabila komponen dipasang, anda sedang mendaftar pendengar acara tatal tetingkap. Jika komponen dimusnahkan, anda perlu menyahdaftar pendengar acara, jika tidak, ia masih akan menyala setiap kali tetingkap ditatal. Ini mungkin tidak menjadi masalah dalam kes anda, tetapi untuk komponen boleh guna semula adalah perlu.

    balas
    0
  • Batalbalas