又見iScroll問題,特別是三星手機和iPhone,順便提一句,如今的項目中他們給div加了height屬性來解決不能滾動問題,我的認爲是個很是愚蠢的解決方案,我必須使用media query來解決隨之而來的不一樣手機有不一樣高度問題,既不能適應全部手機,萬一未來有了新手機型號,也會發生問題。不過他們是公司專門僱傭的顧問和專家,我也沒轍。css
轉載自: http://www.websqq.org/archives/1524,原文以下html
iScroll(注4.2.5版本)框架在部分三星手機上沒法滑動或點擊的解決方案node
1、測試平臺
三星 i9023 android 4.1.2 (正常)
三星 i9250 android 4.2.2 (存在問題)
三星 i9300 android4.1.1 (存在問題)
三星 i9308 android 4.0.4 (存在問題)android
2、問題描述
上述手機出現沒法滑動或者沒法觸發點擊事件的狀況web
3、問題分析chrome
一、onBeforeScrollStart方法瀏覽器
此方法是在_start裏進行了調用,目的是爲了阻止瀏覽器默認動做的執行,防止在滑動的過程當中進行干擾,同時也就阻止了滑動區域裏元素的事件的觸發,這種處理方式也直接致使了必需要在_end方法中再次觸發元素的點擊事件app
二、_end方法 框架
if (target.tagName != 'SELECT' && target.tagName != 'INPUT' && target.tagName != 'TEXTAREA') { ev = document.createEvent('MouseEvents'); ev.initMouseEvent('click', true, true, e.view, 1,point.screenX, point.screenY, point.clientX, point.clientY,e.ctrlKey, e.altKey, e.shiftKey, e.metaKey,0, null); ev._fake = true; target.dispatchEvent(ev); }
這個處理方式就是順承了上面所提到的阻止了瀏覽器默認行爲後,對滑動區域除SELECT、INPUT、TEXTAREA外的元素觸發click事件,已完成對click綁定事件的調用。 dom
【具體分析】
因爲onBeforeScrollStart是在_start方法中進行的調用,e.preventDefault();阻止了元素的默認行爲,從而致使了元素綁定事件的失效,必須在_end操做結束後進行綁定事件的模擬調用,原始的iScroll源代碼中在_end中最後建立了click事件的模擬,可是這裏必需要清楚的一個原理就是,click實際上是要依賴於其餘事件的:
1) 普通pc網頁中,click須要依賴於mousedown、mouseup的相繼觸發
2) 移動webkit中,click則須要依賴於touchstart、touchend(實際mousedown,mouseup在移動webkit上也存在)的相繼觸發
「相繼觸發」的意思就是中間不會夾雜有其餘的事件類型,這也就很容易理解iScroll中在_end中對模擬事件調用的條件了,必需要判斷that.moved才能直接觸
發模擬事件。
iScroll中與_start、_move、_end相關的三個事件類型是按照以下的規則來設置的:
START_EV = hasTouch ? 'touchstart' : 'mousedown' MOVE_EV = hasTouch ? 'touchmove' : 'mousemove' END_EV = hasTouch ? 'touchend' : 'mouseup'
【注意事項】
經測試,三星部分手機裏默認瀏覽器裏會默認全部元素都有一個默認的click事件(測試結果顯示鼠標事件中默認事件包含mouseup,mousedown,click,dblclick在移動webkit上不支持,爲系統放大功能),e.preventDefault時會阻止掉默認click事件的執行,必需要人爲的在_end結束以後模擬click事件的調用,而其餘正常手機即便調用了e.preventDefault也不會阻止click事件的觸發,由於這些手機的默認瀏覽器上的元素的click事件的cancelable屬性不爲true,不能夠被preventDefault取消掉,會正常執行,而若是在_end中模擬了click事件則將會致使click的重複調用(在有toggle狀態的事件上很是明顯),所以折中的方式參見下面的解決方案。
4、解決方案
1. 去除onBeforeScrollStart裏的阻止默認行爲
2. onBeforeScrollMove設置爲
以保證手機上的正常滑動免受瀏覽器默認行爲影響(以下滑時會有窗口的scroll事件),固然若是這裏不添加的話也能夠在document的END_EV中阻止瀏覽器默認行爲
3. _end 中將模擬事件名更改成END_EV或者直接去掉模擬事件的功能
iscroll.js是Matteo Spinelli開發的一個js文件,使用原生js編寫,不依賴與任何js框架。旨在解決移動webkit系瀏覽器的區域滾動問題,兼容mobile safari、android默認瀏覽器、safari、chrome、firefox5+、opera11+、IE9+及其餘webkit核心瀏覽器。最新版本爲iscroll4。
iscroll的用武之地
1.區域滾動
咱們在pc端web開發中,有時會用固定某一區域的寬度和高度,而後使用overflow:auto,使其內容在該區域內滾動。
iphone默認瀏覽器(mobile safari)也支持固定區域的滾動,但必須雙指滑動操做,並且沒有滾動條。mobile safari中的單指滑動只針對頁面級別,不針對頁面元素。這樣的操做體驗很麻煩,並且不少用戶根本不知道雙指可以區域滑動。
android自帶瀏覽器也支持區域滾動,且能夠單指滑動操做,可是滑動起來卡的半死半活,很不流暢。
使用iscroll,能夠完美解決上述問題了,不只能夠在iphone和android上單指滑動,並且滑動起來流暢之極,酣暢淋漓。滑動過程當中也有漂亮的滾動條提示,讓你舒心不已。
2.固定定位
固定定位不是iscroll的原生用法,而是使用iscroll協助解決固定定位問題。
話說iphone很先進,但就是不支持position:fixed。這下苦了咱們了,固定定位怎麼解決啊,咱們會常常遇到固定標題欄、固定工具欄等狀況啊!!
使用iscroll協助解決:首先獲取瀏覽器窗口高度;而後獲取固定工具欄的高度;接着將除固定工具欄以外的內容所有放在一個固定區域內,該固定區域的高度=窗口高度-工具欄高度;以後對固定區域使用iscroll。這樣,整個html頁面的高度正好等於窗口高度,頁面級別不會出現滾動,工具欄就一直固定在當前的位置。在固定區域內滑動,能夠查看頁面其餘內容,不會影響工具欄的定位。
鼠標滾輪滾動
iscroll支持在pc端瀏覽器中使用鼠標滾輪控制區域滾動,但操做起來很不靈敏。這是因爲iscroll對鼠標滾輪事件作了攔截,而後縮小了滾輪的滾動距離,詳見iscroll4.js源代碼608-609行:
iscroll將每次的滾輪距離縮小爲系統默認距離的12分之一,難怪滾起來很慢,感受不靈敏。只須要將12改爲1,滾輪的滾動速度就恢復正常了。你也能夠根據實際須要設置成其餘值。
輸入框聚焦不靈敏、沒法選擇文字
使用了iscroll以後,你會發現點擊輸入框時不靈敏,常常沒法聚焦;頁面文字也沒法選擇和複製。這是因爲iscroll要監聽鼠標事件和觸摸事件來進行滾動,因此禁止了瀏覽器的默認行爲,詳見源代碼92行:
iscroll不分青紅皁白,禁止了瀏覽器的一切默認行爲,致使上述問題。因此咱們須要稍做修改:
onBeforeScrollStart: function (e) { var target = e.target; while (target.nodeType != 1) target = target.parentNode; if (target.tagName != ‘SELECT’ && target.tagName != ‘INPUT’ && target.tagName != ‘TEXTAREA’) e.preventDefault(); }
判斷觸發事件的元素是否是input、select、textarea等表單輸入類元素,若是不是就阻止默認行爲。這樣保證了輸入類元素能正確快速聚焦。
在上述修改中追加一個條件 target.tagName != ‘body’或者直接將onBeforeScrollStart修改成null,便可作到鼠標選取文字,但這樣的修改會致使iscroll滾動失效或不靈敏,因此沒法選取文字這個問題先放一邊吧。
select元素操做不靈敏或操做後白屏
使用iscroll後,還有一個較麻煩的問題,就是select元素點擊不靈敏(滾動以後點擊select,常常無響應);有時點擊有反應了,下拉菜單顯示卻錯位(pc端);選擇一項以後,頁面直接變成了空白(iphone、android中)或者頁面位置向上偏離,滾動區域位置出現偏離。
說白了,就是致使select無法用。
爲此我調試了好久,最後發現了問題所在:iscroll默認使用的是css的transform變形中的translate3d實現區域滾動,每次滾動實際是改變translate3d中的y軸值,實際的dom位置並無發生變化。translate3d會致使頁面的焦點錯誤,系統級下拉菜單的顯示則會致使其出現顯示偏離。
控制滾動模式的代碼在67行:useTransform: true。好在iscroll提供了另外一種滾動方式,基於絕對定位位置變化的滾動。
修改成useTransform: false以後,iscroll就會使用對定位位方式來實現滾動,該方式是咱們在web開發中模擬動畫的最經常使用方式,滾動以後dom的實際位置也同步發生了變化,不會出現錯位偏離現象。
在pc端主流瀏覽器、iphone、android2.2下測試,select問題完美解決。
不過須要注意,使用對position決定定位後,滾動區的寬度默認會自適應內容寬度,而不是父元素的100%,因此最好將滾動區域寬度設爲100%。
美中不足
iscroll是小而精的經典做品,名字也帶着apple範。但惟一美中不足的是,只能使用id調用。
最近作移動平臺的應用,使用iscroll使屏幕上下滑動。發現當使用iscroll後,input等不能輸入內容了。只要在iscroll.js文件中加入以下代碼就ok了。
function allowFormsInIscroll(){ [].slice.call(document.querySelectorAll('input, select, button')).forEach(function(el){ el.addEventListener(('ontouchstart' in window)?'touchstart':'mousedown', function(e){ e.stopPropagation(); }) }) } document.addEventListener('DOMContentLoaded', allowFormsInIscroll, false);