之前写了一个功能,通过v-for渲染数据,但是数据中存在hidden项,则对数据进行隐藏,由于数据显隐采用了v-if,且循环使用的key,用了(index+900)之类的写法,导致虚拟dom的计算量成倍上涨。\n具体问题如下:\n\n\u003Ctemplate v-if="showFieldList">\n \u003Ctemplate v-for="(item, index) in fieldList">\n \u003Ctemplate v-if="!item.hidden">\n \u003C!-- 单选框 -->\n \u003Cel-col\n :span="item.span || 8"\n :key="index + 900"\n v-if="item.type === 'radio'"\n >\n ......\n \u003C/template>\n \u003C/template>\n\u003C/template>\n\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n这里犯了两个重大的错误,\n第一,key作为vue虚拟dom中递归判断改变的标志,正确的使用key可以节省很多无畏的性能损失。\n\n设置key与不设置key区别\n举个例子:\n\n创建一个实例,2秒后往items数组插入数据\n\n\u003Cbody>\n \u003Cdiv id="demo">\n \u003Cp v-for="item in items" :key="item">{{item}}\u003C/p>\n \u003C/div>\n \u003Cscript src="../../dist/vue.js">\u003C/script>\n \u003Cscript>\n // 创建实例\n const app = new Vue({\n el: '#demo',\n data: { items: ['a', 'b', 'c', 'd', 'e'] },\n mounted () {\n setTimeout(() => { \n this.items.splice(2, 0, 'f') // \n }, 2000);\n },\n });\n \u003C/script>\n\u003C/body>\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n在不使用key的情况,vue会进行这样的操作:\n\n\n分析下整体流程:\n\n比较A,A,相同类型的节点,进行patch,但数据相同,不发生dom操作\n比较B,B,相同类型的节点,进行patch,但数据相同,不发生dom操作\n比较C,F,相同类型的节点,进行patch,数据不同,发生dom操作\n比较D,C,相同类型的节点,进行patch,数据不同,发生dom操作\n比较E,D,相同类型的节点,进行patch,数据不同,发生dom操作\n循环结束,将E插入到DOM中\n一共发生了3次更新,1次插入操作\n\n在使用key的情况:vue会进行这样的操作:\n\n比较A,A,相同类型的节点,进行patch,但数据相同,不发生dom操作\n比较B,B,相同类型的节点,进行patch,但数据相同,不发生dom操作\n比较C,F,不相同类型的节点\n比较E、E,相同类型的节点,进行patch,但数据相同,不发生dom操作\n比较D、D,相同类型的节点,进行patch,但数据相同,不发生dom操作\n比较C、C,相同类型的节点,进行patch,但数据相同,不发生dom操作\n循环结束,将F插入到C之前\n一共发生了0次更新,1次插入操作\n\n通过上面两个小例子,可见设置key能够大大减少对页面的DOM操作,提高了diff效率\n\n第二,Vue 官方强烈不建议在 v-for 内使用 v-if,因为这会 导致重复计算。改用 computed 过滤数据:\n\n\u003C!-- 错误做法 -->\n\u003Cdiv v-for="item in list" v-if="item.isActive">{{ item.text }}\u003C/div>\n\n\u003C!-- 正确做法 -->\n\u003Cdiv v-for="item in activeList" :key="item.id">{{ item.text }}\u003C/div>\n\n\u003Cscript>\nexport default {\n computed: {\n activeList() {\n return this.list.filter(item => item.isActive);\n }\n }\n};\n\u003C/script>\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n最后修改为如下写法:\n\n\u003Ctemplate v-if="showFieldList">\n \u003Ctemplate v-for="(item, index) in activeList">\n \u003Ctemplate>\n \u003C!-- 单选框 -->\n \u003Cel-col\n :span="item.span || 8"\n :key="item.code"\n v-if="item.type === 'radio'"\n >\n ......\n \u003C/template>\n \u003C/template>\n\u003C/template>\n\nactiveList() {\n return this.fieldList.filter(item => !item.hidden);\n}\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n至此,性能问题基本解决。引以为鉴!
文章来源:ximaonetwork.cn