成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

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

hot_pot_Leo / 976人閱讀

摘要:從本人這兩個(gè)月移動(dòng)實(shí)踐的經(jīng)驗(yàn)來(lái)看,微信的里面和的滑動(dòng)效果無(wú)論是在安卓還是下的體驗(yàn)都很一般,有明顯的卡頓現(xiàn)象,在安卓下面還會(huì)出現(xiàn)滑動(dòng)過(guò)快的時(shí)候在頁(yè)面停下來(lái)之后滾動(dòng)條才閃到相應(yīng)位置的現(xiàn)象。

前言

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

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

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

簡(jiǎn)述touch事件

智能手機(jī)和平板電腦一類(lèi)的移動(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元素上移開(kāi)

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

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

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

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

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

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

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

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

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

http://jsfiddle.net/yuanzm/ws9j4v1v/2/

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

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

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

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

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

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

元素的offsetHeight大于等于scrollHeight,無(wú)縱向滾動(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,那我們?cè)趺磁袛嘣貎?nèi)的內(nèi)容下拉到底部了呢?這就需要綜合offsetHeight和scrollTop的值了,如果offsetHeight的值加上srcollTop的值大于等于scrollHeight的值,就表明內(nèi)容已經(jīng)滑動(dòng)底部了。和第一點(diǎn)一樣,當(dāng)我們知道了臨界條件后,及時(shí)阻止掉冒泡就ok了。

結(jié)合touch和height屬性

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

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

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

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

總結(jié)起來(lái)如下表(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í)就是對(duì)兩種條件做一個(gè)&運(yùn)算!話不多說(shuō),上核心源碼

        // 防止過(guò)分拉動(dòng)
        preventMove: function(e) {
            // 高位表示向上滾動(dòng), 底位表示向下滾動(dòng): 1容許 0禁止
            var status = "11", 
                e = e || window.event, // 使用 || 運(yùn)算取得event對(duì)象
                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,就說(shuō)明不允許該方向滾動(dòng),則禁止默認(rèn)事件,阻止?jié)L動(dòng)
                if (!(parseInt(status, 2) & parseInt(direction, 2))) {
                    e.preventDefault();
                    e.stopPropagation();
                    return;
                }
            }
        },
與UI共用的線程

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

異步的概念之所以首先在Web2.0中火起來(lái),是因?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)的頁(yè)面上引入下面這段代碼:

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

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

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

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

可愛(ài)的IOS5新特性

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

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

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

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

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

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

原始場(chǎng)景

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

改進(jìn)場(chǎng)景

現(xiàn)在我們把組件的作用元素設(shè)定為body內(nèi)最外圍的div元素,并且給這個(gè)元素添加兩個(gè)CSS屬性overflow:scroll-webkit-overflow-scrolling: touch;,那么上面的場(chǎng)景就會(huì)變成:
頁(yè)面中body內(nèi)最外圍的div標(biāo)簽內(nèi)容超過(guò)一屏,其內(nèi)容可以往下滑動(dòng)(手指往上拉)。按照我們組件的設(shè)定,手指開(kāi)始的時(shí)候是不能往下拉的。和之前一樣,手指先往上拉一小段,在手指不離開(kāi)該元素的基礎(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)黑底了。

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

小結(jié)

多說(shuō)無(wú)用,看源碼吧:
https://github.com/yuanzm/preventoverscrolljs

參考

touch事件標(biāo)準(zhǔn)文檔

http://www.phpied.com/rendering-repaint-reflowrelayout-restyle/

https://stackoverflow.com/questions/10966710/choppy-laggy-scroll-event-on-chrome-and-ie/11039468#11039468?newreg=ded03509915248adaed26d1facce2c6c

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/86025.html

相關(guān)文章

  • 微信小程序下拉組件運(yùn)用方法

      在項(xiàng)目開(kāi)發(fā)中,會(huì)要求在小程序有時(shí)使用下拉框選項(xiàng)。在通常思路就是用 picker 組件實(shí)現(xiàn)。pick 組件使用 mode 來(lái)區(qū)分類(lèi)別,默認(rèn)使用普通選擇器就行?! ∵€有另一個(gè)方法就是可以通過(guò)自定義組件實(shí)現(xiàn),代碼如下:  //index.js   Component({   /**   *組件的屬性列表   */   properties:{   propArray:{   type:Array, ...

    3403771864 評(píng)論0 收藏0
  • pythonGUI多做輸入文本Text的完成

      文章主要是詳細(xì)介紹了pythonGUI多做輸入文本Text的控制方式,具有非常好的實(shí)用價(jià)值,希望能幫助到大家。如有誤或者未考慮到真正的地區(qū),望鼎力相助  Text的屬性wrap  fromtkinterimport*   root=Tk()   root.geometry('200x300')   te=Text(root,height=20,width=15)   #將多做輸...

    89542767 評(píng)論0 收藏0
  • 實(shí)現(xiàn)uniapp微信小程序自定義導(dǎo)航欄

    前言  世界之大無(wú)奇不有,當(dāng)客戶對(duì)于導(dǎo)航欄不滿時(shí)候,就需要我們自己去開(kāi)發(fā)了。當(dāng)然uniapp也有很多自定義導(dǎo)航插件,但現(xiàn)在我們要自己寫(xiě)?! ∈紫?,我們要知道有那幾部分。  可以看到在我們的,這個(gè)時(shí)候我們自定義的導(dǎo)航欄,需要做到標(biāo)題于膠囊水平對(duì)齊,那其實(shí)這個(gè)時(shí)候整個(gè)頭部其實(shí)主要又:。 上圖中,微信小程序中,頭部導(dǎo)航欄其實(shí)受到右上角膠囊的限制比較大,也就需要我們做改進(jìn),我們可以看到:狀態(tài)欄的高度+...

    3403771864 評(píng)論0 收藏0
  • 微信小程序?qū)崿F(xiàn)tab點(diǎn)擊切換

    微信小程序項(xiàng)目中,要實(shí)現(xiàn)無(wú)滑動(dòng)效果,可以用tab點(diǎn)擊切換,看看具體代碼供參考:  <!--pages/dingdan/dingdan.wxml-->   <viewclass="body">   <viewclass="swiper-tab">   <viewwx:for="{{tabList}}"...

    3403771864 評(píng)論0 收藏0
  • selenium動(dòng)態(tài)數(shù)據(jù)獲取的方法實(shí)現(xiàn)

      這篇文章主要是闡述了selenium可視化數(shù)據(jù)抓取有效的方法實(shí)現(xiàn),文中根據(jù)舉例編碼講到的十分詳盡,對(duì)大家學(xué)習(xí)培訓(xùn)還是工作具有很強(qiáng)的參照學(xué)習(xí)培訓(xùn)使用價(jià)值,需求的小伙伴們下邊伴隨著小編就來(lái)互相學(xué)習(xí)了解一下吧。  Selenium是一個(gè)自動(dòng)化技術(shù)檢測(cè)工具,運(yùn)用它能夠推動(dòng)電腦瀏覽器實(shí)行特殊動(dòng)作,如鼠標(biāo)點(diǎn)擊、下拉框等操作,同時(shí)也可以獲取電腦瀏覽器現(xiàn)階段獲得界面的程序代碼,保證由此可見(jiàn)即可獲得。對(duì)于有些J...

    89542767 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<