vue中引入mousewheel事件及兼容性處理方式
引入mousewheel事件及兼容性處理
項(xiàng)目實(shí)現(xiàn)過(guò)程中需要對(duì)一個(gè)已經(jīng)有縱向滾動(dòng)條的table表格增加鼠標(biāo)滾輪(mousewheel)事件,方便查看數(shù)據(jù);其實(shí)現(xiàn)原理與我上一篇博客中的拖動(dòng)事件類似,利用模擬出來(lái)的同一個(gè)滾動(dòng)條來(lái)實(shí)現(xiàn)
滾動(dòng)條設(shè)置的要點(diǎn)在于
1、滾動(dòng)條與滾動(dòng)槽的高度比例 應(yīng)該等于 內(nèi)容區(qū)(動(dòng)態(tài)變化)和可視區(qū)的高度比例;滾動(dòng)槽與可視區(qū)平齊,高度一樣;滾動(dòng)條的高度則根據(jù)內(nèi)容的高度等比例計(jì)算;
2、各元素的定位采用絕對(duì)定位,其父元素采用相對(duì)定位,這樣就能很好地設(shè)置樣式;
布局與樣式做好后,只需要在組件methods注冊(cè)方法,在元素就位后調(diào)用該方法,在方法內(nèi)部為表格綁定(mousewheel)事件;在這里需要考慮兼容性問(wèn)題,firefox并不支持mousewheel事件,它對(duì)應(yīng)的鼠標(biāo)滾動(dòng)事件為DOMMouseScroll事件,并且該事件僅能通過(guò)DOM2級(jí)(addEventListener)添加處理程序;并且判斷鼠標(biāo)滾動(dòng)方向的方式也不一樣,firefoxt通過(guò)detail屬性判斷,向前滾動(dòng)該屬性為-3,向后+3;其余瀏覽器通過(guò)wheelDelta屬性,向前時(shí)為+120的倍數(shù),向后為-120的倍數(shù);
具體內(nèi)容可參考《js高級(jí)程序設(shè)計(jì)》事件一章;添加函數(shù)如下:
? ? scroll(){ ? ? ? ? this.wrapDiv = document.getElementById("wrap"); ? ? ? ? this.contentDiv = document.getElementById("context-table"); ? ? ? ? this.contentDiv1 = document.getElementById("context-table1"); ? ? ? ? this.sliderWrap = document.getElementById("sliderWrap"); ? ? ? ? this.slider = document.getElementById("slider"); ? ? ? ? //設(shè)置比例 ? ? ? ? let scale = ?this.wrapDiv.clientHeight / ?this.contentDiv.clientHeight; ? ? ? ? if (scale < 1) { ? ? ? ? ? this.mouseFlag = true; ? ? ? ? ? let h1 = ?this.sliderWrap.clientHeight * scale; ? ? ? ? ? h1 = (h1 < 50) ? 50 : h1; ? ? ? ? ? this.slider.style.height = h1 + "px";/*滾動(dòng)條高度動(dòng)態(tài)變化*/ ? ? ? ? ? let y = 0; ? ? ? ? ? let that = this; ? ? ? ? ? //為firefox添加滾輪事件 ? ? ? ? ? if (document.addEventListener){ ? ? ? ? ? ? document.addEventListener('DOMMouseScroll',function (e) { ? ? ? ? ? ? ? ? if(that.mouseFlag){ ? ? ? ? ? ? ? ? ? //console.log('scroll'); ? ? ? ? ? ? ? ? ? let event1 = window.event|| e; ? ? ? ? ? ? ? ? ? y = (event1.detail > 0) ? y + 8 : y - 8; ? ? ? ? ? ? ? ? ? y = (y < 0) ? 0 : y; ? ? ? ? ? ? ? ? ? let max = that.sliderWrap.clientHeight - that.slider.clientHeight; ? ? ? ? ? ? ? ? ? y = (y > max + 1) ? max + 1 : y; ? ? ? ? ? ? ? ? ? that.slider.style.top = y + "px"; ? ? ? ? ? ? ? ? ? scale = that.wrapDiv.clientHeight / that.contentDiv.clientHeight; ? ? ? ? ? ? ? ? ? let y1 = -y / scale; ? ? ? ? ? ? ? ? ? that.contentDiv.style.top = y1 + "px"; ? ? ? ? ? ? ? ? ? that.contentDiv1.style.top = y1 + "px"; ? ? ? ? ? ? ? ? } ? ? ? ? ? ? },false) ? ? ? ? ? } ? ? ? ? ? this.wrapDiv.onmousewheel = function (e) { ? ? ? ? ? ? if (scale < 1) { ? ? ? ? ? ? ? let event1 = window.event || e; ? ? ? ? ? ? ? y = (event1.wheelDelta < 0) ? y + 8 : y - 8; ? ? ? ? ? ? ? y = (y < 0) ? 0 : y;/*限定滾動(dòng)范圍*/ ? ? ? ? ? ? ? let max = ?that.sliderWrap.clientHeight - ?that.slider.clientHeight; ? ? ? ? ? ? ? //console.log(scale, y, sliderWrap.clientHeight, slider.clientHeight); ? ? ? ? ? ? ? y = (y > max + 1) ? max + 1 : y; ? ? ? ? ? ? ? that.slider.style.top = y + "px"; ? ? ? ? ? ? ? scale = ?that.wrapDiv.clientHeight / ?that.contentDiv.clientHeight; ? ? ? ? ? ? ? let y1 = -y / scale; ? ? ? ? ? ? ? that.contentDiv.style.top = y1 + "px"; ? ? ? ? ? ? ? that.contentDiv1.style.top = y1 + "px"; ? ? ? ? ? ? } ? ? ? ? ? } ? ? ? ? } ? ? ? ? else{/*當(dāng)內(nèi)容區(qū)高度小于等于可視區(qū)時(shí),去除綁定的事件和滾動(dòng)條*/ ? ? ? ? ? this.wrapDiv.onmousewheel =null; ? ? ? ? ? if(document.addEventListener){ ? ? ? ? ? ? ?this.mouseFlag = false; ? ? ? ? ? } ? ? ? ? ? this.sliderWrap.style.visibility = 'hidden'; ? ? ? ? ? let height = this.contentDiv.clientHeight; ? ? ? ? ? tableRight.style.height ?= height+72+'px'; ? ? ? ? ? this.wrapDiv.style.height = height+2+'px'; ? ? ? ? } ? ? ? },
該函數(shù)在給firefox綁定的事件解綁時(shí)遇到了問(wèn)題,由于removeEventListener()需要通過(guò)句柄來(lái)解綁,而addEventListener()通過(guò)句柄添加處理函數(shù)會(huì)導(dǎo)致event參數(shù)無(wú)法傳遞的問(wèn)題;即使在需要解綁時(shí)給document綁定空的處理函數(shù)也無(wú)法覆蓋前一個(gè)綁定函數(shù);最后只好添加一個(gè)標(biāo)志,在需要解綁函數(shù)時(shí)改變標(biāo)志的值;在綁定函數(shù)中通過(guò)判斷該標(biāo)志的值來(lái)確定是否要做操作;
通過(guò)上述方式即可很好地實(shí)現(xiàn)鼠標(biāo)滾動(dòng)事件的效果,并不會(huì)有兼容性的問(wèn)題出現(xiàn)。
注:若僅僅是為表格綁定單一的滾動(dòng)事件,則可以不顯示滾動(dòng)條,甚至不設(shè)置滾動(dòng)條;滾動(dòng)條的作用僅僅是用來(lái)指示內(nèi)容區(qū)滾動(dòng)的位置,以及配合拖動(dòng)事件使用;
關(guān)于scroll和mousewheel事件的問(wèn)題
需要注意的點(diǎn)
火狐的鼠標(biāo)滾輪事件是DOMMouseScroll
事件參數(shù)兼容:e=window.event||e;(下面省略)
preventDefault()函數(shù)取消的是默認(rèn)事件,不會(huì)把我們自己添加的事件處理刪除
實(shí)驗(yàn)開(kāi)始
在下面驗(yàn)證例子的基礎(chǔ)上實(shí)驗(yàn),實(shí)驗(yàn)之間代碼沒(méi)有干涉:
1.原樣輸出
在元素內(nèi)無(wú)論是手動(dòng)拉動(dòng)滾動(dòng)條還是滾動(dòng)鼠標(biāo)滾輪,'d'都是無(wú)法出現(xiàn)的。而當(dāng)元素滾動(dòng)到達(dá)頂部或底部的時(shí)候,輸出的是就有'd'了,但是這個(gè)時(shí)候并沒(méi)有輸出'b',說(shuō)明scroll事件本來(lái)就沒(méi)有發(fā)生冒泡。而document的scroll事件是由于其他因素觸發(fā)的。
2.在element的mousewheel事件處理里把冒泡取消
e.stopPropagation();
這時(shí)候在元素內(nèi)滾動(dòng)鼠標(biāo)滾輪,'c'始終是無(wú)法出現(xiàn)的,說(shuō)明我們阻止mousewheel事件的冒泡成功了。但是在滾動(dòng)條到達(dá)底部或頂部時(shí),雖然'c'依舊沒(méi)有出現(xiàn),但是'd'卻出現(xiàn)了,說(shuō)明這個(gè)時(shí)候的document的scroll事件是靠element的mousewheel來(lái)觸發(fā)的。
到這里就出現(xiàn)一個(gè)問(wèn)題:element的mousewheel事件在默認(rèn)處理里對(duì)這一情形進(jìn)行了處理嗎?
3.在element的mousewheel事件處理里取消默認(rèn)處理
e.preventDefault();
這時(shí)候在元素內(nèi)滾動(dòng)鼠標(biāo),只會(huì)有'a'、'c'會(huì)出現(xiàn),頁(yè)面也不會(huì)滾動(dòng)。說(shuō)明鼠標(biāo)滾輪滾動(dòng)element頁(yè)面的效果是由element的mousewheel默認(rèn)事件處理來(lái)的。這個(gè)時(shí)候留意實(shí)驗(yàn)1中滾輪滾動(dòng)一下'b'的輸出數(shù)量,大概就能猜到默認(rèn)處理的過(guò)程。
4.在element的mousewheel里添加一個(gè)自己的頁(yè)面滾動(dòng)(與默認(rèn)處理的滾動(dòng)方向相反)
element.scrollTop+=e.wheelDelta>0?30:-30;//手動(dòng)添加的頁(yè)面滾動(dòng)
這個(gè)時(shí)候在元素內(nèi)滾動(dòng)鼠標(biāo),你會(huì)發(fā)現(xiàn)即使?jié)L動(dòng)到頂部或底部,元素外的頁(yè)面并不會(huì)滾動(dòng),且并沒(méi)有輸出'd',也就是document的scroll事件沒(méi)有觸發(fā)。不好的一點(diǎn)是你在滾動(dòng)到底部或頂部時(shí),繼續(xù)滾動(dòng)鼠標(biāo)的話,元素內(nèi)還是會(huì)滾動(dòng),只不過(guò)是先下再上(或先上再下)地波動(dòng)一下。
5.在element的mousewheel里添加一個(gè)自己的頁(yè)面滾動(dòng)(與默認(rèn)處理的滾動(dòng)方向相同)
element.scrollTop+=e.wheelDelta<0?30:-30;//手動(dòng)添加的頁(yè)面滾動(dòng)
這個(gè)時(shí)候在元素內(nèi)滾動(dòng)鼠標(biāo),你會(huì)發(fā)現(xiàn)即使?jié)L動(dòng)到頂部或底部,元素外的頁(yè)面跟著滾動(dòng),且輸出'd',也就是document的scroll事件觸發(fā)了。
這里需要注意到一點(diǎn):元素的scrollTop屬性是無(wú)法無(wú)限增加和減少的,到了滾動(dòng)的頂部或底部后只能反向變化(可以自行輸出測(cè)試)。
6.在實(shí)驗(yàn)5的基礎(chǔ)上,將滾動(dòng)的距離調(diào)整到很大
element.scrollTop+=e.wheelDelta<0?300:-300;(值要大等于滾動(dòng)行程)
認(rèn)真觀察輸出的'b'的個(gè)數(shù),和實(shí)驗(yàn)1的對(duì)比,你會(huì)發(fā)現(xiàn)這次只有1個(gè)'b',而且還輸出了'd',而且'd'的數(shù)量還不少。經(jīng)過(guò)一些其他的實(shí)驗(yàn),得到:默認(rèn)事件處理里的判斷大概如下:
(function scroll(element){ ? ? for(var i=0;i<12;i++){ ? ? ? ? var temp=element.scrollTop; ? ? ? ? element.scrollTop+=e.wheelDelta<0?10:-10; //滾動(dòng)算法肯定不是這個(gè),這里只是簡(jiǎn)單演示 ? ? ? ? if(temp!= element.scrollTop){ ? ? ? ? ? ? //滾動(dòng)‘消息樹(shù)'的下一個(gè)元素(和冒泡是一個(gè)列表) ? ? ? ? ? ? var newEle=....//消息樹(shù)怎么獲取我不懂 ? ? ? ? ? ? scroll(newEle); ? ? ? ? ? ? return; ? ? ? ? } ? ? } })();
驗(yàn)證例子:
? ? ? ?addEventListener(element,'mousewheel',function(e){ ? ? ? ? ? ? console.log('a'); ? ? ? ? }); ? ? ? ? addEventListener(element,'scroll',function(e){ ? ? ? ? ? ? console.log('b'); ? ? ? ? }); ? ? ? ? addEventListener(document.documentElement,'mousewheel',function(e){ ? ? ? ? ? ? console.log('c'); ? ? ? ? }); ? ? ? ? addEventListener(document,'scroll',function(e){ ? ? ? ? ? ? console.log('d'); ? ? ? ? });
結(jié)論:通過(guò)上面的6個(gè)實(shí)驗(yàn),很容易發(fā)現(xiàn)在元素的mousewheel的默認(rèn)處理事件里對(duì)scrollTop屬性進(jìn)行變化和判斷,如果沒(méi)有發(fā)生變化就對(duì)外部元素進(jìn)行滾動(dòng)一下(具體滾動(dòng)算法不懂,滾動(dòng)距離和鼠標(biāo)滾一下是一樣的),以此類推,如果下一個(gè)元素到邊界了,就再下一個(gè)。而這個(gè)過(guò)程和冒泡是沒(méi)有關(guān)系的,只是當(dāng)前元素的mousewheel默認(rèn)事件處理進(jìn)行的。
應(yīng)用:因此為了實(shí)現(xiàn)元素滾動(dòng)到底時(shí)繼續(xù)滾動(dòng)卻不會(huì)使外部元素滾動(dòng),我們可以直接取消它的默認(rèn)處理,然后給一個(gè)自己的滾動(dòng)函數(shù)就可以了。至于怎么滾就看自己給什么函數(shù)了,而冒泡取不取消也看自己,上面的默認(rèn)處理在冒泡和捕獲階段是不進(jìn)行的。
例子如下:
? ? ? ?addEventListener(element,'mousewheel',function(e){ ? ? ? ? ? ? console.log('a'); ? ? ? ? ? ? e.preventDefault(); ? ? ? ? ? ? // e.stopPropagation(); ? ? ? ? ? ? ulObj.scrollTop+=e.wheelDelta<0?20:-20; ? ? ? ? }); ? ? ? ? addEventListener(element,'scroll',function(e){ ? ? ? ? ? ? console.log('b'); ? ? ? ? }); ? ? ? ? addEventListener(document.documentElement,'mousewheel',function(e){ ? ? ? ? ? ? console.log('c'); ? ? ? ? }); ? ? ? ? addEventListener(document,'scroll',function(e){ ? ? ? ? ? ? console.log('d'); ? ? ? ? });
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
ssm+vue前后端分離框架整合實(shí)現(xiàn)(附源碼)
這篇文章主要介紹了ssm+vue前后端分離框架整合實(shí)現(xiàn)(附源碼),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07vue項(xiàng)目持久化存儲(chǔ)數(shù)據(jù)的實(shí)現(xiàn)代碼
這篇文章主要介紹了vue項(xiàng)目持久化存儲(chǔ)數(shù)據(jù)的實(shí)現(xiàn)代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-10-10Vue中v-on的基礎(chǔ)用法、參數(shù)傳遞和修飾符的示例詳解
使用v-on:click給button綁定監(jiān)聽(tīng)事件以及回調(diào)函數(shù),@是v-on:的縮寫(xiě),也就是簡(jiǎn)寫(xiě)也可以使用@click,這篇文章主要介紹了Vue中v-on的基礎(chǔ)用法、參數(shù)傳遞和修飾符,需要的朋友可以參考下2022-08-08vite+vue3.0+ts+element-plus快速搭建項(xiàng)目的實(shí)現(xiàn)
本文將結(jié)合實(shí)例代碼,介紹vite+vue3.0+ts+element-plus快速搭建項(xiàng)目的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-06-06全局安裝 Vue cli3 和 繼續(xù)使用 Vue-cli2.x操作
這篇文章主要介紹了全局安裝 Vue cli3 和 繼續(xù)使用 Vue-cli2.x操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-09-09Vue-input框checkbox強(qiáng)制刷新問(wèn)題
這篇文章主要介紹了Vue-input框checkbox強(qiáng)制刷新問(wèn)題,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-04-04