模拟滚动条与表格性能优化

模拟滚动条是在禁用浏览器自带滚动条后使用html和js代码自定义实现滚动条效果

首先需要设置原有出现滚动条的元素 overfolw:hidden

需要用到的事件有鼠标滚轮事件,mousemove,mouseup,mouseleave,mousedown(其中mousedown事件是放置在滚动条或者滚动滑块上的)

基于上一篇关于队列的文章,我们添加了这些事件

以下代码基于element-ui的表格控件table实现

<div class="el-table__body-scrollbar" ref="scrollBar" :style="[bodyHeight]">
        <div class="scroll_block" @mousedown="mouseDown"></div>
</div>


mouseEvent.addEvent(this,this.mouseMove,"mousemove");
mouseEvent.addEvent(this,this.mouseUp,"mouseup");   
mouseEvent.addEvent(this,this.mouseLeave,"mouseleave");
mouseEvent.addEvent(this,this.mouseWeel);

html部分就不做全部展示了,将以上代码中的html部分放到合适的地方或者自己写

/**
 *this.barHeight滚动条中滚动块的高度
 *this.scrollHeight滚动条本身的高度
 *this.tableHeight表格内部整体高度所有表格的高度和
 *以下所有阻止冒泡事件可以封装
*/

//滚动条中滚动块在鼠标按下时
mouseDown(e){
  this.isDrag=true;//标识参数 表示通过可以拖动了
  this.pageY=e.pageY;//记录初始的纵向位置
  //以下阻止冒泡部分可以封装公用
  if(e.stopPropagation) e.stopPropagation();
  e.cancelBubble=true;
  e.returnValue=false;
  return false;
}

mouseMove(event){
  if(this.isDrag){
    var tar=this.$refs.scrollBar.children.item(0);//没有直接使用ref,取的是滚动块
    var mv=event.pageY-this.pageY;//移动量
    var top=tar.style.top;//当前滚动块的top 位置
    if(top){//如果存在
      top=parseFloat(top.replace("px",""));//得出具体数值
      if((mv+this.barHeight+top)>this.scrollHeight){//如果移动量加块本身的高度加原有的top位置大于了滚动条的高度
        mv=this.scrollHeight-this.barHeight;//移动量保持在最底部
      }else if((mv+top)<0){//如果是向上滑动并且超出了顶部  保留在顶部
        mv=0;
      }else{//正常情况   相加就行
        mv=top+mv;
      }
    }else{
      if((mv+this.barHeight)>this.scrollHeight){//同上一种情况,去掉top的影响,去掉相加的情况
            mv=this.scrollHeight-this.barHeight;
      }else if(mv<0){mv=0;}
    }
    this.adjust(mv);//具体执行函数,执行滚动条位置变换操作
    this.pageY=event.pageY;//保存当前位置
    if(!this.simulate){//不可分页  在不可分页的情况 可能实际数据与显示数据不一致 这里是将滚动事件分发到了父组件
      this.$emit('bar-scroll',event,mv,this.barHeight);
    }
    if(event.stopPropagation) event.stopPropagation();
    if(event.preventDefault) event.preventDefault();
    event.cancelBubble=true;
    event.returnValue=false;
    return false;
  }
}

//这里习惯性的使用了原生js
adjust(mv){
  if(typeof mv=='number'){
    var tar=this.$refs.scrollBar.children.item(0);
    var table=this.bodyWrapper.querySelector(".el-table__body");
    tar.style.top=mv+"px";
    //到了这里mv代表的就是新的top属性  这是常规算法
    //使用marginTop调整块的位置
    table.style.marginTop=-(mv*(this.tableHeight-this.scrollHeight))/(this.scrollHeight-this.barHeight)+"px";
  }
}

//当鼠标结束按下的状态后
mouseUp(e){
   if(this.isDrag){
    this.isDrag = false;//标识设置为否
    if (e.stopPropagation) e.stopPropagation();
    e.cancelBubble = true;
    e.returnValue = false;
    return false;  
   }
}
//离开作用范围后
mouseLeave(event){
  this.isDrag=false;
},

//鼠标滚轮滚动时的操作
mouseWeel(event){
  //先判断作用域范围是否是当前组件
  event = event || window.event;
  var tar=this.bodyWrapper;
  var target=event.target;
  if(tar.contains(target)){
    var scrollBar=this.$refs.scrollBar;
    var bar=scrollBar.children.item(0);
    var resize=this.simulate?1:(100/this.total);
    var top=bar.style.top,step=(100*this.scrollHeight*resize)/this.tableHeight;
    if(scrollBar.style.display!="none"){
      top=parseFloat(top.replace("px",""));
      if (event.wheelDelta) {  //判断浏览器IE,谷歌滑轮事件    
        //当滑轮向上滚动时
        if (event.wheelDelta > 0) {
          if((top-step)<=0){
            this.adjust(0);
          }else{
            this.adjust(top-step);
          }
          if(top>0){
            if(event.stopPropagation) event.stopPropagation();
            if(event.preventDefault) event.preventDefault();
            event.cancelBubble=true;
            event.returnValue=false;
            return false;
          }
        }
        //当滑轮向下滚动时  
        if (event.wheelDelta < 0) {
          if((top+step+this.barHeight)>=this.scrollHeight){
            this.adjust(this.scrollHeight-this.barHeight);
          }else{
            this.adjust(top+step);
          }
          if((top+this.barHeight)<(this.scrollHeight-0.01)){
            if(event.stopPropagation) event.stopPropagation();
              if(event.preventDefault) event.preventDefault();
              event.cancelBubble=true;
              event.returnValue=false;
              return false;
          }
        }
      } else if (event.detail) {  //Firefox滑轮事件  
        if (event.detail< 0) {
          if((top-step)<=0){
            this.adjust(0);
          }else{
            this.adjust(top-step);
          }
          if(top>0){
            if(event.stopPropagation) event.stopPropagation();
            if(event.preventDefault) event.preventDefault();
            event.cancelBubble=true;
            event.returnValue=false;
            return false;
          }
        }
        if (event.detail> 0) {
          if((top+step+this.barHeight)>=this.scrollHeight){
            this.adjust(this.scrollHeight-this.barHeight);
          }else{
            this.adjust(top+step);
          }
          if((top+this.barHeight)<this.scrollHeight){
            if(event.stopPropagation) event.stopPropagation();
            if(event.preventDefault) event.preventDefault();
            event.cancelBubble=true;
            event.returnValue=false;
            return false;
          }
         }
       }
     }
   }
  }
}

//执行位置更新操作  并初始化相关参数
//判断是否需要显示滚动条
//代码可能不那么vue 不过不重要
scrollBarSet(){
  var scrollBar=this.$refs.scrollBar;
  if(scrollBar){
    var body=this.bodyWrapper,table=body.querySelector(".el-table__body");
    var bar=scrollBar.children.item(0);
    var extraHgt=table.offsetWidth>body.offsetWidth?10:0;//设置额外高度。主要是底部滚动条高度这里设置为10
    if(body.offsetHeight>=(table.offsetHeight+extraHgt)){
      scrollBar.style.display="none";
      bar.style.top="";
      bar.style.height="";
      this.adjust(0);
    }else{
      scrollBar.style.display="block";
      var height=(body.offsetHeight*scrollBar.offsetHeight)/(table.offsetHeight+extraHgt);
      if(height<20){//当数据量过大的时候保持滚动块最少20px
        height=20;
      }
      bar.style.height=height+"px";
      this.scrollHeight=scrollBar.offsetHeight;
      this.tableHeight=table.offsetHeight+extraHgt;
      this.barHeight=height;
      var top=bar.style.top;
      if(top){
        top=parseFloat(top.replace("px",""));
        if((top+height)>this.scrollHeight){
          top=this.scrollHeight-height;
        }
      }else{top=0;}
        this.adjust(top);
      }
  }
},

以上代码可以实现正常情况下的模拟滚动条功能
如果需要实现在数据量特别大的时候只加载显示部分数据
并且根据相关事件在滚动过程中变换数据实现从显示上加载了全部数据的形式
就需要在实际的控件中手动去切换数据并配合预留的bar-scroll分发实现了

这部分就不贴代码了,完成了这个步骤表格就不会应为数据量而造成严重性能问题

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,744评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,505评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,105评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,242评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,269评论 6 389
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,215评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,096评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,939评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,354评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,573评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,745评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,448评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,048评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,683评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,838评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,776评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,652评论 2 354

推荐阅读更多精彩内容