久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

微信里面防止下拉“露底”組件

 dxw121 2016-12-29

前言

在微信里面瀏覽頁面的時(shí)候,,有一個(gè)很管用的方法可以區(qū)分這個(gè)頁面是原生的還是H5形式的。隨便打開一個(gè)頁面,,用力往下扯的時(shí)候,,如果頁面上方出現(xiàn)了“黑底”,黑底上有一行諸如網(wǎng)頁由game.weixin.qq.com提供的文字,,就表明這個(gè)頁面是H5形式的,。這帶來的問題是,如果一個(gè)頁面可滾動(dòng)區(qū)域很小,,隨便一拉,,頁面下方出現(xiàn)了黑底,然后你又輕輕往上一拉,,上面的黑底又出來了,,個(gè)人表示非常難受啊,!
于是乎,,折騰了一番,,寫了一個(gè)簡單的組件來實(shí)現(xiàn)禁止這種拉動(dòng)頁面出現(xiàn)黑底的特性。

實(shí)現(xiàn)原理

首先需要說明的是,,由于Android和IOS的webview存在差異,,這個(gè)組件對于IOS是比較友好的,安卓下并不能做到完美避免,,下面一一分析,。

簡述touch事件

智能手機(jī)和平板電腦一類的移動(dòng)設(shè)備通常會(huì)有一個(gè)電容式觸摸屏(capacitive touch-sensitive screen),以捕捉用戶的手指所做的交互,。有三種在規(guī)范中列出并獲得跨移動(dòng)設(shè)備廣泛實(shí)現(xiàn)的基本觸摸事件:

  • touchstart :手指放在一個(gè)DOM元素上

  • touchmove :手指拖曳一個(gè)DOM元素

  • touchend :手指從一個(gè)DOM元素上移開

其中每一個(gè)觸摸事件都會(huì)包含三個(gè)觸摸列表:

  • touches :當(dāng)前位于屏幕上的所有手指的一個(gè)列表,。

  • targetTouches :位于當(dāng)前DOM元素上的手指的一個(gè)列表。

  • changedTouches :涉及當(dāng)前事件的手指的一個(gè)列表,。

這些列表由包含了觸摸信息的對象組成:

  • identifier :一個(gè)數(shù)值,,唯一標(biāo)識觸摸會(huì)話(touch session)中的當(dāng)前手指。

  • target :DOM元素,,是動(dòng)作所針對的目標(biāo),。

  • 客戶/頁面/屏幕坐標(biāo) :動(dòng)作在屏幕上發(fā)生的位置。

  • 半徑坐標(biāo)和 rotationAngle :畫出大約相當(dāng)于手指形狀的橢圓形,。
    在jsfiddle里面寫一個(gè)簡單的小demo就一目了然了:

http:///yuanzm/ws9j4v1v/2/

在這個(gè)組件中,,我們只需要用到e.touches[0].clientY屬性就夠了:在開始觸摸的時(shí)候,記錄觸摸點(diǎn)的起始位置,,在手指移動(dòng)過程中,,不斷獲取最新的clientY,與起始位置的clientY比較,,就能獲知拉動(dòng)頁面的方向,。

與height相關(guān)的幾個(gè)屬性

  • scrollHeight: 是計(jì)量元素內(nèi)容高度的只讀屬性,包括overflow樣式屬性導(dǎo)致的視圖中不可見內(nèi)容,。沒有垂直滾動(dòng)條的情況下,scrollHeight值與元素視圖填充所有內(nèi)容所需要的最小值clientHeight相同,。包括元素的padding,,但不包括元素的margin.

  • offsetHeight:是一個(gè)只讀屬性,它返回該元素的像素高度,,高度包含該元素的垂直內(nèi)邊距和邊框,,且是一個(gè)整數(shù)。

  • scrollTop:設(shè)置獲取讀取元素向上滾動(dòng)了多少像素,。對于可滾動(dòng)的元素,,這個(gè)值是可見區(qū)域頂部和不可見區(qū)域頂部的距離。如果元素不能滾動(dòng),,這個(gè)值默認(rèn)為0,。

這三個(gè)屬性是用來計(jì)算元素處于頁面的哪個(gè)位置的,考慮下面兩種情況:

  • 元素的offsetHeight大于等于scrollHeight,無縱向滾動(dòng)條出現(xiàn),,這個(gè)元素是不能滾動(dòng)的,。如果一個(gè)元素不能滾動(dòng)了,就會(huì)嘗試外層的元素能不能滾動(dòng),,一層一層往外冒泡,。在webview里面,最外面一層就是這個(gè)webview容器了,,按照微信的設(shè)置,,這一層的“滾動(dòng)”就是露出下面的黑底。所以為了避免露出黑底,,我們要在當(dāng)前元素不能滾動(dòng)的時(shí)候及時(shí)禁止掉冒泡,,這樣就不會(huì)觸發(fā)到上一層的滾動(dòng)。

  • 如果一個(gè)元素設(shè)置了高度,,并且設(shè)置了overflow: scroll,,當(dāng)元素內(nèi)的內(nèi)容可滾動(dòng)的時(shí)候,scrollHeight的值就會(huì)明顯大于offsetheight,,那我們怎么判斷元素內(nèi)的內(nèi)容下拉到底部了呢,?這就需要綜合offsetHeight和scrollTop的值了,如果offsetHeight的值加上srcollTop的值大于等于scrollHeight的值,,就表明內(nèi)容已經(jīng)滑動(dòng)底部了,。和第一點(diǎn)一樣,當(dāng)我們知道了臨界條件后,,及時(shí)阻止掉冒泡就ok了,。

結(jié)合touch和height屬性

通過上面兩點(diǎn),我們已經(jīng)知道要達(dá)到禁止出現(xiàn)黑底的效果,,努力的方向是在知道滑動(dòng)方向的條件下,,在與height相關(guān)的屬性達(dá)到臨界值的時(shí)候及時(shí)阻止事件冒泡。只有三種簡單的情況:

  • (內(nèi)容)向下拉到底部,,不能往下拉,,但是可以往上拉

  • (內(nèi)容)向上拉到頂部,不能往上拉,,但是可以往下拉

  • (內(nèi)容)既不能往下拉也不能往下拉

總結(jié)起來如下表(1為允許,,0為禁止,高位表示向上方向,,低位表示向下方向)

可以拉的方向(height) 拉的方向(touch) 能否繼續(xù)拉
00 10 0
00 01 0
01 10 0
01 01 1
10 10 1
10 01 0

從表中我們可以得出一個(gè)結(jié)論是,,能否在該方向上繼續(xù)拉其實(shí)就是對兩種條件做一個(gè)&運(yùn)算!話不多說,,上核心源碼

        // 防止過分拉動(dòng)
        preventMove: function(e) {
            // 高位表示向上滾動(dòng), 底位表示向下滾動(dòng): 1容許 0禁止
            var status = '11', 
                e = e || window.event, // 使用 || 運(yùn)算取得event對象
                ele = this,
                currentY = e.touches[0].clientY,
                startY = startMoveYmap[ele.id],
                scrollTop = ele.scrollTop,
                offsetHeight = ele.offsetHeight,
                scrollHeight = ele.scrollHeight;

            if (scrollTop === 0) {
                // 如果內(nèi)容小于容器則同時(shí)禁止上下滾動(dòng)
                status = offsetHeight >= scrollHeight ? '00' : '01';
            } else if (scrollTop + offsetHeight >= scrollHeight) {
                // 已經(jīng)滾到底部了只能向上滾動(dòng)
                status = '10';
            }
            if (status != '11') {
                // 判斷當(dāng)前的滾動(dòng)方向
                var direction = currentY - startY > 0 ? '10' : '01';
                // console.log(direction);
                // 操作方向和當(dāng)前允許狀態(tài)求與運(yùn)算,,運(yùn)算結(jié)果為0,,就說明不允許該方向滾動(dòng),則禁止默認(rèn)事件,,阻止?jié)L動(dòng)
                if (!(parseInt(status, 2) & parseInt(direction, 2))) {
                    e.preventDefault();
                    e.stopPropagation();
                    return;
                }
            }
        },

與UI共用的線程

開始的時(shí)候,,我以為上面的代碼就萬事大吉了,經(jīng)過實(shí)踐和摸索,,結(jié)論是:簡直是天真,。

異步的概念之所以首先在Web2.0中火起來,是因?yàn)樵跒g覽器中JavaScript在單線程上執(zhí)行,,而且它還與UI渲染共用一個(gè)UI線程,。這意味著JavaScript在執(zhí)行的時(shí)候UI渲染和響應(yīng)是處于停滯狀態(tài)的。 ----《深入淺出nodejs》

這意味這什么呢,?當(dāng)我們的UI線程在進(jìn)行渲染的時(shí)候,,JavaScript代碼也是處于停滯狀態(tài)的!不信的話可以在一個(gè)可以滑動(dòng)的頁面上引入下面這段代碼:

var count = 0;
setInterval(functiong() {
    console.log(++count);
}, 100);

刷新頁面的時(shí)候,,控制臺(tái)會(huì)一直打印不斷變大的數(shù)字,,但是只要你用手指開始拖動(dòng)頁面,打印終止,,等你把手放開的時(shí)候,,打印繼續(xù),而且數(shù)字會(huì)承接打印停止前那個(gè)數(shù)字,。也就是UI在渲染的時(shí)候,,js保存了狀態(tài),在UI渲染停止的時(shí)候,,js又可以繼續(xù)運(yùn)行,。
這對我們的組件帶來的影響是什么呢?幾乎是毀滅性的,,場景如下:

  • 如果頁面內(nèi)容不足一屏,,按照組件的設(shè)定,既不能上拉也不能下拉,,這種情況不會(huì)受影響,。

  • 如果頁面內(nèi)容多于一屏,按照組件的設(shè)定,,這時(shí)候可以往下拉不能往上拉,在嘗試上拉的時(shí)候,,組件會(huì)阻止冒泡,。但如果先下拉一點(diǎn)然后使勁往上拉,本來拉到頂之后組件會(huì)阻止事件冒泡,,但是一旦下拉之后,,線程就歸屬于UI了,,上拉的過程中組件的判斷完全插不進(jìn)手,還是無情漏出了黑底,!GG,!

可愛的IOS5新特性

在尋求最終的解決方案之前,我們先來討論一下overflow這個(gè)屬性,。

傳統(tǒng) pc 端中,,子容器高度超出父容器高度,通常使用 overflow:auto 可出現(xiàn)滾動(dòng)條拖動(dòng)顯示溢出的內(nèi)容,,而移動(dòng)web開發(fā)中,,由于瀏覽器廠商的系統(tǒng)不同、版本不同,,導(dǎo)致有部分機(jī)型不支持對彈性滾動(dòng),,從而在開發(fā)中制造了所謂的 BUG。

從本人這兩個(gè)月移動(dòng)Web實(shí)踐的經(jīng)驗(yàn)來看,,微信的webview里面overflow: scrolloverflow: auto的滑動(dòng)效果無論是在安卓還是IOS下的體驗(yàn)都很一般,,有明顯的卡頓現(xiàn)象,在安卓下面還會(huì)出現(xiàn)滑動(dòng)過快的時(shí)候在頁面停下來之后滾動(dòng)條才閃到相應(yīng)位置的現(xiàn)象,。
在IOS5之后,,出現(xiàn)了一個(gè)新的屬性: -webkit-overflow-scrolling,用來控制元素在移動(dòng)設(shè)備上是否使用滾動(dòng)回彈效果。它的取值有兩個(gè):

  • auto:使用普通滾動(dòng), 當(dāng)手指從觸摸屏上移開,,滾動(dòng)會(huì)立即停止,。

  • touch:使用具有回彈效果的滾動(dòng), 當(dāng)手指從觸摸屏上移開,內(nèi)容會(huì)繼續(xù)保持一段時(shí)間的滾動(dòng)效果,。繼續(xù)滾動(dòng)的速度和持續(xù)的時(shí)間和滾動(dòng)手勢的強(qiáng)烈程度成正比,。同時(shí)也會(huì)創(chuàng)建一個(gè)新的堆棧上下文。

實(shí)驗(yàn)表明,,在IOS下,,對一個(gè)元素設(shè)置了overflow:scroll的基礎(chǔ)上再添加-webkit-overflow-scrolling: touch;會(huì)讓滑動(dòng)又如絲般順滑。
這個(gè)屬性和我們解決之前的問題有什么聯(lián)系呢,?秘密就在這彈性滾動(dòng)效果,。

原始場景

頁面中body元素的內(nèi)容超過一屏,頁面可以往下滑動(dòng)(手指往上拉),。按照我們組件的設(shè)定,,手指開始的時(shí)候是不能往下拉的,但是如果手指的方向是先往上拉一小段,,在手指不離開屏幕的基礎(chǔ)上再往下拉,,當(dāng)頁面拉到頂部的時(shí)候,會(huì)相繼出現(xiàn)黑底,,因?yàn)閁I在渲染,,js沒法去阻止事件冒泡,。

改進(jìn)場景

現(xiàn)在我們把組件的作用元素設(shè)定為body內(nèi)最外圍的div元素,并且給這個(gè)元素添加兩個(gè)CSS屬性overflow:scroll-webkit-overflow-scrolling: touch;,,那么上面的場景就會(huì)變成:
頁面中body內(nèi)最外圍的div標(biāo)簽內(nèi)容超過一屏,,其內(nèi)容可以往下滑動(dòng)(手指往上拉)。按照我們組件的設(shè)定,,手指開始的時(shí)候是不能往下拉的,。和之前一樣,手指先往上拉一小段,,在手指不離開該元素的基礎(chǔ)上再往下拉,,當(dāng)元素內(nèi)容到頂之后,因?yàn)閁I在渲染,,js本插不上手,,但是該元素內(nèi)部的內(nèi)容設(shè)置了彈性滾動(dòng),要實(shí)現(xiàn)彈性滾動(dòng),,基本要求就是這個(gè)div容器是不動(dòng)的,,可以理解成因?yàn)閺椥詽L動(dòng),自動(dòng)就禁止掉了事件冒泡,也就不會(huì)出現(xiàn)黑底了,。

肯定有人要問了,,既然自動(dòng)禁止了事件冒泡,那還要這個(gè)組件何用,?當(dāng)然有用,,會(huì)禁止掉事件冒泡的前提是內(nèi)容在滾動(dòng)。依照上面的場景,,如果一開始手指直接往下拉,,沒有組件的限制,還是會(huì)露出黑底,,因而,,要實(shí)現(xiàn)比較好的效果,是需要這兩個(gè)屬性和組件配合的,。
至于安卓嘛,,因?yàn)闆]有這個(gè)屬性,暫時(shí)只能一邊涼快去吧,。

小結(jié)

多說無用,,看源碼吧:
https://github.com/yuanzm/preventoverscrolljs

參考

    本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn),。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多