在去年,咱們對IScroll的源碼進行了學習,而且分離出了一段代碼本身使用,在使用學習過程當中發現幾個致命問題:javascript
① 光標移位css
② 文本框找不到(先讓文本框獲取焦點,再滑動一下,輸入文字即可重現)html
③ 偶爾致使頭部消失,頭部可不是fixed哦前端
因爲以上問題,加之去年咱們團隊的工做量極大,和中間一些組織架構調整,這個事情一直被放到了今天,內心一直對此耿耿於懷,由於IScroll讓人忘不了的好處java
小釵堅信,IScroll能夠帶來前端體驗上的革命,由於他能夠解決如下問題node
咱們不能由於一兩個小問題而放棄如此牛逼的點子,因此咱們要處理其中的問題,那麼這些問題是否真的不可解決,而引發這些問題的緣由又究竟是什麼,咱們今天來一一探索ios
PS:該問題已有更好的解決方案,待續css3
第一步依舊是抽離IScroll核心邏輯,咱們這裏先在簡單層面上探究問題,以避免被旁枝末節的BUG困擾,這裏造成的一個庫只支持縱向滾動,代碼量比較少web
代碼中引入了fastclick解決其移動端點擊問題,demo效果在此:架構
http://sandbox.runjs.cn/show/xq2fbetv
基本代碼出來了,咱們如今來一個個埋坑,首先解決難的問題!
光標跳動是什麼現象你們都知道了,至於致使的緣由又咱們測試下來,便可肯定罪魁禍首爲:transform,因而咱們看看滑動過程當中發生了什麼
① 每次滑動會涉及到位置的變化
this._translate(0, newY);
② 每次變化會改變transform屬性
1 //移動x,y這裏比較簡單就不分離y了 2 _translate: function (x, y) { 3 this.scrollerStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.translateZ; 4 5 this.x = x; 6 this.y = y; 7 8 if (this.options.scrollbars) { 9 this.indicator.updatePosition(); 10 } 11 12 },
咱們這裏作一次剝離,將transform改爲直接改變top值看看效果
this.scrollerStyle['top'] = y + 'px';
而事實證實,一旦去除transform屬性,咱們這裏便再也不有光標閃動的問題了。
更進一步的分析,實驗,你會發現其實引發的緣由是這句:
// this.scrollerStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.translateZ; this.scrollerStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' ;
沒錯,就是css3d加速引發的,他的優點是讓動畫變得順暢,卻未曾想到會引發文本框光標閃爍的問題
針對ios閃爍有一個神奇的屬性是
-webkit-backface-visibility: hidden;
因而加入到,scroller元素上後觀察之,無效,捨棄該方案再來就是一些怪辦法了:
文本獲取焦點的狀況下,會隱藏虛擬鍵盤,連焦點都沒有了,這個問題天然不藥而癒,因而咱們只要滑動便讓其失去焦點,這樣彷佛狡猾的繞過了這個問題
在touchmove邏輯處加入如下邏輯
1 //暫時只考慮input問題,有效再擴展 2 var el = document.activeElement; 3 if (el.nodeName.toLowerCase() == 'input') { 4 el.blur(); 5 this.disable(); 6 setTimeout($.proxy(function () { 7 this.enable(); 8 }, this), 250); 9 return; 10 }
該方案最爲簡單粗暴,他在咱們意圖滑動時便直接致使虛擬鍵盤失效,從而根本不會滑動,便錯過了光標跳動的問題
甚至,解決了因爲滾動致使的文本框消失問題!!!
其中有一個250ms的延時,這個期間是虛擬鍵盤隱藏所用時間,這個時間段將不可對IScroll進行操做,該方案實驗下來效果還行
其中這個延時在200-300之間比較符合人的操做習慣,不設置滾動區域會亂閃,取什麼值各位本身去嘗試,測試地址:
http://sandbox.runjs.cn/show/8nkmlmz5
這個方案是我以爲最優的方案,其是否接受還要看產品態度
_translate是IScroll滑動的總控,這裏默認是使用transform進行移動,但如果獲取焦點的狀況下咱們能夠具備不同的方案
在文本框具備焦點是,咱們使用top代替transform!
PS:這是個爛方法不建議採用
1 //移動x,y這裏比較簡單就不分離y了 2 _translate: function (x, y) { 3 4 var el = document.activeElement; 5 if (el.nodeName.toLowerCase() == 'input') { 6 this.scrollerStyle['top'] = y + 'px'; 7 } else { 8 this.scrollerStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.translateZ; 9 } 10 11 this.x = x; 12 this.y = y; 13 14 if (this.options.scrollbars) { 15 this.indicator.updatePosition(); 16 } 17 18 },
該方案被測試確實可行,不會出現光標閃的現象,可是有一個問題卻須要咱們處理,即是一旦文本框失去焦點,咱們要作top與transform的換算
因此這是一個爛方法!!!這裏換算事實上也不難,就是將top值從新歸還transform,可是整個這個邏輯倒是讓人以爲彆扭
並且咱們這裏還須要一個定時器去作計算,判斷什麼時候文本框失去焦點,整個這個邏輯就是一個字 坑!
1 //移動x,y這裏比較簡單就不分離y了 2 _translate: function (x, y) { 3 4 var el = document.activeElement; 5 if (el.nodeName.toLowerCase() == 'input') { 6 this.scrollerStyle['top'] = y + 'px'; 7 8 //便須要作距離換算相關清理,一旦文本框事情焦點,咱們要作top值還原 9 if (!this.TimerSrc) { 10 this.TimerSrc = setInterval($.proxy(function () { 11 var el = document.activeElement; 12 if (el.nodeName.toLowerCase() != 'input') { 13 14 pos = this.getComputedPosition(); 15 16 var top = $(scroller).css('top'); 17 this.scrollerStyle['top'] = '0px'; 18 console.log(pos); 19 20 var _x = Math.round(pos.x); 21 var _y = Math.round(pos.y); 22 _y = _y + parseInt(top); 23 24 //移動過去 25 this._translate(_x, _y); 26 27 clearInterval(this.TimerSrc); 28 this.TimerSrc = null; 29 } 30 }, this), 20); 31 } 32 } else { 33 this.scrollerStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.translateZ; 34 } 35 36 this.x = x; 37 this.y = y; 38 39 if (this.options.scrollbars) { 40 this.indicator.updatePosition(); 41 } 42 43 },
經測試,該代碼能夠解決光標跳動問題,可是坑不坑你們內心有數,一旦須要被迫使用定時器的地方,一定會有點坑!測試地址
http://sandbox.runjs.cn/show/v9pno9d8
文本框消息是因爲滾動中產生動畫,將文本框搞到區域外了,這個時候一旦咱們輸入文字,致使input change,系統便會自動將文本定位到中間,而出現文本不可見問題
該問題的處理最好的方案,依舊是方案一,如果這裏要死磕,又會有許多問題,方案無非是給文本設置changed事件,或者定時器什麼的,當變化時,自動將文本元素
至於IScroll可視區域,樓主這裏就不獻醜了,由於我基本決定使用方案一了。
所謂步長移動即是我一次必須移動必定距離,這個與圖片橫向輪播功能有點相似,而這類需求在移動端數不勝數,那咱們的IScroll應該如何處理才能加上這一偉大特性呢?
去看IScroll的源碼,人家都已經實現了,竟然人家都實現了,哎,可是咱們這裏無論他,照舊作咱們的事情吧,加入步長功能
PS:這裏有點小小的失落,我覺得沒有實現呢,這樣我搞出來確定沒有官方的優雅了!
思路其實很簡單,咱們如果設置了一個步長屬性,暫時咱們認爲他是一個數字(其實能夠是bool值,由庫本身計算該值),而後每次移動時候便必須強制移動該屬性的整數倍便可,好比:
1 var s = new IScroll({ 2 wrapper: $('#wrapper'), 3 scroller: $('#scroller'), 4 setp: 40 5 });
這個便要求每次都得移動10px的步長,那麼這個如何實現呢?其實實現點,依然是_translate處,咱們這裏須要一點處理
1 //移動x,y這裏比較簡單就不分離y了 2 _translate: function (x, y, isStep) { 3 4 //處理步長 5 if (this.options.setp && !isStep) { 6 var flag2 = y > 0 ? 1 : -1; //這個會影響後面的計算結果 7 var top = Math.abs(y); 8 var mod = top % this.options.setp; 9 top = (parseInt(top / this.options.setp) * this.options.setp + (mod > (this.options.setp/2) ? this.options.setp : 0)) * flag2; 10 y = top; 11 } 12 13 this.scrollerStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.translateZ; 14 15 this.x = x; 16 this.y = y; 17 18 if (this.options.scrollbars) { 19 this.indicator.updatePosition(); 20 } 21 22 },
這樣一改後,每次便要求移動40px的步長,固然,我這裏代碼寫的不是太好,整個效果在此
這裏惟一須要處理的就是touchmove了,每次move的時候,咱們不該該對其進行步長控制,然後皆能夠,這種控制步長的效果有什麼用呢?請看這個例子:
所謂雙IScroll,即是一個頁面出現了兩個IScroll組件的問題,這個問題前段時間發生在了咱們一個團隊身上,其情況具體爲
他在一個view上面有兩個地方使用了IScroll,結果就是感受滑動很卡,而且不能很好的定位緣由,其實致使這個緣由的主要因素是:
他將事件綁定到了document上,而不是具體包裹層元素上,這樣的話,就算一個IScroll隱藏了,他滑動時候已經執行了兩個邏輯,從而出現了卡的現象
固然,一個IScroll隱藏的話其實應該釋放其中的事件句柄,當時他沒有那麼作,因此之後你們遇到對應的功能,須要將事件綁定對位置
咱們這裏舉個例子:
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <title></title> 5 <meta http-equiv="Content-Type" content="text/html; charset=gb2312" /> 6 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0"> 7 <meta name="keywords" content="" /> 8 <meta name="description" content="" /> 9 <meta name="robots" content="all" /> 10 <style type="text/css"> 11 12 /*reset*/ 13 body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,textarea,p,blockquote,th,td,hr,button,article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{margin:0;padding:0} 14 body,button,input,select,textarea{font:normal 14px/1.5 Tahoma,"Lucida Grande",Verdana,"Microsoft YaHei",hei;} 15 article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section,iframe{display:block;} 16 h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:500;} 17 address,cite,dfn,em,var,i{font-style:normal;font-weight:normal;font-family:arial;} 18 ul,ol{list-style:none} 19 a{color:#000;text-decoration:none} 20 a:hover{text-decoration:underline;-webkit-transition:color .2s linear;-moz-transition:color .2s linear;-ms-transition:color .2s linear;-o-transition:color .2s linear;transition:color .2s linear;} 21 fieldset,img,button,input{border:0} 22 button,input,select,textarea{font-size:100%} 23 table{border-collapse:collapse;border-spacing:0} 24 input[type="button"],input[type="submit"]{-webkit-appearance:none;} 25 body{min-width:320px; background:#f5f5f5;overflow-x:hidden;-webkit-text-size-adjust:none;-webkit-tap-highlight-color:rgba(0,0,0,0);-webkit-font-smoothing:subpixel-antialiased;-moz-user-select:none;color:#000;}:focus{outline:none;}.clearfix:after{clear:both;content:'.';display:block;height:0;visibility:hidden;line-height:0;}.clearfix{*zoom:1;}.fl{float:left;}.fr{float:right;}.clear{clear:both;}.overflow{overflow:hidden;}.ellips{white-space:nowrap; overflow:hidden; text-overflow:ellipsis;}.ellips_line2,.ellips_line3{display: -webkit-box;-webkit-box-orient: vertical;overflow: hidden;}.ellips_line2{-webkit-line-clamp:2;}.ellips_line3{-webkit-line-clamp:3;}.pos_rel{position:relative;} 26 html,body,.h100{ height:100%; } 27 dfn{color:#ff9913; font-size:12px; font-weight:normal;} 28 /*-----------------------------------------common--------------------*/ 29 .i,.i_bef:before,.i_aft:after,.carlist li:before,.ok_crt:after{background:url(../img/style1/v2_bgs.png) no-repeat; background-size:175px 125px;} 30 .i_bef:before,.i_aft:after,.carlist li:before{position: absolute;content: "";} 31 .abs_size{-moz-box-sizing:border-box; -webkit-box-sizing:border-box; box-sizing:border-box;} 32 .opacity{opacity:0.7; filter:alpha(opacity=70);} 33 34 /*active*/ 35 .list_st_border li:active,.p_hinttxt:active,.search_cancel:active,.citylist dd:active{ background:#f8f8f8;} 36 .btn_yellow:active{background:#eb840f;} 37 38 /*layout*/ 39 .wrap{margin-top:48px;} 40 .wrap_pb{margin-top:48px; padding-bottom:45px;} 41 .p10{padding:10px;} 42 .hm{text-align:center;} 43 .break_all{word-break:break-all;} 44 .fix_b{position:fixed; bottom:0; left:0;z-index:9999;} 45 46 /*font bg color size*/ 47 h1{font:normal 1.286em/1.5 "";}/*18px*/ 48 h2{font:normal 1.143em/1.5 "";}/*16px*/ 49 h3{font:600 1em/1.5 "";}/*14px*/ 50 .price{margin-left:5px;} 51 .price i{margin-left:2px; font-size:1.286em;} 52 .greyfont{color:#686868;} 53 .greyfont1{color:#909090;} 54 .bggrey{height:100%; background:#f5f5f5;} 55 56 /*header*/ 57 header{position:fixed; top:0; left:0; z-index:9999; width:100%; height:48px;background-color:#1491c5;} 58 .returnico{position:absolute; left:0; top:0; width:68px; height:48px; background-color:#15a4d5;} 59 .returnico:before{left:25px;top:16px;width:12px;height:20px; background-position:0 0;} 60 .icon_phone,.icon_home{width:42px;height:100%;top:0;position:relative;float:right;} 61 .icon_phone:before{width:11px;height:20px;top:16px;right:12px;background-position:-115px -65px;} 62 .icon_home:before{width:20px;height:19px;top:16px;right:10px;background-position:-83px -66px;} 63 header i:active{opacity:0.7; filter:alpha(opacity=70);} 64 header h1{position:absolute; width:100%;line-height:48px; text-align:center; letter-spacing:2px; color: #fff;} 65 .header_r,.header_rs{position:absolute;z-index:9; top:0; right:0; line-height:48px; padding:0 15px; font-size:18px; background:#15a4d5; color:#fff;} 66 .header_rs{padding:0 5px; font-size:12px; } 67 68 /*background-position*/ 69 .select_n:before{width:20px;height:20px;background-position:-18px 0;} 70 .select_n.current:before{background-position:-44px 0;} 71 72 /*searchbox*/ 73 .search_wrap{overflow:hidden; padding:10px; background:#dfeaf1;} 74 .search_box{position:relative; float:left; width:100%;} 75 .search_input{width:100%; padding:0 10px 0 28px; line-height:30px; background-color:#fff; border-radius:4px; color:#ccc;} 76 .fdj:before,.fdj:after,.search_box:before,.search_box:after{position:absolute; content:""; z-index:9;} 77 .fdj:before,.search_box:before{left:5px; top:7px; width:12px; height:12px; border:1px solid #bcbcbc; border-radius:12px;} 78 .fdj:after,.search_box:after{left:19px; top:17px; width:1px; height:8px; background:#bcbcbc;} 79 .search_cancel{ display:none;float:left; width:20%; line-height:30px; text-align:center; font-size:16px;color:#1491c5; background:none; border:none;} 80 .close_icon{display:none; position:absolute; z-index:10; top:8px; right:4px; width:16px; height:16px; border-radius:30px; background:#b1b1b1;} 81 .close_icon:before,.close_icon:after{position:absolute; content:""; top:4px; left:7px; width:2px; height:8px; background:#fff; } 82 .close_icon:before{-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);-o-transform:rotate(45deg);transform:rotate(45deg);} 83 .fdj:after,.search_box:after,.close_icon:after{-webkit-transform:rotate(-45deg);-moz-transform:rotate(-45deg);-ms-transform:rotate(-45deg);-o-transform:rotate(-45deg);transform:rotate(-45deg);} 84 .search_focus .search_box{width:80%;} 85 .search_focus .close_icon, .search_focus .search_cancel{display:block;} 86 .search_input:focus{color:#000;} 87 88 /*tab*/ 89 .tab{ background-color:#f8f8f8; border-bottom:1px solid #dfdfdf;} 90 .tab li{float:left; width:50%; height:39px; line-height:39px; text-align:center; border-right:1px solid #dfdfdf;} 91 .tab li:last-child{border-right:none;} 92 .tab li.tabcrt{ background-color:#dfdfdf;} 93 94 .tab_b{ background-color:#f5f5f5; border-bottom:1px solid #c1c1c1;} 95 .tab_b li{float:left; width:50%; height:39px; line-height:39px; text-align:center;} 96 .tab_b li:last-child{border-right:none;} 97 .tab_b li.tabcrt{color:#1491c5; border-bottom:4px solid #1491c5;} 98 99 /*list*/ 100 .list_st_border{ background:#fff; border-bottom:none; border:1px solid #cfcfcf; } 101 .list_st_border li{position:relative;padding:0 10px; line-height:42px; border-bottom:1px solid #cfcfcf;} 102 .list_st_border li:last-child{border-bottom:none;} 103 104 .list_sli{padding:10px; overflow:hidden; border-bottom:1px solid #cfcfcf; background:#fff;} 105 .list_sli .list_sunit{float:left;} 106 107 .citylist{color:#000;} 108 .citylist dt,.citylist dd{padding-left:10px;border-bottom:1px solid #e2e2e2;} 109 .citylist dt{line-height:25px; background-color:#eaeaea;} 110 .citylist dd{position:relative; font-size:16px; line-height:43px; background-color:#fff;} 111 .citylist .ok_crt{color:#1491c5;} 112 .citylist .ok_crt:after{position:absolute;content:""; right:10px; top:50%; margin-top:-6px; width:12px; height:13px; background-position:-110px 0;} 113 114 115 /*arr*/ 116 .li_arr_r{position:relative;} 117 .arr_r{position:absolute;right:0px; top:50%; width:30px; height:30px; margin-top:-15px; } 118 .arr_r:before,.arr_r:after,.li_arr_r:before,.li_arr_r:after{position: absolute; left:15px; content: "";width:2px; height:7px; background-color:#909090;} 119 .arr_r:before,.li_arr_r:before{top:10px;-webkit-transform:rotate(-45deg); -moz-transform:rotate(-45deg);-ms-transform:rotate(-45deg);-o-transform:rotate(-45deg);transform:rotate(-45deg);} 120 .arr_r:after,.li_arr_r:after{top:15px;-webkit-transform:rotate(45deg); -moz-transform:rotate(45deg);-ms-transform:rotate(45deg);-o-transform:rotate(45deg);transform:rotate(45deg);} 121 .li_arr_r:before,.li_arr_r:after{left:auto; right:10px; top:50%; margin-top:-5px;} 122 .li_arr_r:after{margin-top:0;} 123 124 /*p*/ 125 .p_grey{margin:10px 5px; font-size:13px; color:#989898;} 126 .p_grey_center{ text-align:center; margin:20px 5px; font-size:13px; color:#989898;} 127 .p_hinttxt{padding:20px 10px; text-align:center; font-size:16px; color:#1491c5;} 128 129 130 /*btn*/ 131 .btn_yellow,.btn_del{width:100%; height:44px; line-height:42px; padding:0 10px; color:#fff;} 132 .btn_yellow{background:#ff9913;} 133 .btn_del{background:#ca4345;text-align:center;font-size:1.2em;} 134 135 .btn_pay{padding:0 20px;height:44px;float:right;background:#ff7d13;color:#fff;} 136 .btn_pay:active{background:#ff7300;} 137 .room_num {position:absolute; right:10px; width:100px; height:30px; line-height:30px;color:#000;background-color: #fff; text-align:center;border:#bfbfbf 1px solid;} 138 .room_num i{position:absolute; width:30px; height:30px; text-align:center; font:normal 2em/28px "Arial";} 139 .room_num i:first-child{left:0;background:#f4f4f4;color:#d9d9d9;font:normal 2.8em/25px "Arial";} 140 .room_num i:last-child{right:0;background:#06a2d0;color:#fff;} 141 142 143 /*日曆*/ 144 .cui_cldwrap{color:#000;} 145 .cui_cldweek{height:25px; overflow:hidden;font:normal 12px/24px "verdana";border-bottom:1px solid #c8c8c8;} 146 .cui_cldweek li{float:left; width:14%; text-align:center; } 147 .cui_cldweek li:first-child,.cui_cldweek li:last-child{width:15%; color:#acacac;} 148 .cui_cldmonth{height:35px;text-align:center;font:normal 16px/35px "verdana"; background:#fff;} 149 .cui_cldunit{margin-bottom:20px;} 150 .cui_cld_daybox{overflow:hidden; background:#fff;} 151 .cui_cld_daybox li{float:left; width:14%; height:45px; padding:4px 0; font:normal 12px/45px "verdana"; overflow:hidden; text-align:center;} 152 .cui_cld_daybox li:nth-child(7n),.cui_cld_daybox li:nth-child(7n+1){width:15%;} 153 .cui_cld_daypass{ background:#f7f7f7;} 154 .cui_cld_daycrt{background:#06a2d0; color:#fff;} 155 .cui_cld_dayfuture{background:#fff;} 156 .cui_cld_day_nocrtmonth{ visibility:hidden;} 157 .cui_cld_day_havetxt em{display:block; line-height:25px;} 158 .cui_cld_day_havetxt i{display:block;line-height:15px;} 159 .cui_cld_day_hint{color:#06a2d0;} 160 /*全局XXXX*/ 161 162 /*彈出藍色框*/ 163 .cui-pop-box{background:#fff;} 164 .cui-text-center{text-align:center;} 165 .cui-pop-box .cui-hd{height:40px;line-height:40px;font-size:1.2em;color:#fff;background:#1491c5;padding:0 10px;position:relative;} 166 .cui-pop-box .cui-hd .cui-close{position:absolute;top:10px; right:10px; width:18px; height:18px;line-height:18px;border-radius:50%; background:#fff;color:#1491c5;text-align:center;font-weight:bold;} 167 .cui-error{width:150px;margin:auto;border-radius:5px;background:rgba(73,73,73,1);padding:10px;color:#fff;font-weight:700;text-align:center;word-break:break-all;} 168 .cui-select-view li{border-bottom:#dfdfdf 1px solid;padding:.8em 2em .8em .8em;white-space:nowrap; overflow:hidden; text-overflow:ellipsis;position:relative;} 169 .cui-select-view li.current{color:#1084bc;} 170 .cui-select-view li:active{background:rgba(0,0,0,.05);} 171 .cui-select-view li.current:before,.cui-select-view li.current:after{position:absolute;content:"";background:#1084bc;height:3px;top:50%;border-radius:3px;} 172 .cui-select-view li.current:before{width:18px;right:10px;margin-top:-2px;-webkit-transform:rotate(-50deg);-moz-transform:rotate(-50deg);-ms-transform:rotate(-50deg);transform:rotate(-50deg);} 173 .cui-select-view li.current:after{width:9px;right:22px;margin-top:2px;-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);} 174 175 .cui-roller{width:100%;height:90px;overflow:hidden;position:relative;display: -webkit-box;display: -moz-box;display: -ms-flexbox;display: -webkit-flex;display: flex;} 176 .cui-roller .ul-list{text-align:center;font-size:1.1em;line-height:30px;-webkit-box-flex: 1;-moz-box-flex: 1;-webkit-flex: 1;-ms-flex: 1;flex: 1; position: absolute; left: 50%; margin-left: -23px; } 177 .cui-mask{position:absolute;z-index:3;top: 0;left: 0;width: 100%;height: 100%;pointer-events: none; 178 background: linear-gradient(#fff 0,rgba(245,245,245,0) 52%,rgba(245,245,245,0) 48%,#fff 100%); 179 background: -webkit-gradient(linear,left bottom,left top,from(#fff),color-stop(0.52,rgba(245,245,245,0)),color-stop(0.48,rgba(245,245,245,0)),to(#fff)); 180 background: -webkit-linear-gradient(#fff 0,rgba(245,245,245,0) 52%,rgba(245,245,245,0) 48%,#fff 100%); 181 background: -moz-linear-gradient(#fff 0,rgba(245,245,245,0) 52%,rgba(245,245,245,0) 48%,#fff 100%); 182 } 183 .cui-lines{width:100%;height:34px;position:absolute;top:50%;margin-top:-17px;border-top:#dfdfdf 1px solid;border-bottom:#dfdfdf 1px solid;} 184 .cui-roller-tips{color:#8d8d8d;padding:5px;text-align:center;} 185 .cui-roller-btns{background:#f6f5f5;padding:10px;text-align:center;} 186 .cui-roller-btns span{width:45%;display:inline-block;padding:10px 0;color:#fff;} 187 .cui-roller-btns span:active{opacity:.75;} 188 .cui-roller-btns .cui-btns-cancel{background:#a9a9a9;margin-right:5%;} 189 .cui-roller-btns .cui-btns-sure{background:#ff9913;} 190 191 </style> 192 <script id="others_zepto_10rc1" type="text/javascript" class="library" src="http://sandbox.runjs.cn/js/sandbox/other/zepto.min.js"></script> 193 <script type="text/javascript" src="http://sandbox.runjs.cn/uploads/rs/279/2h5lvbt5/fastclick.js"></script> 194 </head> 195 <body> 196 <div class="cui-pop-box"> 197 <div class="cui-hd"> 198 <div class="cui-text-center"> 199 滾輪滾輪滾輪</div> 200 </div> 201 <div class="cui-bd"> 202 <div class="cui-roller" > 203 <div id="wrapper" style="width: 100px; position: relative; "> 204 <ul class="ul-list" id="scroller" style="left: 40%; width: 100px;"> 205 <li>選項1</li> 206 <li>選項2</li> 207 <li>選項3</li> 208 <li>選項4</li> 209 <li>選項5</li> 210 <li>選項6</li> 211 <li>選項7</li> 212 <li>選項8</li> 213 <li>選項9</li> 214 <li>選項10</li> 215 </ul> 216 </div> 217 218 <div id="wrapper2" style="width: 100px; position: relative;"> 219 <ul class="ul-list" id="scroller2" style="right: 10%; width: 100px;"> 220 <li>選項11</li> 221 <li>選項12</li> 222 <li>選項13</li> 223 <li>選項14</li> 224 <li>選項15</li> 225 <li>選項16</li> 226 <li>選項17</li> 227 <li>選項18</li> 228 <li>選項19</li> 229 <li>選項20</li> 230 </ul> 231 </div> 232 233 <div class="cui-lines"> 234 </div> 235 </div> 236 <p class="cui-roller-tips"> 237 提示信息</p> 238 <div class="cui-roller-btns"> 239 <span class="cui-btns-cancel">取消</span><span class="cui-btns-sure">肯定</span> 240 </div> 241 </div> 242 </div> 243 <script type="text/javascript"> 244 245 var utils = (function () { 246 var me = {}; 247 var _elementStyle = document.createElement('div').style; 248 249 //得到須要兼容CSS3前綴 250 var _vendor = (function () { 251 var vendors = ['t', 'webkitT', 'MozT', 'msT', 'OT']; 252 var transform; 253 var i = 0; 254 var l = vendors.length; 255 256 for (; i < l; i++) { 257 transform = vendors[i] + 'ransform'; 258 if (transform in _elementStyle) return vendors[i].substr(0, vendors[i].length - 1); 259 } 260 return false; 261 })(); 262 263 //獲取樣式(CSS3兼容) 264 function _prefixStyle(style) { 265 if (_vendor === false) return false; 266 if (_vendor === '') return style; 267 return _vendor + style.charAt(0).toUpperCase() + style.substr(1); 268 } 269 270 me.getTime = Date.now || function getTime() { return new Date().getTime(); }; 271 272 me.addEvent = function (el, type, fn, capture) { 273 if (el[0]) el = el[0]; 274 el.addEventListener(type, fn, !!capture); 275 }; 276 277 me.removeEvent = function (el, type, fn, capture) { 278 if (el[0]) el = el[0]; 279 el.removeEventListener(type, fn, !!capture); 280 }; 281 282 /* 283 current:當前鼠標位置 284 start:touchStart時候記錄的Y(多是X)的開始位置,可是在touchmove時候可能被重寫 285 time: touchstart到手指離開時候經歷的時間,一樣可能被touchmove重寫 286 lowerMargin:y可移動的最大距離,這個通常爲計算得出 this.wrapperHeight - this.scrollerHeight 287 wrapperSize:若是有邊界距離的話就是可拖動,否則碰到0的時候便中止 288 */ 289 me.momentum = function (current, start, time, lowerMargin, wrapperSize) { 290 var distance = current - start, 291 speed = Math.abs(distance) / time, 292 destination, 293 duration, 294 deceleration = 0.0006; 295 296 destination = current + (speed * speed) / (2 * deceleration) * (distance < 0 ? -1 : 1); 297 duration = speed / deceleration; 298 299 if (destination < lowerMargin) { 300 destination = wrapperSize ? lowerMargin - (wrapperSize / 2.5 * (speed / 8)) : lowerMargin; 301 distance = Math.abs(destination - current); 302 duration = distance / speed; 303 } else if (destination > 0) { 304 destination = wrapperSize ? wrapperSize / 2.5 * (speed / 8) : 0; 305 distance = Math.abs(current) + destination; 306 duration = distance / speed; 307 } 308 309 return { 310 destination: Math.round(destination), 311 duration: duration 312 }; 313 314 }; 315 316 $.extend(me, { 317 hasTouch: 'ontouchstart' in window 318 }); 319 320 321 //咱們暫時只判斷touch 和 mouse便可 322 $.extend(me.style = {}, { 323 transform: _prefixStyle('transform'), 324 transitionTimingFunction: _prefixStyle('transitionTimingFunction'), 325 transitionDuration: _prefixStyle('transitionDuration'), 326 transitionDelay: _prefixStyle('transitionDelay'), 327 transformOrigin: _prefixStyle('transformOrigin') 328 }); 329 330 $.extend(me.eventType = {}, { 331 touchstart: 1, 332 touchmove: 1, 333 touchend: 1, 334 335 mousedown: 2, 336 mousemove: 2, 337 mouseup: 2 338 }); 339 340 $.extend(me.ease = {}, { 341 quadratic: { 342 style: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)', 343 fn: function (k) { 344 return k * (2 - k); 345 } 346 }, 347 circular: { 348 style: 'cubic-bezier(0.1, 0.57, 0.1, 1)', // Not properly "circular" but this looks better, it should be (0.075, 0.82, 0.165, 1) 349 fn: function (k) { 350 return Math.sqrt(1 - (--k * k)); 351 } 352 }, 353 back: { 354 style: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)', 355 fn: function (k) { 356 var b = 4; 357 return (k = k - 1) * k * ((b + 1) * k + b) + 1; 358 } 359 }, 360 bounce: { 361 style: '', 362 fn: function (k) { 363 if ((k /= 1) < (1 / 2.75)) { 364 return 7.5625 * k * k; 365 } else if (k < (2 / 2.75)) { 366 return 7.5625 * (k -= (1.5 / 2.75)) * k + 0.75; 367 } else if (k < (2.5 / 2.75)) { 368 return 7.5625 * (k -= (2.25 / 2.75)) * k + 0.9375; 369 } else { 370 return 7.5625 * (k -= (2.625 / 2.75)) * k + 0.984375; 371 } 372 } 373 }, 374 elastic: { 375 style: '', 376 fn: function (k) { 377 var f = 0.22, 378 e = 0.4; 379 380 if (k === 0) { return 0; } 381 if (k == 1) { return 1; } 382 383 return (e * Math.pow(2, -10 * k) * Math.sin((k - f / 4) * (2 * Math.PI) / f) + 1); 384 } 385 } 386 }); 387 return me; 388 })(); 389 390 function IScroll(opts) { 391 this.wrapper = typeof opts.wrapper == 'string' ? $(opts.wrapper) : opts.wrapper; 392 this.scroller = typeof opts.scroller == 'string' ? $(opts.scroller) : opts.scroller; 393 if (!opts.wrapper[0] || !opts.scroller[0]) throw 'param error'; 394 395 this.wrapper = this.wrapper[0]; 396 this.scroller = this.scroller[0]; 397 398 //這個屬性會被動態改變的,若是這裏 399 this.scrollerStyle = this.scroller.style; 400 401 this.options = { 402 //每次要求移動的步長 403 setp: false, 404 //是否具備滾動條 405 scrollbars: true, 406 // 其實時期Y的位置 407 startY: 0, 408 //超出邊界還原時間點 409 bounceTime: 600, 410 //超出邊界返回的動畫 411 bounceEasing: utils.ease.circular, 412 413 //超出邊界時候是否還能拖動 414 bounce: true, 415 416 bindToWrapper: true, 417 418 //當window觸發resize事件60ms後還原 419 resizePolling: 60, 420 startX: 0, 421 startY: 0 422 }; 423 424 for (var i in opts) { 425 this.options[i] = opts[i]; 426 } 427 428 this.translateZ = ' translateZ(0)'; 429 430 this.x = 0; 431 this.y = 0; 432 this._events = {}; 433 this._init(); 434 435 //更新滾動條位置 436 this.refresh(); 437 438 //更新自己位置 439 this.scrollTo(this.options.startX, this.options.startY); 440 441 this.enable(); 442 443 }; 444 445 IScroll.prototype = { 446 _init: function () { 447 this._initEvents(); 448 449 //初始化滾動條,滾動條此處須要作重要處理 450 if (this.options.scrollbars) { 451 this._initIndicator(); 452 } 453 }, 454 refresh: function () { 455 var rf = this.wrapper.offsetHeight; // Force reflow 456 457 this.wrapperHeight = this.wrapper.clientHeight; 458 this.scrollerHeight = this.scroller.offsetHeight; 459 this.maxScrollY = this.wrapperHeight - this.scrollerHeight; 460 461 this.endTime = 0; 462 463 this._execEvent('refresh'); 464 465 this.resetPosition(); 466 467 }, 468 _initEvents: function (remove) { 469 var eventType = remove ? utils.removeEvent : utils.addEvent; 470 var target = this.options.bindToWrapper ? this.wrapper : window; 471 472 eventType(window, 'orientationchange', this); 473 eventType(window, 'resize', this); 474 475 if (utils.hasTouch) { 476 eventType(this.wrapper, 'touchstart', this); 477 eventType(target, 'touchmove', this); 478 eventType(target, 'touchcancel', this); 479 eventType(target, 'touchend', this); 480 } else { 481 eventType(this.wrapper, 'mousedown', this); 482 eventType(target, 'mousemove', this); 483 eventType(target, 'mousecancel', this); 484 eventType(target, 'mouseup', this); 485 } 486 487 eventType(this.scroller, 'transitionend', this); 488 eventType(this.scroller, 'webkitTransitionEnd', this); 489 eventType(this.scroller, 'oTransitionEnd', this); 490 eventType(this.scroller, 'MSTransitionEnd', this); 491 }, 492 _start: function (e) { 493 if (!this.enabled || (this.initiated && utils.eventType[e.type] !== this.initiated)) { 494 return; 495 } 496 497 var point = e.touches ? e.touches[0] : e, pos; 498 this.initiated = utils.eventType[e.type]; 499 500 this.moved = false; 501 502 this.distY = 0; 503 504 //開啓動畫時間,若是以前有動畫的話,便要中止動畫,這裏由於沒有傳時間,因此動畫便直接中止了 505 this._transitionTime(); 506 507 this.startTime = utils.getTime(); 508 509 //若是正在進行動畫,須要中止,而且觸發滑動結束事件 510 if (this.isInTransition) { 511 this.isInTransition = false; 512 pos = this.getComputedPosition(); 513 var _x = Math.round(pos.x); 514 var _y = Math.round(pos.y); 515 516 if (_y < 0 && _y > this.maxScrollY && this.options.adjustXY) { 517 _y = this.options.adjustXY.call(this, _x, _y).y; 518 } 519 520 //移動過去 521 this._translate(_x, _y); 522 this._execEvent('scrollEnd'); 523 } 524 525 this.startX = this.x; 526 this.startY = this.y; 527 this.absStartX = this.x; 528 this.absStartY = this.y; 529 this.pointX = point.pageX; 530 this.pointY = point.pageY; 531 532 this._execEvent('beforeScrollStart'); 533 534 e.preventDefault(); 535 536 }, 537 538 _move: function (e) { 539 if (!this.enabled || utils.eventType[e.type] !== this.initiated) { 540 return; 541 } 542 e.preventDefault(); 543 544 var point = e.touches ? e.touches[0] : e, 545 deltaX = point.pageX - this.pointX, 546 deltaY = point.pageY - this.pointY, 547 timestamp = utils.getTime(), 548 newX, newY, 549 absDistX, absDistY; 550 551 this.pointX = point.pageX; 552 this.pointY = point.pageY; 553 554 this.distX += deltaX; 555 this.distY += deltaY; 556 absDistX = Math.abs(this.distX); 557 absDistY = Math.abs(this.distY); 558 559 // 若是一直按着沒反應的話這裏就直接返回了 560 if (timestamp - this.endTime > 300 && (absDistX < 10 && absDistY < 10)) { 561 return; 562 } 563 564 newY = this.y + deltaY; 565 566 if (newY > 0 || newY < this.maxScrollY) { 567 newY = this.options.bounce ? this.y + deltaY / 3 : newY > 0 ? 0 : this.maxScrollY; 568 } 569 570 if (!this.moved) { 571 this._execEvent('scrollStart'); 572 } 573 574 this.moved = true; 575 576 //暫時只考慮input問題,有效再擴展 577 var el = document.activeElement; 578 if (el.nodeName.toLowerCase() == 'input') { 579 el.blur(); 580 this.disable(); 581 setTimeout($.proxy(function () { 582 this.enable(); 583 }, this), 250); 584 return; 585 } 586 587 this._translate(0, newY, true); 588 589 if (timestamp - this.startTime > 300) { 590 this.startTime = timestamp; 591 this.startX = this.x; 592 this.startY = this.y; 593 } 594 595 596 }, 597 _end: function (e) { 598 599 if (!this.enabled || utils.eventType[e.type] !== this.initiated) { 600 return; 601 } 602 603 var point = e.changedTouches ? e.changedTouches[0] : e, 604 momentumY, 605 duration = utils.getTime() - this.startTime, 606 newX = Math.round(this.x), 607 newY = Math.round(this.y), 608 distanceX = Math.abs(newX - this.startX), 609 distanceY = Math.abs(newY - this.startY), 610 time = 0, 611 easing = ''; 612 613 this.isInTransition = 0; 614 this.initiated = 0; 615 this.endTime = utils.getTime(); 616 617 if (this.resetPosition(this.options.bounceTime)) { 618 return; 619 } 620 621 this.scrollTo(newX, newY); 622 if (!this.moved) { 623 //click 的狀況 624 625 this._execEvent('scrollCancel'); 626 return; 627 } 628 629 if (duration < 300) { 630 631 momentumY = utils.momentum(this.y, this.startY, duration, this.maxScrollY, this.options.bounce ? this.wrapperHeight : 0); 632 // newX = momentumX.destination; 633 newY = momentumY.destination; 634 time = Math.max(momentumY.duration); 635 this.isInTransition = 1; 636 } 637 638 if (newY != this.y) { 639 if (newY > 0 || newY < this.maxScrollY) { 640 easing = utils.ease.quadratic; 641 } 642 643 this.scrollTo(newX, newY, time, easing); 644 return; 645 } 646 647 this._execEvent('scrollEnd'); 648 }, 649 650 _resize: function () { 651 var that = this; 652 653 clearTimeout(this.resizeTimeout); 654 655 this.resizeTimeout = setTimeout(function () { 656 that.refresh(); 657 }, this.options.resizePolling); 658 }, 659 660 _transitionTimingFunction: function (easing) { 661 this.scrollerStyle[utils.style.transitionTimingFunction] = easing; 662 663 this.indicator && this.indicator.transitionTimingFunction(easing); 664 }, 665 666 //開始或者中止動畫 667 _transitionTime: function (time) { 668 time = time || 0; 669 this.scrollerStyle[utils.style.transitionDuration] = time + 'ms'; 670 671 //滾動條,咱們這裏只會出現一個滾動條就不搞那麼複雜了 672 this.indicator && this.indicator.transitionTime(time); 673 674 }, 675 676 getComputedPosition: function () { 677 var matrix = window.getComputedStyle(this.scroller, null), x, y; 678 679 matrix = matrix[utils.style.transform].split(')')[0].split(', '); 680 x = +(matrix[12] || matrix[4]); 681 y = +(matrix[13] || matrix[5]); 682 683 return { x: x, y: y }; 684 }, 685 686 _initIndicator: function () { 687 //滾動條 688 var el = createDefaultScrollbar(); 689 this.wrapper.appendChild(el); 690 this.indicator = new Indicator(this, { el: el }); 691 692 this.on('scrollEnd', function () { 693 this.indicator.fade(); 694 }); 695 696 var scope = this; 697 this.on('scrollCancel', function () { 698 scope.indicator.fade(); 699 }); 700 701 this.on('scrollStart', function () { 702 scope.indicator.fade(1); 703 }); 704 705 this.on('beforeScrollStart', function () { 706 scope.indicator.fade(1, true); 707 }); 708 709 this.on('refresh', function () { 710 scope.indicator.refresh(); 711 }); 712 713 }, 714 715 //移動x,y這裏比較簡單就不分離y了 716 _translate: function (x, y, isStep) { 717 718 //處理步長 719 if (this.options.setp && !isStep) { 720 var flag2 = y > 0 ? 1 : -1; //這個會影響後面的計算結果 721 var top = Math.abs(y); 722 var mod = top % this.options.setp; 723 top = (parseInt(top / this.options.setp) * this.options.setp + (mod > (this.options.setp / 2) ? this.options.setp : 0)) * flag2; 724 y = top; 725 } 726 727 this.scrollerStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.translateZ; 728 729 this.x = x; 730 this.y = y; 731 732 if (this.options.scrollbars) { 733 this.indicator.updatePosition(); 734 } 735 736 }, 737 738 resetPosition: function (time) { 739 var x = this.x, 740 y = this.y; 741 742 time = time || 0; 743 744 if (this.y > 0) { 745 y = 0; 746 } else if (this.y < this.maxScrollY) { 747 y = this.maxScrollY; 748 } 749 750 if (y == this.y) { 751 return false; 752 } 753 754 this.scrollTo(x, y, time, this.options.bounceEasing); 755 756 return true; 757 }, 758 759 //移動 760 scrollTo: function (x, y, time, easing) { 761 762 // //l_wang 必須項目高度的整數 763 // if (y < 0 && y > this.maxScrollY && this.options.adjustXY) { 764 // y = this.options.adjustXY.call(this, x, y).y; 765 // } 766 767 768 if (this.options.adjustXY) { 769 y = this.options.adjustXY.call(this, x, y).y; 770 } 771 772 //l_wang 驗證該項是否可選 773 if (this.options.checkSelected) { 774 y = this.options.checkSelected.call(this, x, y).y; 775 } 776 777 easing = easing || utils.ease.circular; 778 779 this.isInTransition = time > 0; 780 781 if (!time || easing.style) { 782 this._transitionTimingFunction(easing.style); 783 this._transitionTime(time); 784 this._translate(x, y); 785 } 786 }, 787 788 //統一的關閉接口 789 disable: function () { 790 this.enabled = false; 791 }, 792 //統一的open接口 793 enable: function () { 794 this.enabled = true; 795 }, 796 797 on: function (type, fn) { 798 if (!this._events[type]) { 799 this._events[type] = []; 800 } 801 802 this._events[type].push(fn); 803 }, 804 805 _execEvent: function (type) { 806 if (!this._events[type]) { 807 return; 808 } 809 810 var i = 0, 811 l = this._events[type].length; 812 813 if (!l) { 814 return; 815 } 816 817 for (; i < l; i++) { 818 this._events[type][i].call(this); 819 } 820 }, 821 destroy: function () { 822 this._initEvents(true); 823 this._execEvent('destroy'); 824 this.indicator && this.indicator.destroy(); 825 826 console.log('destroy') 827 828 }, 829 830 _transitionEnd: function (e) { 831 if (e.target != this.scroller || !this.isInTransition) { 832 return; 833 } 834 835 this._transitionTime(); 836 if (!this.resetPosition(this.options.bounceTime)) { 837 this.isInTransition = false; 838 this._execEvent('scrollEnd'); 839 } 840 }, 841 842 //事件具體觸發點 843 handleEvent: function (e) { 844 switch (e.type) { 845 case 'touchstart': 846 case 'mousedown': 847 this._start(e); 848 break; 849 case 'touchmove': 850 case 'mousemove': 851 this._move(e); 852 break; 853 case 'touchend': 854 case 'mouseup': 855 case 'touchcancel': 856 case 'mousecancel': 857 this._end(e); 858 break; 859 case 'orientationchange': 860 case 'resize': 861 this._resize(); 862 break; 863 case 'transitionend': 864 case 'webkitTransitionEnd': 865 case 'oTransitionEnd': 866 case 'MSTransitionEnd': 867 this._transitionEnd(e); 868 break; 869 } 870 } 871 872 }; 873 874 function createDefaultScrollbar() { 875 var scrollbar = document.createElement('div'), 876 indicator = document.createElement('div'); 877 878 scrollbar.style.cssText = 'position:absolute;z-index:9999'; 879 scrollbar.style.cssText += ';width:7px;bottom:2px;top:2px;right:1px'; 880 scrollbar.style.cssText += ';overflow:hidden'; 881 882 indicator.style.cssText = '-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;position:absolute;background:rgba(0,0,0,0.5);border:1px solid rgba(255,255,255,0.9);border-radius:3px'; 883 indicator.style.width = '100%'; 884 885 scrollbar.appendChild(indicator); 886 887 return scrollbar; 888 } 889 890 function Indicator(scroller, opts) { 891 this.wrapper = typeof opts.el == 'string' ? document.querySelector(opts.el) : opts.el; 892 this.indicator = this.wrapper.children[0]; 893 894 this.wrapperStyle = this.wrapper.style; 895 this.indicatorStyle = this.indicator.style; 896 this.scroller = scroller; 897 898 this.sizeRatioY = 1; 899 this.maxPosY = 0; 900 901 this.wrapperStyle[utils.style.transform] = this.scroller.translateZ; 902 this.wrapperStyle[utils.style.transitionDuration] = '0ms'; 903 //this.wrapperStyle.opacity = '0'; 904 } 905 906 Indicator.prototype = { 907 transitionTime: function (time) { 908 time = time || 0; 909 this.indicatorStyle[utils.style.transitionDuration] = time + 'ms'; 910 }, 911 transitionTimingFunction: function (easing) { 912 this.indicatorStyle[utils.style.transitionTimingFunction] = easing; 913 }, 914 refresh: function () { 915 916 this.transitionTime(); 917 918 var r = this.wrapper.offsetHeight; // force refresh 919 920 this.wrapperHeight = this.wrapper.clientHeight; 921 922 923 this.indicatorHeight = Math.max(Math.round(this.wrapperHeight * this.wrapperHeight / (this.scroller.scrollerHeight || this.wrapperHeight || 1)), 8); 924 this.indicatorStyle.height = this.indicatorHeight + 'px'; 925 926 927 this.maxPosY = this.wrapperHeight - this.indicatorHeight; 928 this.sizeRatioY = (this.scroller.maxScrollY && (this.maxPosY / this.scroller.maxScrollY)); 929 930 this.updatePosition(); 931 }, 932 destroy: function () { 933 this.wrapper.remove(); 934 }, 935 updatePosition: function () { 936 var y = Math.round(this.sizeRatioY * this.scroller.y) || 0; 937 this.y = y; 938 939 //不須要兼容方式了 940 this.indicatorStyle[utils.style.transform] = 'translate(0px,' + y + 'px)' + this.scroller.translateZ; 941 942 }, 943 fade: function (val, hold) { 944 if (hold && !this.visible) { 945 return; 946 } 947 948 clearTimeout(this.fadeTimeout); 949 this.fadeTimeout = null; 950 951 var time = val ? 250 : 500, 952 delay = val ? 0 : 300; 953 954 val = val ? '1' : '0'; 955 956 this.wrapperStyle[utils.style.transitionDuration] = time + 'ms'; 957 958 this.fadeTimeout = setTimeout($.proxy(function (val) { 959 this.wrapperStyle.opacity = val; 960 this.visible = +val; 961 }, this), delay); 962 963 } 964 }; 965 966 IScroll.utils = utils; 967 968 </script> 969 <script type="text/javascript"> 970 971 var s = new IScroll({ 972 wrapper: $('#wrapper'), 973 scroller: $('#scroller'), 974 scrollbars: false, 975 setp: 30 976 }); 977 978 var s1 = new IScroll({ 979 wrapper: $('#wrapper2'), 980 scroller: $('#scroller2'), 981 scrollbars: false, 982 setp: 30 983 }); 984 985 new FastClick(document.body); 986 987 </script> 988 </body> 989 </html>
這裏,咱們將滑動事件綁定到了各個wrapper上,因此不會出現卡的現象,之後各位本身要注意:
這個問題其實比較簡單,只須要每次操做後執行一次refresh,方法便可,這裏重啓一行有點坑爹了
每每最後介紹的方法最爲牛B,不錯,小釵還有一招大殺器能夠解決以上問題,
http://sandbox.runjs.cn/show/s3dqvlfk
1 _start: function (e) { 2 if (!this.enabled || (this.initiated && utils.eventType[e.type] !== this.initiated)) { 3 return; 4 } 5 6 7 //暫時只考慮input問題,有效再擴展 8 var el = document.activeElement; 9 if (el.nodeName.toLowerCase() == 'input') { 10 return; 11 } 12 13 14 var point = e.touches ? e.touches[0] : e, pos; 15 this.initiated = utils.eventType[e.type]; 16 17 this.moved = false; 18 19 this.distY = 0; 20 21 //開啓動畫時間,若是以前有動畫的話,便要中止動畫,這裏由於沒有傳時間,因此動畫便直接中止了 22 this._transitionTime(); 23 24 this.startTime = utils.getTime(); 25 26 //若是正在進行動畫,須要中止,而且觸發滑動結束事件 27 if (this.isInTransition) { 28 this.isInTransition = false; 29 pos = this.getComputedPosition(); 30 var _x = Math.round(pos.x); 31 var _y = Math.round(pos.y); 32 33 if (_y < 0 && _y > this.maxScrollY && this.options.adjustXY) { 34 _y = this.options.adjustXY.call(this, _x, _y).y; 35 } 36 37 //移動過去 38 this._translate(_x, _y); 39 this._execEvent('scrollEnd'); 40 } 41 42 this.startX = this.x; 43 this.startY = this.y; 44 this.absStartX = this.x; 45 this.absStartY = this.y; 46 this.pointX = point.pageX; 47 this.pointY = point.pageY; 48 49 this._execEvent('beforeScrollStart'); 50 51 e.preventDefault(); 52 53 },
每次touchStart的時候如果發現當前得到焦點的是input,便不予理睬了,這個時候滑動效果是系統滑動,各位能夠一試
關於IScroll的研究暫時告一段落,但願此文對各位有幫助,通過此次的深刻學習同時也對小釵的一些問題獲得了處理
我相信將之用於項目重的點會愈來愈多!
如果各位在實際工做中遇到什麼IScroll的疑難雜症能夠留言,有時間小釵願意整理解決方案