最近的一次開(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è)offsetWidth、offsetHeight,然后才去調(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)hscroll為false 的時(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>

<li>
<li>

<li>
<li>

<li>
<li>

<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