Vue计算属性加载器不显示问题及大列表渲染优化咨询
加载器不显示的原因及解决方案
原因分析
- 同步状态变更被合并:计算属性内同步设置
loading=true后立刻改为false,Vue的响应式更新是异步批量处理的,这两个状态变更会被合并,DOM根本没有机会更新显示加载器。 - 计算属性违反设计原则:计算属性的定位是无副作用的纯计算逻辑,直接在里面修改
data中的loading属于不当操作。 - 渲染阻塞:真正耗时的是数千条数据的DOM节点生成,这个过程在Vue的更新周期内同步执行,会阻塞浏览器渲染,导致加载器无法及时显示。
解决方案
- 将排序触发逻辑改为方法调用,先触发加载器显示,再把排序操作放到下一个事件循环,让浏览器先渲染加载器再处理列表更新。
- 排序时创建数组副本,避免直接修改原数组(
Array.sort()会修改原数组)。 - 利用
$nextTick在列表渲染完成后关闭加载器。
修改后的代码
模板代码
<div v-if="loading">Wait pliz</div> <div @click="handleSort('ctg')">SortByCtg</div> <div v-for="item in sortedRows" :key="item.id">{{item.ctg}} , {{item.name}} .... </div>
脚本代码
data: function(){ return { sortby: 'name', sortbyDir: 1, loading: false, rows: [ {'id': 1, 'name':'abc','ctg':'def'}, ...] // 给每个项添加唯一ID作为v-for的key } }, computed: { sortedRows: function(){ const sortby = this.sortby; const sortbyDir = this.sortbyDir; // 创建数组副本再排序,避免修改原数组 return [...this.rows].sort(function(a, b) { return sortbyDir * a[sortby].localeCompare(b[sortby]); }); } }, methods: { handleSort(field) { // 先显示加载器 this.loading = true; // 将排序操作放到下一个事件循环,让浏览器先渲染加载器 setTimeout(() => { this.sortby = field; // 等待列表DOM渲染完成后关闭加载器 this.$nextTick(() => { this.loading = false; }); }, 0); } }
额外说明
- 给
v-for添加唯一key是Vue性能优化的必要操作,能大幅减少重复DOM节点的创建,加快渲染速度。 setTimeout(fn, 0)的作用是让当前事件循环结束后再执行排序,此时浏览器会优先处理加载器的DOM渲染,避免被列表渲染阻塞。
内容的提问来源于stack exchange,提问作者PM_KLS
相关产品推荐
相关产品推荐

