模擬滾動(dòng)條是在禁用瀏覽器自帶滾動(dòng)條后使用html和js代碼自定義實(shí)現(xiàn)滾動(dòng)條效果
首先需要設(shè)置原有出現(xiàn)滾動(dòng)條的元素 overfolw:hidden
需要用到的事件有鼠標(biāo)滾輪事件,mousemove,mouseup,mouseleave,mousedown(其中mousedown事件是放置在滾動(dòng)條或者滾動(dòng)滑塊上的)
基于上一篇關(guān)于隊(duì)列的文章,我們添加了這些事件
以下代碼基于element-ui的表格控件table實(shí)現(xiàn)
<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滾動(dòng)條中滾動(dòng)塊的高度
*this.scrollHeight滾動(dòng)條本身的高度
*this.tableHeight表格內(nèi)部整體高度所有表格的高度和
*以下所有阻止冒泡事件可以封裝
*/
//滾動(dòng)條中滾動(dòng)塊在鼠標(biāo)按下時(shí)
mouseDown(e){
this.isDrag=true;//標(biāo)識(shí)參數(shù) 表示通過可以拖動(dòng)了
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,取的是滾動(dòng)塊
var mv=event.pageY-this.pageY;//移動(dòng)量
var top=tar.style.top;//當(dāng)前滾動(dòng)塊的top 位置
if(top){//如果存在
top=parseFloat(top.replace("px",""));//得出具體數(shù)值
if((mv+this.barHeight+top)>this.scrollHeight){//如果移動(dòng)量加塊本身的高度加原有的top位置大于了滾動(dòng)條的高度
mv=this.scrollHeight-this.barHeight;//移動(dòng)量保持在最底部
}else if((mv+top)<0){//如果是向上滑動(dòng)并且超出了頂部 保留在頂部
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);//具體執(zhí)行函數(shù),執(zhí)行滾動(dòng)條位置變換操作
this.pageY=event.pageY;//保存當(dāng)前位置
if(!this.simulate){//不可分頁 在不可分頁的情況 可能實(shí)際數(shù)據(jù)與顯示數(shù)據(jù)不一致 這里是將滾動(dòng)事件分發(fā)到了父組件
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;
}
}
//這里習(xí)慣性的使用了原生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屬性 這是常規(guī)算法
//使用marginTop調(diào)整塊的位置
table.style.marginTop=-(mv*(this.tableHeight-this.scrollHeight))/(this.scrollHeight-this.barHeight)+"px";
}
}
//當(dāng)鼠標(biāo)結(jié)束按下的狀態(tài)后
mouseUp(e){
if(this.isDrag){
this.isDrag = false;//標(biāo)識(shí)設(shè)置為否
if (e.stopPropagation) e.stopPropagation();
e.cancelBubble = true;
e.returnValue = false;
return false;
}
}
//離開作用范圍后
mouseLeave(event){
this.isDrag=false;
},
//鼠標(biāo)滾輪滾動(dòng)時(shí)的操作
mouseWeel(event){
//先判斷作用域范圍是否是當(dāng)前組件
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,谷歌滑輪事件
//當(dāng)滑輪向上滾動(dòng)時(shí)
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;
}
}
//當(dāng)滑輪向下滾動(dòng)時(shí)
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;
}
}
}
}
}
}
}
//執(zhí)行位置更新操作 并初始化相關(guān)參數(shù)
//判斷是否需要顯示滾動(dòng)條
//代碼可能不那么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;//設(shè)置額外高度。主要是底部滾動(dòng)條高度這里設(shè)置為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){//當(dāng)數(shù)據(jù)量過大的時(shí)候保持滾動(dòng)塊最少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);
}
}
},
以上代碼可以實(shí)現(xiàn)正常情況下的模擬滾動(dòng)條功能
如果需要實(shí)現(xiàn)在數(shù)據(jù)量特別大的時(shí)候只加載顯示部分?jǐn)?shù)據(jù)
并且根據(jù)相關(guān)事件在滾動(dòng)過程中變換數(shù)據(jù)實(shí)現(xiàn)從顯示上加載了全部數(shù)據(jù)的形式
就需要在實(shí)際的控件中手動(dòng)去切換數(shù)據(jù)并配合預(yù)留的bar-scroll分發(fā)實(shí)現(xiàn)了
這部分就不貼代碼了,完成了這個(gè)步驟表格就不會(huì)應(yīng)為數(shù)據(jù)量而造成嚴(yán)重性能問題