案發(fā)現(xiàn)場(chǎng)
今天給后臺(tái)的表格組件替換為一個(gè)前同事寫的表格組件,替換完發(fā)現(xiàn)除了滾動(dòng)條不能用鼠標(biāo)滾動(dòng)以外,其他都沒什么大問題。我是一個(gè)跟任何東西都可以較勁的人,我不信一個(gè)小小的滾動(dòng)條還能奈我何?于是就發(fā)生了這個(gè)血案。從看源碼,到問前同事,足足浪費(fèi)了我一個(gè)下午來找問題,深深地感到自己的能力是如此的不足。
案發(fā)詳情
滾動(dòng)條歸屬的問題。
我們都知道,如何頁(yè)面超過了瀏覽器窗口的大小,瀏覽器會(huì)自動(dòng)生成一個(gè)滾動(dòng)條。這個(gè)滾動(dòng)條是屬于誰的?是屬于html元素還是body元素的?
都不是!!
當(dāng)一個(gè)子元素超過了其父元素的限定高度并且在父元素設(shè)置了overflow:auto或者overflow:scroll父元素容器就會(huì)產(chǎn)生一個(gè)滾動(dòng)條,這個(gè)滾動(dòng)條毫無疑問是歸屬于父元素的。直接看demo01,以下是demo01的主要代碼:
<div class="parent">
parent
<div class="child">
child
</div>
</div>
body{
margin:0;
}
.parent{
height:400px;
border:1px solid #ddd;
overflow:auto;
}
.child{
height:800px;
background-color:#eee;
}
可以看到,child撐開了parent的高度,于是parent生成了滾動(dòng)條,滾動(dòng)條屬于parent,這個(gè)是沒有爭(zhēng)議的。
如何判斷滾動(dòng)條的歸屬呢?
一種直觀的方法:可以通過控制臺(tái)的Element面板,把鼠標(biāo)hover在parent元素上,可以看到滾動(dòng)條是在元素內(nèi)部的。(在Mac下,滾動(dòng)條的表現(xiàn)形式不太一樣,只有滾動(dòng)的時(shí)候才會(huì)出現(xiàn)滾動(dòng)條,沒有滾動(dòng)時(shí)自動(dòng)隱藏)
另一種方法是可以通過對(duì)元素添加scroll監(jiān)聽事件來判斷。
如果是body下的直接子元素的高度超過了body的限定高度,并且給body增加overflow :auto,這時(shí)生成的滾動(dòng)條是屬于誰的?看一下例子demo02,以下是主要代碼:
<div class="child">
Child
</div>
html, body{
height:100%;
}
body{
margin:0;
overflow:auto;
}
.child{
height:1000px;
background-color:#eee;
}
咦,好像滾動(dòng)條并不屬于body元素??確實(shí)不屬于body,也不屬于html。Mac下按照上面第一種方法觀察,滾動(dòng)條好像是屬于html元素的,但其實(shí)不然,可以通過給元素添加scroll事件的監(jiān)聽就可以發(fā)現(xiàn),滾動(dòng)的時(shí)候并不會(huì)觸發(fā)html元素或者body元素的scroll事件。
//監(jiān)聽window窗口的滾動(dòng)事件
window.addEventListener('scroll', (e) => {
console.log('window');
})
//監(jiān)聽document對(duì)象的滾動(dòng)事件
document.addEventListener('scroll', (e) => {
console.log('document');
})
//監(jiān)聽html元素的滾動(dòng)事件
document.documentElement.addEventListener('scroll', (e) => {
console.log('html');
})
//監(jiān)聽body元素的滾動(dòng)事件
document.body.addEventListener('scroll', (e) => {
console.log('body');
})
上面的四個(gè)監(jiān)聽器,滾動(dòng)的時(shí)候只有前兩個(gè)才會(huì)被觸發(fā),所以證明滾動(dòng)條是屬于document對(duì)象的。
為什么window也能監(jiān)聽到scroll事件呢?這是因?yàn)?strong>事件冒泡
當(dāng)html元素也添加overflow:auto時(shí),滾動(dòng)條會(huì)是誰的呢?看例子demo03
這時(shí),滾動(dòng)條貌似是屬于body的?是的沒錯(cuò),就是屬于body的,用監(jiān)聽器來監(jiān)聽一下滾動(dòng)事件,只會(huì)觸發(fā)document.body的監(jiān)聽器,而不會(huì)觸發(fā)window和document的。
為什么會(huì)這樣?應(yīng)該不僅只有我一個(gè)人才發(fā)現(xiàn)滾動(dòng)條這個(gè)坑的吧?TAT
先來回顧一下overflow有哪些值:
/* 默認(rèn)值。內(nèi)容不會(huì)被修剪,會(huì)呈現(xiàn)在元素框之外*/
overflow: visible;
/* 內(nèi)容會(huì)被修剪,并且其余內(nèi)容不可見 */
overflow: hidden;
/* 內(nèi)容會(huì)被修剪,瀏覽器會(huì)顯示滾動(dòng)條以便查看其余內(nèi)容 */
overflow: scroll;
/* 由瀏覽器定奪,如果內(nèi)容被修剪,就會(huì)顯示滾動(dòng)條 */
overflow: auto;
/* 規(guī)定從父元素繼承overflow屬性的值 */
overflow: inherit;
于是得出結(jié)論(也可以說個(gè)人猜測(cè),因?yàn)椴灰欢ㄕ_):
html和body僅有一個(gè)元素會(huì)產(chǎn)生滾動(dòng)條時(shí),這個(gè)滾動(dòng)條會(huì)默認(rèn)歸屬于document
當(dāng)html和body元素的overflow屬性都是默認(rèn)值auto時(shí),因?yàn)?code>body高度可能超過html的高度,這時(shí)就會(huì)產(chǎn)生一個(gè)滾動(dòng)條,這個(gè)滾動(dòng)條屬于document的,所以如果body再產(chǎn)生一個(gè)滾動(dòng)條,就只能是屬于body自己的了。
鼠標(biāo)滾輪事件
頁(yè)面出現(xiàn)滾動(dòng)條時(shí),我們可以用鼠標(biāo)滾輪來對(duì)頁(yè)面進(jìn)行縱向滾動(dòng),那是否可以組織這個(gè)滾動(dòng)行為呢?
肯定是可以的。e.preventDefault()就是阻止事件的默認(rèn)行為,在mousewheel事件監(jiān)聽里加上這句,就能阻止鼠標(biāo)滾輪觸發(fā)滾動(dòng)事件了。
因?yàn)檫@個(gè),讓我在組件源碼里折騰了好一會(huì),當(dāng)然不是不知道e.preventDefault(),是忽略了它的作用。
因?yàn)楣ぷ髅Γ@篇文章前后寫了好久,當(dāng)時(shí)的一些思路靈感都已經(jīng)消逝了,寫不下去了,先到這為止吧,之后有想起什么遺漏的再補(bǔ)上。