解決頁(yè)面使用overflow: scroll在iOS上滑動(dòng)卡頓的問(wèn)題

最近的一次開(kāi)發(fā)中,使用到了overflow:scroll 屬性來(lái)滑動(dòng)div。
如果你對(duì)某個(gè)div或模塊使用了overflow: scroll屬性,在iOS系統(tǒng)的手機(jī)上瀏覽時(shí),則會(huì)出現(xiàn)明顯的卡頓現(xiàn)象。
但是在android系統(tǒng)的手機(jī)上則不會(huì)出現(xiàn)該問(wèn)題。大家不妨可以分別使用IOS和Android系統(tǒng)的手機(jī)瀏覽以下鏈接,滑動(dòng)文字區(qū)域查看該效果(重點(diǎn)是記住iPhone瀏覽時(shí)的效果,方便瀏覽后文):http://geek100.com/demo/os.html.

以下代碼可解決這種卡頓的問(wèn)題:-webkit-overflow-scrolling: touch;,是因?yàn)檫@行代碼啟用了硬件加速特性,所以滑動(dòng)很流暢。

實(shí)際上,Safari真的用了原生控件來(lái)實(shí)現(xiàn),對(duì)于有-webkit-overflow-scrolling的網(wǎng)頁(yè),會(huì)創(chuàng)建一個(gè)UIScrollView,提供子layer給渲染模塊使用。

在WebKit 108400版本左右才支持,所以iOS Safari應(yīng)該是需要5.0。Android則是在4.0以上支持。
從前端開(kāi)發(fā)的角度講,只需要知道CSS的屬性-webkit-overflow-scrolling是真的創(chuàng)建了帶有硬件加速的系統(tǒng)級(jí)控件,所以效率很高。

上述所說(shuō)的方法的確可以解決ios5.0、android4.0以后系統(tǒng)的滑動(dòng)卡頓問(wèn)題,不過(guò)呢在這還可以為大家推薦一些相關(guān)插件:iScroll

https://github.com/cubiq/iscroll

IScroll 實(shí)踐指南

之所以iscroll會(huì)誕生,主要是因?yàn)闊o(wú)論是在iphone、ipod、android 或是更早前的移動(dòng)webkit都沒(méi)有提供一種原生的方式來(lái)支持在一個(gè)固定高度的容器內(nèi)滾動(dòng)內(nèi)容。
這個(gè)不幸的規(guī)則導(dǎo)致所有web-app要模擬成app的樣子時(shí),只能由一個(gè)絕對(duì)定位的header 或是footer再加上一個(gè)可以內(nèi)容的滾動(dòng)的中間區(qū)域組成。
幸運(yùn)的是移動(dòng)webkit提供了一種強(qiáng)大的硬件加速的CSS屬性,這個(gè)屬性可以用來(lái)模擬這個(gè)缺失的功能,Iscroll從這里開(kāi)始了前進(jìn)之路,但是沒(méi)有不帶刺的玫瑰。讓內(nèi)容滾動(dòng)像原生方式一般比想象中要難

通過(guò)樣式:

overflow:scroll;  
-webkit-overflow-scrolling:touch;  

IOS5 已經(jīng)能夠支持區(qū)域滾動(dòng)了。但是andriod4 還是不行...

iScroll 使用起來(lái)很簡(jiǎn)單,首先你需要一個(gè)合理的DOM結(jié)構(gòu):

<div id="wrapper">  
    <ul id="scroll">  
        <li></li>  
        ...  
        ...  
    </ul>  
</div>  

推薦的樣式:

#wrapper {  
    position:relative;  
    z-index:1;  
    width:/* your desired width, auto and 100% are fine */;  
    height:/* element height */;  
    overflow:/* hidden|auto|scroll */;  
}  

官方推薦這樣的結(jié)構(gòu),因?yàn)閕scroll只能滾動(dòng)wrapper里的第一個(gè)子節(jié)點(diǎn),或者說(shuō)唯一一個(gè)子節(jié)點(diǎn)才能使得iscroll正確的生效。因?yàn)檫@個(gè)節(jié)點(diǎn)需要一個(gè)絕對(duì)定位的CSS屬性,更重要的是這個(gè)節(jié)點(diǎn)里所包裹的內(nèi)容有了一個(gè)統(tǒng)一的容器,我們只需要計(jì)算之后修改這個(gè)容器的屬性值就可以達(dá)到我們滾動(dòng)的效果。

iscroll 需要兩個(gè)參數(shù),第一個(gè)很簡(jiǎn)單就是外容器的id,第二個(gè)參數(shù)是一個(gè)參數(shù)對(duì)象。
通過(guò)這個(gè)對(duì)象可以傳入iscroll的各項(xiàng)參數(shù)來(lái)配置iscroll。
他的參數(shù)基本分為四個(gè)部分

  • 基礎(chǔ)
  • 滾動(dòng)條
  • 放大縮小
  • 事件回調(diào)

以下是 iScroll參數(shù)以及其代表的意思:

hScroll: true, //是否水平滾動(dòng)  
vScroll: true, //是否垂直滾動(dòng)  
x: 0, //滾動(dòng)水平初始位置  
y: 0, //滾動(dòng)垂直初始位置  
bounce: true, //是否超過(guò)實(shí)際位置反彈  
bounceLock: false, //當(dāng)內(nèi)容少于滾動(dòng)是否可以反彈,這個(gè)實(shí)際用處不大  
momentum: true, //動(dòng)量效果,拖動(dòng)慣性  
lockDirection: true,  
//當(dāng)水平滾動(dòng)和垂直滾動(dòng)同時(shí)生效時(shí),當(dāng)拖動(dòng)開(kāi)始是否鎖定另一邊的拖動(dòng)  
useTransform: true, //是否使用CSS形變  
useTransition: false, //是否使用CSS變換  
topOffset: 0, //已經(jīng)滾動(dòng)的基準(zhǔn)值(一般情況用不到)  
checkDOMChanges: false, //是否自動(dòng)檢測(cè)內(nèi)容變化  

checkDOMChanges 這個(gè)不是十分靠得住,因?yàn)樗壳笆禽喸儥z測(cè)offsetWidthoffsetHeight,然后才去調(diào)自身的refresh 重新計(jì)算滾動(dòng)區(qū)域,但是有時(shí)候只檢測(cè)這個(gè)不是很準(zhǔn)..

// Scrollbar 的相關(guān)參數(shù)  
hScrollbar: true, //是否顯示水平滾動(dòng)條  
vScrollbar: true, //同上垂直滾動(dòng)條  
fixedScrollbar: isAndroid, //對(duì)andriod的fixed  
hideScrollbar: isIDevice,  //是否隱藏滾動(dòng)條  
fadeScrollbar: isIDevice && has3d, //滾動(dòng)條是否漸隱漸顯  
scrollbarClass: '', //字定義滾動(dòng)條的樣式名  

通過(guò)scrollbar這些參數(shù)可以配置iscroll的滾動(dòng)條,通過(guò)scrollbarClass可以自己定義一套滾動(dòng)條的樣式。

// Zoom 放大相關(guān)的參數(shù)  
zoom: false, //默認(rèn)是否放大  
zoomMin: 1, //放大的最小倍數(shù)  
zoomMax: 4, //最大倍數(shù)  
doubleTapZoom: 2, //雙觸放大幾倍  
wheelAction: 'scroll', //鼠標(biāo)滾動(dòng)行為(還可以是zoom)  

這個(gè)Zoom我覺(jué)得比較好用,對(duì)于一個(gè)固定顯示圖片區(qū)域的類似應(yīng)用,可以非常簡(jiǎn)單的做到固定滾動(dòng),包括兩指放大的應(yīng)用。
wheelAction 這個(gè)參數(shù)是給PC的鼠標(biāo)滾動(dòng)定義的,可以定義為滾動(dòng)鼠標(biāo)滾輪放大。

// 自定義 Events 的相關(guān)參數(shù)   
onRefresh: null, //refresh 的回調(diào),關(guān)于自身何時(shí)調(diào)用refresh 后面會(huì)繼續(xù)談到  
onBeforeScrollStart: function (e) { e.preventDefault(); },   
//開(kāi)始滾動(dòng)前的時(shí)間回調(diào),默認(rèn)是阻止瀏覽器默認(rèn)行為  
onScrollStart: null, //開(kāi)始滾動(dòng)的回調(diào)  
onBeforeScrollMove: null, //在內(nèi)容移動(dòng)前的回調(diào)  
onScrollMove: null, //內(nèi)容移動(dòng)的回調(diào)  
onBeforeScrollEnd: null, 在滾動(dòng)結(jié)束前的回調(diào)  
onScrollEnd: null, //在滾動(dòng)完成后的回調(diào)  
onTouchEnd: null, //手離開(kāi)屏幕后的回調(diào)  
onDestroy: null, //銷毀實(shí)例的回調(diào)  
onZoomStart: null,  
onZoom: null,   
onZoomEnd: null  

通過(guò)了解以上參數(shù),你可以非常容易的配置自己的iscroll 應(yīng)用:
你可以通過(guò)onScrollEnd 事件回調(diào)在結(jié)束滾動(dòng)后執(zhí)行一段你自己的代碼
你也可以簡(jiǎn)單的新建一個(gè)可以通過(guò)雙觸放大的固定滾動(dòng)區(qū)域。
你也可以什么都不做,只是簡(jiǎn)單的約定碰到邊界是否反彈,等等。

var myscroll = new iScroll('wrapper', {  
     hScroll: false, //是否水平滾動(dòng)  
     vScroll: true, //是否垂直滾動(dòng)  
     y: 10, //滾動(dòng)垂直初始位置  
     bounce : false  
});  

當(dāng)然,在使用時(shí),如果對(duì)創(chuàng)建的iscroll 實(shí)例保存引用會(huì)有很多好處:
你可以在內(nèi)容改變時(shí),DOM結(jié)構(gòu)發(fā)生改變時(shí)調(diào)用 myscroll.refresh()來(lái)重新計(jì)算固定滾動(dòng)區(qū)域的內(nèi)容高度,從而使得你的iscroll工作正常。
你也可以在你的應(yīng)用結(jié)束時(shí),用過(guò)這個(gè)引用調(diào)用destroy方法來(lái),銷毀這個(gè)iscroll 實(shí)例
等等....
當(dāng)然,iscroll提供的Api也是非常豐富,所以我們可以通過(guò)使用iscroll來(lái)做很多webapp的應(yīng)用

下面介紹一下iscroll的公用調(diào)用方法,以及參數(shù)的控制。

如何使用 iscroll 提供的API,以及一些沒(méi)有提供的功能,如何通過(guò)參數(shù)來(lái)控制iscroll
Iscroll 提供的調(diào)用方法有:

destroy
refresh
scrollTo
scrollToElement
scrollToPage
disable
enable
stop
zoom
isReady

destroy
顧名思義,是用來(lái)銷毀你實(shí)例化的iScroll 實(shí)例,包括之前綁定的所有iscroll 事件。

refresh
這個(gè)方法非常有用,當(dāng)你的滾動(dòng)區(qū)域的內(nèi)容發(fā)生改變 或是 滾動(dòng)區(qū)域不正確,都用通過(guò)調(diào)用refresh來(lái)使得iscroll 重新計(jì)算滾動(dòng)的區(qū)域,包括滾動(dòng)條,來(lái)使得iscroll 適合當(dāng)前的dom。

scrollTo
這個(gè)方法接受4個(gè)參數(shù)x, y, time, relative x為移動(dòng)的x軸坐標(biāo),y為移動(dòng)的y軸坐標(biāo), time為移動(dòng)時(shí)間,relative表示是否相對(duì)當(dāng)前位置。

scrollToElement
這個(gè)方法實(shí)際上是對(duì)scrollTo的進(jìn)一步封裝,接受兩個(gè)參數(shù)(el,time),el為需要滾動(dòng)到的元素引用,time為滾動(dòng)時(shí)間。

scrollToPage
此方法接受三個(gè)參數(shù)(pageX,pageY,time)當(dāng)滾動(dòng)內(nèi)容的高寬大于滾動(dòng)范圍時(shí),iscroll 會(huì)自動(dòng)分頁(yè),然后就能使用scrollToPage方法滾動(dòng)到頁(yè)面。當(dāng)然,當(dāng)hscrollfalse 的時(shí)候,不能左右滾動(dòng)。pageX這個(gè)參數(shù)就失去效果

disable
調(diào)用這個(gè)方法會(huì)立即停止動(dòng)畫滾動(dòng),并且把滾動(dòng)位置還原成0,取消綁定touchmove,touchend、touchcancel事件。

enable
調(diào)用這個(gè)方法,使得iscroll恢復(fù)默認(rèn)正常狀態(tài)

stop
立即停止動(dòng)畫

zoom
改變內(nèi)容的大小倍數(shù),此方法接受4個(gè)參數(shù),x,y,scale,time分別表示的意思為,放大的基準(zhǔn)坐標(biāo),以及放大倍數(shù),動(dòng)畫時(shí)間

isReady
當(dāng)iscroll 沒(méi)有處于正在滾動(dòng),沒(méi)有移動(dòng)過(guò),沒(méi)有改變大小時(shí),此值為true

上一篇沒(méi)有談到snap這個(gè)屬性,而這個(gè)屬性往往是需要用iscroll作滾動(dòng)組件非常關(guān)鍵的一個(gè)屬性。還記得我們的iphone 菜單滾動(dòng)效果吧?當(dāng)手指觸摸屏幕向左拉動(dòng)到一半的情況,應(yīng)用菜單會(huì)自動(dòng)滾動(dòng)對(duì)齊到下一頁(yè)。這個(gè)snap 屬性就是用來(lái)實(shí)現(xiàn)這種效果的。

<script type="text/javascript">  
var myScroll;  
  
function loaded() {  
    myScroll = new iScroll('wrapper', {  
        snap: 'li',  
        momentum: false,  
        hScrollbar: false,  
        vScrollbar: false  
     });  
}  
  
document.addEventListener('DOMContentLoaded', loaded, false);  
</script>  

以上是官方例子的代碼,展示了iscroll 滑動(dòng)對(duì)齊到元素li。

snap值可以為true 或是 DOM元素的tagname,當(dāng)為true時(shí),對(duì)齊的坐標(biāo)會(huì)根據(jù)可滾動(dòng)的位置和滾動(dòng)區(qū)域計(jì)算得到可滑動(dòng)幾頁(yè)。如果為tagname,則滑動(dòng)會(huì)對(duì)齊到元素上。舉個(gè)例子
假設(shè)有這樣一個(gè)列表,每個(gè)li里的img 都為居中顯示,maxWidth 都等于屏幕寬度,li的寬度都為屏幕的寬度,那么上面的代碼就可以實(shí)現(xiàn)一個(gè)滾動(dòng)圖片組件了

<ul>  
    <li>  
       ![](img.jpg)  
    <li>  
    <li>  
       ![](img.jpg)  
    <li>  
    <li>  
       ![](img.jpg)  
    <li>  
    <li>  
       ![](img.jpg)  
    <li>  
    </ul>  

我們看到 iscroll 的所有的屬性和 api 都旨在做一件事情,就是在固定區(qū)域內(nèi)滾動(dòng)。當(dāng)然通過(guò)snap,我們可以很好的模擬iphone 菜單間的平滑滾動(dòng)。

轉(zhuǎn)載請(qǐng)注明原文出處:http://qbaty.iteye.com/blog/1221061

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 問(wèn)答題47 /72 常見(jiàn)瀏覽器兼容性問(wèn)題與解決方案? 參考答案 (1)瀏覽器兼容問(wèn)題一:不同瀏覽器的標(biāo)簽?zāi)J(rèn)的外補(bǔ)...
    _Yfling閱讀 14,090評(píng)論 1 92
  • 文、攝影:垂楊紫陌 冬來(lái)了 大地越發(fā)地性感 先褪去了青澀 再褪去成熟 再褪去整夜的喧囂和浮華 冷眼看時(shí)間裸奔著前進(jìn)...
    love垂楊紫陌閱讀 222評(píng)論 2 2
  • 靚穎這幾天上頭條了,事情大家看新聞也都知道。今天和友人吃飯,連她這樣除了工作基本不問(wèn)世事的人都聽(tīng)說(shuō)了這個(gè)八卦...
    猴得柱閱讀 317評(píng)論 0 0
  • 其實(shí)一點(diǎn)兒都不奇怪,因?yàn)槲覑?ài)你,我知道。 不是萬(wàn)家燈火掩住了所有的星光 不是一望無(wú)際的海都沉默在荒涼 我都不會(huì)說(shuō)愛(ài)...
    擼串兒評(píng)論員閱讀 308評(píng)論 0 0
  • 斯坎倫保護(hù)區(qū)(Scanlon Creek Conservation Area)位于多倫多北面大約1小時(shí)車程的小鎮(zhèn)B...
    田園讀書人閱讀 777評(píng)論 0 4

友情鏈接更多精彩內(nèi)容