跟著視頻學做項目的時候,碰到一個多級聯動列表,列表元素的display會從none切換成block,切換過程中可能導致資源渲染過多,從而導致卡頓問題。
<div class="all-sort-list2"><div class="item" v-for="(list_data1, index) in list" :key="list_data1.categoryId"@mouseenter="setChooseIndex(index)"><h3 :class="{ chooseNow: nowIndex == index }"><a>{{ list_data1.categoryName }}</a></h3><div class="item-list clearfix" :style="{ display: nowIndex == index ? 'block' : 'none' }"><div class="subitem"><dl class="fore" v-for="list_data2 in list_data1.categoryChild" :key="list_data2.categoryId"><dt><a>{{ list_data2.categoryName }}</a></dt><dd><em v-for="list_data3 in list_data2.categoryChild" :key="list_data3.categoryId"><a>{{ list_data3.categoryName }}</a></em></dd></dl></div></div></div>
</div>
對于這個列表,其內部元素是從服務區獲取數據,然后通過v-for顯示。
類item-list的disblock會不斷從none切換為block。
組件渲染導致使用卡頓
<div class="all-sort-list2"><div class="item" v-for="(list_data1, index) in list" :key="list_data1.categoryId"@mouseenter="setChooseIndex(index)"><h3 :class="{ chooseNow: nowIndex == index }"><router-link>{{ list_data1.categoryName }}</router-link></h3><div class="item-list clearfix" :style="{ display: nowIndex == index ? 'block' : 'none' }"><div class="subitem"><dl class="fore" v-for="list_data2 in list_data1.categoryChild" :key="list_data2.categoryId"><dt><router-link>{{ list_data2.categoryName }}</router-link></dt><dd><em v-for="list_data3 in list_data2.categoryChild" :key="list_data3.categoryId"><router-link>{{ list_data3.categoryName }}</router-link></em></dd></dl></div></div></div>
</div>
當v-for循環中使用router-link標簽時,隨著display從none切換為block,多個router-link標簽會被重新渲染。由于router-link標簽是VUE組件,當數據過多時,可能一次display切換,會導致上千個VUE組件被重新渲染,因此會造成性能問題。
一個解決辦法是可以把router-link換成a標簽,再在a標簽上綁定click事件處理。
回調函數被多次渲染
<div class="all-sort-list2"><div class="item" v-for="(list_data1, index) in list" :key="list_data1.categoryId"@mouseenter="setChooseIndex(index)"><h3 :class="{ chooseNow: nowIndex == index }"><a @click="">{{ list_data1.categoryName }}</a></h3><div class="item-list clearfix" :style="{ display: nowIndex == index ? 'block' : 'none' }"><div class="subitem"><dl class="fore" v-for="list_data2 in list_data1.categoryChild" :key="list_data2.categoryId"><dt><a @click="">{{ list_data2.categoryName }}</a></dt><dd><em v-for="list_data3 in list_data2.categoryChild" :key="list_data3.categoryId"><a @click="">{{ list_data3.categoryName }}</a></em></dd></dl></div></div></div>
</div>
但是這種方法仍然存在問題,由于每個a標簽中都綁定了click事件,該事件會被渲染上千次,可以通過事件委托到父級,把事件的渲染降低為一次。
(但這里其實我也不太懂,我覺得雖然事件生成了多個,但是其實不click就不會被調用,不調用也會影響性能嗎)
解決辦法是使用事件委托。
把事件綁定在父級上,然后通過event.target獲得點擊的標簽,進行處理。
<div class="all-sort-list2" @click="goSearch"><div class="item" v-for="(list_data1, index) in list" :key="list_data1.categoryId" ... </div>
</div><script>...goSearch(event){let e = event.target;getAttribute('...');}
</script>