专干老熟女a片,日韩毛片免费无码无毒视频观看,日韩中文字幕免费视频,解开老师裙子猛烈进入动漫

IT技術(shù)

JS控制多個(gè)滾動(dòng)條同步跟隨滾動(dòng)
作者:
來(lái)源: 本站
發(fā)布日期: 2018/8/3 14:22:24
點(diǎn)擊量: 1437次
【 字體:
背景顏色:

在一些支持用 markdown寫(xiě)文章的網(wǎng)站,例如 掘金 或者 CSDN等,后臺(tái)寫(xiě)作頁(yè)面,一般都是支持 markdown即時(shí)預(yù)覽的,也就是將整個(gè)頁(yè)面分成兩部分,左半部分是你輸入的 markdown文字,右半部分則即時(shí)輸出對(duì)應(yīng)的預(yù)覽頁(yè)面。

本文不是闡述如何從 0實(shí)現(xiàn)這種效果的(后續(xù) 很可能 會(huì)單出文章,),拋開(kāi)其他,單看頁(yè)面主體中左右兩個(gè)容器元素,即 markdown輸入框元素和預(yù)覽顯示框元素
本文要探討的是,當(dāng)這兩個(gè)容器元素的內(nèi)容都超出了容器高度,即都出現(xiàn)了滾動(dòng)框的時(shí)候,如何在其中一個(gè)容器元素滾動(dòng)時(shí),讓另外一個(gè)元素也隨之滾動(dòng)。
既然是與滾動(dòng)條有關(guān),那么首先想到 js中控制滾動(dòng)條高度的一個(gè)屬性: scrollTop,只要能控制這個(gè)屬性的值,自然也就能控制滾動(dòng)條的滾動(dòng)了。
對(duì)于以下 DOM結(jié)構(gòu):
其中,.left元素是左半部分輸入框容器元素,.right元素是右半部分顯示框容器元素,.container是它們共同的父元素。
由于需要溢出滾動(dòng),所以還需要設(shè)置一下對(duì)應(yīng)的樣式(只是關(guān)鍵樣式,非全部):
再向 .left和 .right元素中塞入足夠的內(nèi)容,讓二者出現(xiàn)滾動(dòng)條,


樣式是出來(lái)個(gè)大概了,下面就可以在這些 DOM上進(jìn)行一系列的操作了。
大致思路,監(jiān)聽(tīng)兩個(gè)容器元素的滾動(dòng)事件,在其中一個(gè)元素滾動(dòng)的時(shí)候,獲取這個(gè)元素的 scrollTop屬性的值,同時(shí)將此值設(shè)置為另外一個(gè)滾動(dòng)元素的 scrollTop值即可。
似乎很不錯(cuò),但是現(xiàn)在是不僅想讓右邊跟隨左邊滾動(dòng),還想左邊跟隨右邊滾動(dòng),于是再加以下代碼:
看上去很不錯(cuò),然而,哪有那么簡(jiǎn)單的事情。
這個(gè)時(shí)候你再用鼠標(biāo)滾輪進(jìn)行滾動(dòng)的時(shí)候,卻發(fā)現(xiàn)滾動(dòng)得有點(diǎn)吃力,兩個(gè)容器元素的滾動(dòng)似乎被什么阻礙住了,很難滾動(dòng)。
仔細(xì)分析,原因很簡(jiǎn)單,當(dāng)你在左邊滾動(dòng)的時(shí)候,觸發(fā)了左邊的滾動(dòng)事件,于是右邊跟隨滾動(dòng),但是與此同時(shí)右邊的跟隨滾動(dòng)也是滾動(dòng),于是也觸發(fā)了右邊的滾動(dòng),于是左邊也要跟隨右邊滾動(dòng)…然后就進(jìn)入了一個(gè)類似于相互觸發(fā)的情況,所以就會(huì)發(fā)現(xiàn)滾動(dòng)得很吃力。
想要解決上述問(wèn)題,暫時(shí)有以下兩種方案。
由于 scroll事件不僅會(huì)被鼠標(biāo)主動(dòng)滾動(dòng)觸發(fā),同時(shí)改變?nèi)萜髟氐?scrollTop也會(huì)觸發(fā),元素的主動(dòng)滾動(dòng)其實(shí)就是鼠標(biāo)滾輪觸發(fā)的,所以可以將scroll事件換成一個(gè)對(duì)鼠標(biāo)滾動(dòng)敏感而不是元素滾動(dòng)敏感的事件:’mousewheel’。

似乎是有點(diǎn)用,但是實(shí)際上還有兩個(gè)問(wèn)題。
在網(wǎng)上找了一圈,沒(méi)有找到關(guān)于 wheel事件滾動(dòng)頻率相關(guān)內(nèi)容,我推測(cè)這可能就是此事件的一個(gè) feature
鼠標(biāo)每次滾動(dòng)基本上都并不是以 1px為單位的,其最小單元遠(yuǎn)比 scroll事件小的多,我用我的鼠標(biāo)在 chrome瀏覽器上滾動(dòng),每次滾過(guò)的距離都恰好是 100px,不同的鼠標(biāo)或者瀏覽器這個(gè)數(shù)值應(yīng)該都是不一樣的。
如果你的鼠標(biāo)質(zhì)量比較好,齒輪比較精細(xì),那么應(yīng)該就會(huì)小于 100px, 跳動(dòng)也就不會(huì)那么大,我的鼠標(biāo)是公司給配的電腦自帶的,作用只限于能用,所以齒輪刻度比較大。
而 wheel事件其實(shí)真正監(jiān)聽(tīng)的是鼠標(biāo)滾輪滾過(guò)一個(gè)齒輪卡點(diǎn)的事件,這也就能解釋為何會(huì)出現(xiàn)彈跳的現(xiàn)象了。


一般來(lái)說(shuō),鼠標(biāo)滾輪每滾過(guò)一個(gè)齒輪卡點(diǎn),就能監(jiān)聽(tīng)到一個(gè)wheel事件,從開(kāi)始到結(jié)束,被鼠標(biāo)主動(dòng)滾動(dòng)的元素已經(jīng)滾動(dòng)了 100px,所以另外一個(gè)跟隨滾動(dòng)的容器元素也就瞬間跳動(dòng)了 100px
而之所以上述 scroll事件不會(huì)讓跟隨滾動(dòng)元素出現(xiàn)瞬間彈跳,則是因?yàn)楦S滾動(dòng)元素每次 scrollTop發(fā)生變化時(shí),其值不會(huì)有 100px那么大的跨度,可能也沒(méi)有小到1px,但由于其觸發(fā)頻率高,滾動(dòng)跨度小,最起碼在視覺(jué)上就是平滑滾動(dòng)的了。
如果你想讓右側(cè)滾動(dòng)框也平滑滾動(dòng),也是可以做到的,當(dāng)每次監(jiān)聽(tīng)到 wheel事件的時(shí)候,也別管它相比于上次是差了100px還是50px的,始終都讓右側(cè)的跟隨滾動(dòng)框按照 10px(或者再稍大點(diǎn)或者稍小點(diǎn)的跨度,只要給人視覺(jué)上的感受是平滑滾動(dòng)并且延遲不是太大就行了)來(lái)滾動(dòng),連續(xù)滾動(dòng)10次,那就是100px了,同樣能到達(dá)準(zhǔn)確的位置,例如如下代碼:
這個(gè)其實(shí)很好解決,用鼠標(biāo)拖動(dòng)滾動(dòng)條肯定是能觸發(fā) scroll事件的,而在這種情況下,你肯定能夠很輕易地判斷出這個(gè)被拖動(dòng)的滾動(dòng)條是屬于哪個(gè)容器元素的,只需要處理這個(gè)容器的滾動(dòng)事件,另外一個(gè)跟隨滾動(dòng)容器的滾動(dòng)事件不做處理即可。
wheel事件是 DOM Level3的標(biāo)準(zhǔn)事件,但是除了此事件之外,還有很多非標(biāo)準(zhǔn)事件,不同的瀏覽器內(nèi)核使用不同的標(biāo)準(zhǔn),所以可能還需要按情況來(lái)進(jìn)行兼容,具體可見(jiàn) MDN MouseWheelEvent

如果你難以忍受 wheel的彈跳,以及各種兼容,那么其實(shí)還有另外的路可以走得通,依舊是 scroll事件,只不過(guò)需要做一些額外的工作。
scroll事件的問(wèn)題在于,沒(méi)有判斷當(dāng)前主動(dòng)滾動(dòng)的是哪一個(gè)容器元素,只要確定了主動(dòng)滾動(dòng)的容器元素,這事就好辦了,例如上述使用 wheel事件中,用鼠標(biāo)拖動(dòng)滾動(dòng)條之所以能夠使用 scroll事件,就是因?yàn)槟軌蚝苋菀椎卮_定當(dāng)前主動(dòng)滾動(dòng)容器元素是哪一個(gè)。
所以,問(wèn)題的關(guān)鍵在于,如何判斷出當(dāng)前主動(dòng)滾動(dòng)的容器元素,只要解決了這個(gè)問(wèn)題,剩下的就很好辦了。
不論是鼠標(biāo)滾輪滾動(dòng)還是鼠標(biāo)按在滾動(dòng)條上拖動(dòng)滾動(dòng)條滾動(dòng),都會(huì)觸發(fā) scroll事件,并且這個(gè)時(shí)候,在坐標(biāo)系 Z軸上,鼠標(biāo)的坐標(biāo)肯定是位于滾動(dòng)容器元素所占的面積之內(nèi)的,也就是說(shuō),在 Z軸上,鼠標(biāo)肯定是懸浮或者位于滾動(dòng)容器元素之上。
鼠標(biāo)在屏幕上移動(dòng)的時(shí)候,是可以獲取到鼠標(biāo)當(dāng)前坐標(biāo)的。

其中,clientX和 clientY就是當(dāng)前鼠標(biāo)相對(duì)于視口的坐標(biāo),可以認(rèn)為,只要這個(gè)坐標(biāo)在某個(gè)滾動(dòng)容器的范圍內(nèi),則認(rèn)為這個(gè)容器元素就是主動(dòng)滾動(dòng)容器元素,容器元素的坐標(biāo)范圍可以使用 getBoundingClientRect進(jìn)行獲取。
這樣確實(shí)是可以的,不過(guò)考慮到兩個(gè)滾動(dòng)容器元素幾乎占據(jù)了整個(gè)屏幕面積,所以 mousemove所要監(jiān)聽(tīng)的面積未免有點(diǎn)大,對(duì)于性能可能要求較高,所以其實(shí)可以換成 mouseover事件,只需要監(jiān)聽(tīng)鼠標(biāo)有沒(méi)有進(jìn)入到某個(gè)滾動(dòng)容器元素即可,也省去上述的坐標(biāo)判斷了。
當(dāng)確定了鼠標(biāo)主動(dòng)滾動(dòng)的容器元素是哪一個(gè)時(shí),只需要處理這個(gè)容器的滾動(dòng)事件,另外一個(gè)跟隨滾動(dòng)容器的滾動(dòng)事件不做處理即可。

嗯,效果很不錯(cuò),性能也很好,perfect,可以收工嘍~
那一屋!
事情沒(méi)有那么簡(jiǎn)單!


上面全部是在兩個(gè)滾動(dòng)容器元素的內(nèi)容高度完全一致的情況下的效果,如果這兩個(gè)滾動(dòng)容器元素的內(nèi)容高度不同呢?

可見(jiàn),由于兩個(gè)滾動(dòng)容器元素的內(nèi)容高度不同,所以最大的 scrollTop也就不同,就會(huì)出現(xiàn)當(dāng)其中一個(gè) scrollTop值較小的元素滾到底時(shí),另外一個(gè)元素還停留在一半,或者當(dāng)其中一個(gè) scrollTop值較大的元素才滾到一半時(shí),另外一個(gè)元素就已經(jīng)滾到底了。
這種情況很常見(jiàn),例如你用 markdown寫(xiě)作時(shí),一個(gè)一級(jí)標(biāo)題標(biāo)記 #在編輯模式下占用的高度,一般都是小于預(yù)覽模式占用的高度的,這樣就出現(xiàn)了左右兩側(cè)滾動(dòng)高度不一致的情況。
所以,如果將這種情況也考慮進(jìn)來(lái)的話,那么就不能簡(jiǎn)單地為兩個(gè)滾動(dòng)容器元素相互設(shè)置 scrollTop值那么簡(jiǎn)單。
雖然無(wú)法固定住滾動(dòng)容器內(nèi)容的高度,但是有一點(diǎn)可以確定,滾動(dòng)條最大滾動(dòng)高度,或者說(shuō) scrollTop的值,肯定是與滾動(dòng)容器內(nèi)容的高度與滾動(dòng)容器本身的高度呈一定的關(guān)系。
由于需要知道滾動(dòng)容器內(nèi)容的高度,還要存在滾動(dòng)條,所以需要給此容器元素加個(gè)子元素,子元素高度不限,就是滾動(dòng)容器內(nèi)容的高度,容器高度固定,溢出滾動(dòng)即可。
結(jié)構(gòu)示例如下:

通過(guò)我的觀察推論與實(shí)踐驗(yàn)證,已經(jīng)確定下來(lái)了它們之間的關(guān)系,很簡(jiǎn)單,就是最基本的加減法運(yùn)算:
也就是說(shuō),如果已經(jīng)確定了滾動(dòng)容器內(nèi)容的高度(即子元素高度ch)與滾動(dòng)容器本身的高度(即容器元素高度ph),那么就一定能確定滾動(dòng)條的最大滾動(dòng)高度(scrollTop),而這兩個(gè)高度值基本上都是可以獲取到的,所以就能得到 scrollTop
因此,想要讓兩個(gè)滾動(dòng)元素容器等比例上下滾動(dòng),即其中一個(gè)元素滾到頭或者滾到底,另外一個(gè)元素也能對(duì)應(yīng)滾到頭和滾到底,那么只要得到這兩個(gè)滾動(dòng)容器元素之間的 scrollTop最大值的比例(scale)就行了。
確定了 scale之后,實(shí)時(shí)滾動(dòng)時(shí),只需要獲取主動(dòng)滾動(dòng)容器元素的 scrollTop1,就能得到另外一個(gè)跟隨滾動(dòng)的容器元素對(duì)應(yīng)的 scrollTop2:
思路弄清晰了,寫(xiě)代碼就是很容易的事情了。
上述基本上已經(jīng)實(shí)現(xiàn)了需求,可能在實(shí)踐過(guò)程中還需要根據(jù)實(shí)際情況來(lái)進(jìn)行一定的修改,例如如果你編寫(xiě)一個(gè) markdown的在線編輯和預(yù)覽頁(yè)面,就需要根據(jù)輸入內(nèi)容的高度實(shí)時(shí)更新 scale值,不過(guò)主體已經(jīng)搞定,小修小改就沒(méi)什么難度了。
另外,本文所述不僅是針對(duì)兩個(gè)滾動(dòng)容器元素的跟隨滾動(dòng),同時(shí)也可擴(kuò)展開(kāi)來(lái),更多的元素間的跟隨滾動(dòng)都是可以根據(jù)本文思路來(lái)實(shí)現(xiàn)的,本文只是為了方便講解而具體到了兩個(gè)元素上。
掃一掃在手機(jī)打開(kāi)當(dāng)前頁(yè)

Contact

聯(lián)系我們

告訴我們您想要的吧!我們?yōu)楫?dāng)?shù)乜蛻籼峁I(yè)、及時(shí)的服務(wù)
地址:云南省昆明市白云路368號(hào)
電話:400-871-8716 (工作時(shí)間:09:00-18:00(周一至周五))
何總:23592693
李總:53815112
主站蜘蛛池模板: 昂仁县| 郑州市| 交口县| 六枝特区| 伊金霍洛旗| 平武县| 游戏| 哈尔滨市| 雷山县| 达日县| 二连浩特市| 敦煌市| 靖宇县| 象山县| 邵武市| 荥阳市| 固镇县| 七台河市| 东丰县| 关岭| 江华| 彭水| 石泉县| 富顺县| 定襄县| 高邑县| 屏边| 湘阴县| 威远县| 安陆市| 化州市| 舒城县| 兴安盟| 昌吉市| 江油市| 溧水县| 莫力| 道孚县| 吕梁市| 永川市| 哈尔滨市|