跟着视频学做项目的时候,碰到一个多级联动列表,列表元素的display会从none切换成block,切换过程中可能导致资源渲染过多,从而导致卡顿问题。
javascript
<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。
组件渲染导致使用卡顿
javascript
<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事件处理。
回调函数被多次渲染
javascript
<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获得点击的标签,进行处理。
javascript
<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>