车型参数配置页的实现与优化(dom过多造成页面卡顿,优化dom)
2020/4/23 11:22:17
本文主要是介绍车型参数配置页的实现与优化(dom过多造成页面卡顿,优化dom),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
技术
vue、table
一、页面介绍
最近做个车型参数配置页,页面长下面这样,包括输入框,单选多选,下拉框,横向配置功能。
二、优化前效果演示以及分析问题
可以看的出来,页面异常卡顿,列头跟不上滑动,输入框卡的怀疑人生,做出来以后就开始分析问题,以及想对应的解决办法,当然最先怀疑的肯定是dom过多,但是看了汽车之家等类似页面,发现dom也是那么多,人家还是那么流畅,尝试解决问题:
- 首先就是优化后端返回来的数据,把所有无用的属性删除,想法很简单,以为能减轻vue监听的数据量,但是现实啪啪打脸,并没任何效果,思考了一下,vue框架应该不会监听view层没有用到的model,具体源码忘了,所以优化后端的数据就当个心里安慰吧。
- 其次就是把所有单元格的数据都写死,不再是根据类型各种判断显示出不同的输入框单选框什么的,嗯,这回速度唰唰的,基本猜到问题应该是两方面组成的,一个是template里的循环,条件判断太多,另一个是dom元素也多,第一种我没办法解决,因为这就是配置页面,不像汽车之家的展示页面,而且数据结构比较复杂,关联性比较强,循环起来比较多。所以自然想到优化dom元素在页面的数量这个办法了,下面开启讲解之旅。
三、从静态页面布局开始
拿到页面时想到的是elementui的表格有没有这种支持横向列的,呃,找半天没有,然后就默默的打开了汽车之家页面的开发者模式,借鉴了一下布局,是用纯table写的,我又根据我的需求改动了一些,但是大体跟汽车之家一样。
首先上面是一块,下面整体是一块,但是每个组又是一个table 大概就是这么个结构布局,下面是html结构代码,对应再写上css 静态页面就ok了。四、数据结构
数据结构这块可以看下图:
- 简单说下 config 是所有的参数,需要根据parent_cid把扁平化数组转成树结构的,代码稍后供上
- model 是车型数组,需要用config_list里的值 跟config里面key_value 对应上,表示的就是这个车型当前某个参数的值。
- config中有个value_area 以及 data_type,data_type是该参数的类型,比如单选多选下拉框输入框,value_area就是该参数值的范围。
- 所以我说循环判断的条件太多了,导致页面卡。
五、部分代码
- 数组转树代码
formatarr(config){ let parents = config.filter(value => value.parent_cid == 0 ) let children = config.filter(value => value.parent_cid !== 0 ) let translator = (parents, children) => { parents.forEach((parent) => { children.forEach((current, index) => { if (current.parent_cid === parent.id) { parent.sub !== undefined ? parent.sub.push(current) : parent.sub = [current] let temp = JSON.parse(JSON.stringify(children)) temp.splice(index, 1) translator([current], temp) } } ) } ) } translator(parents, children) return parents } 复制代码
- 下面是单个table的模版 ,一个table就是一组参数,可以略见数据的复杂,循环判断特别多。
<div class="conbox" style=" margin-top: 100px; overflow: auto; height: 500px;" @scroll="scrollevent" > <div v-for="(item,index) in config" :key=item.id :style="{ minHeight : (item.sub && item.sub.length+1)*61+'px'}" :ref="item.id"> <table class="tbcs" v-if="index==0 || item.showdom" > <tbody> <tr> <th class="cstitle" colspan="20"> <h3> <span>{{item.label}}</span> </h3> </th> </tr> <tr style="background: rgb(255, 255, 255);" v-for="subItem in item.sub" :key=subItem.id> <th> <div style=" display: flex; justify-content: space-between; align-items: center; width:169px" > <span>{{subItem.label}}</span> <el-button size="mini" style="margin-right: 10px;" @click="hengxiang(subItem.key_value)" >横向配置</el-button> </div> </th> <td v-for="item in model" :key=item.id> <div v-if=" judgeconfig_list( item['config_list'] )"> <div v-if="subItem['data_type'] == 'input' "> <el-input v-model="item['config_list'][subItem.key_value]" :placeholder=subItem.label ></el-input> </div> <div v-else-if="subItem['data_type'] == 'select' "> <el-select v-model="item['config_list'][subItem.key_value] " placeholder="请选择"> <el-option v-for="item in JSON.parse(subItem['value_area']) " :key="item.label" :label="item.label" :value="item.label" > </el-option> </el-select> </div> <div v-else-if="subItem['data_type'] == 'radio' "> <el-radio style="display: block; padding-top: 2px;" v-for="ritem in JSON.parse(subItem['value_area'])" :key="ritem.key" v-model="item['config_list'][subItem.key_value]" :label="ritem.key + ','+ ritem.label + ','"> {{ritem.label}} </el-radio> </div> <div v-else-if="subItem['data_type'] == 'checkbox' "> <el-checkbox-group v-model="item['config_list'][subItem.key_value]"> <el-checkbox v-for="ritem in JSON.parse(subItem['value_area'])" :key="ritem.key" style="display: block;" :label="ritem.key + ','+ ritem.label + ','" > <span style=" height: 10px; display: inline-block; width: 10px; background: black; border-radius: 50px;" v-if="filtercheckbox(ritem.key) == 1" ></span> <span style=" height: 8px; display: inline-block; width: 8px; background: white; border-radius: 50px; border: 1px solid black;" v-else-if="filtercheckbox(ritem.key) == 2" ></span> <span style=" height: 10px; display: inline-block; width: 10px; " v-else> </span> <span class="el-checkbox__label">{{ritem.label}}</span> </el-checkbox> </el-checkbox-group> </div> </div> </td> </tr> </tbody> </table> </div> </div> 复制代码
- 滚动事件的代码
scrollevent(e){ this.scrollleft = -e.target.scrollLeft let scrolltop = e.target.scrollTop for (const key in this.$refs) { if (this.$refs.hasOwnProperty(key)) { const element = this.$refs[key]; if((600+scrolltop)>element[0].offsetTop){ let j = 0; for(let i = 0;i<this.config.length;i++){ if (this.config[i].id == key){ this.config[i]['showdom'] =true if(i-1 >=0 ){ j = i-1 } }else{ this.config[i]['showdom'] =false } } this.config[j]['showdom'] =true } } } } 复制代码
六、开始讲解
- 首先,删除dom以及新增dom的思路跟懒加载类似,页面滚动到下面的div快露出来了,就把table插入到div里,这里很重要的一点就是div要占位,要有高度,但是这个高度怎么算的呢,因为这不是普通那种全是图片的结构,这是俩级结构,所以我只想按table来一个一个的展示,table里面的不做dom的删改。 table外面的div刚开始里面是空的,高度自行根据table里面有多少内容算出 minHeight : (item.sub && item.sub.length+1)*61+'px'
- 其次要在父节点有一个属性,标记当前表格显示隐藏的状态,这个需要在数据处理时加进去,默认全是false,然后在循环时 table 里做这个判断 v-if="index==0 || item.showdom" 第一位的展示或者showdom为true
- 最后就开始在滚动事件里做处理 思路就是当前展示区的高度+滑动的scrollTop大于元素的offsetTop就让当前的table显示出来,否则隐藏,但是这里有一个问题,就是下面的表格刚显示出来上面的表格消失了,所以根据自己业务吧,把当前显示出来的table上一个table在内侧循环后也把showdom 置为true,这样就衔接起来了,具体看table高度吧,代码在上面。
- 说下这种解决的优缺点吧,优点毋庸置疑,页面不卡了,缺点也显而易见,就是滚动快了会增加白屏时间,但是利大于弊,所以必须这么做。
七、总结
至此这篇文章就结束了,其中每个细节部分都不简单,都要仔细思考,要不我也不会写出来, 如果还有什么问题评论区留言,我尽量解答。希望看完不要忘记点赞,手敲不易。
这篇关于车型参数配置页的实现与优化(dom过多造成页面卡顿,优化dom)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-10-06小米11i印度快充版ROM合集:极致体验,超越期待
- 2024-10-06【ROM下载】小米11i 5G 印度版系统, 疾速跃迁,定义新速度
- 2024-10-06【ROM下载】小米 11 青春活力版,青春无极限,活力全开
- 2024-10-05小米13T Pro系统合集:性能与摄影的极致融合,值得你升级的系统ROM
- 2024-10-01基于Python+Vue开发的医院门诊预约挂号系统
- 2024-10-01基于Python+Vue开发的旅游景区管理系统
- 2024-10-01RestfulAPI入门指南:打造简单易懂的API接口
- 2024-10-01初学者指南:了解和使用Server Action
- 2024-10-01Server Component入门指南:搭建与配置详解
- 2024-10-01React 中使用 useRequest 实现数据请求