webapp的一大優勢便是在view切換時候可以擁有媲美與native的動畫效果,但是很多時候那只是一種想法,真正的情況卻不是這樣
產生此問題的原因有:
① 手機CPU爛!
② 手機顯卡爛!就算四核其渲染也很有問題
③ 高端手機瀏覽器會有BUG
④ 低端手機支持不好(國內山寨機笑而不語)
因為以上原因,事實上做webapp的都會不同程度的弱化動畫,或者在局部區域使用動畫
問題雖難,總有方案,事實上的情況是,幾行代碼搞死人,就我們的這個動畫問題,前后過手幾輪
最后又回到了我手上,中間甚至經手了國內著名的前端,其中兩位還出過書,所以說動畫老大難問題在移動端是真心難,今天就我所知的動畫做一次分享,希望對各位有幫助,若是有好方案,麻煩賜教一番
難在何處
dom樹過多
view的移動與簡單的圖片slider組件相差甚劇!原因便是其dom結構可能很復雜,大dom樹的移動在移動端效果很差
就簡單列表頁來說,當項目超過100個時,使用IScroll類插件都應該很慎重,這類移動可能非常卡!
而且dom樹復雜度與業務直接相關,我們沒有任何辦法去控制dom樹,因為業務代碼可能不會經過我們的手,就算經過,你又肯定自己做出來的dom樹有多小?不見得吧
長短頁問題
所謂長短頁便是一個view很長一個view很短,這里問題處理十分討厭
首先我們每次做切換需要將view位置切換至頭部(window.scroll(0, 0))如此的話ios中會引起
頁面viewport的變化(系統自動發生),或者會觸發低端工具欄的出現,這個時候頁面抖動無可避免
若是每次不執行window.scroll(0, 0),切換時候又會導致短的view不可見
我現階段想到的解決方案是,移動時候將scroll設得比較大,移動時候將bview的top值與scrollTop相同
最后仍然需要執行window.scroll(0, 0)的操作,所以,這個問題只能緩解,無法解決
手機渲染問題
只要是做移動端的朋友,一定會對三星機或者一些低端機的渲染嗤之以鼻!
具體表現為多次操作style后,后面的操作瀏覽器不會搭理你
解決方案是:
① 引起瀏覽器強烈重繪
② 臨時增刪一個dom結構
但是涉及view切換動畫的話,很有可能會出現一些莫名其妙的問題!
動畫的掙扎
以上是幾個不可避免會遇到的問題,所謂解決方案,也不過自欺欺人
如果不能提高效率,動畫時候最大程度的減小DOM結構便是唯一方法,就算減少render Tree也是一種進步
其基本想法是只顯示視口處的元素,其余不予理睬
1 var FastRender = new inherit({ 2 3 initialize: function(opts) { 4 this.handleOpts(opts); 5 this.init(); 6 }, 7 8 handleOpts: function(opts) { 9 if (!opts || !opts.doms || !opts.doms.length) throw 'FastRender param error'; 10 this.doms = opts.doms; 11 this.container = opts.container || $(window); 12 this.renderContainer = {}; 13 this.step = 50; 14 15 }, 16 17 init: function() { 18 this.initImgContainer(); 19 this.initRender(); 20 this.bindEvents(); 21 }, 22 23 bindEvents: function() { 24 25 //為container綁定事件 26 this.container.on('scroll.fastRender', $.proxy(function() { 27 this.initRender(); 28 }, 29 this)); 30 }, 31 32 initImgContainer: function() { 33 var el, i, len, offset; 34 for (i = 0, len = this.doms.length; i < len; i++) { 35 el = $(this.doms[i]); 36 offset = el.offset(); 37 38 //這塊卡 39 // (function (el) { 40 // setTimeout(function () { 41 el.css({ 42 'width': offset.width, 43 'height': offset.height 44 }); 45 // }, 0); 46 // })(el); 47 48 if (!this.renderContainer[offset.top]) { 49 this.renderContainer[offset.top] = []; 50 } 51 this.renderContainer[offset.top].push(el); 52 } 53 54 }, 55 56 /* 57 這里需要對對象遍歷做優化,以坐標搜索替換數值搜索 58 59 */ 60 initRender: function() { 61 var height = this.container.height(); 62 var srollHeight = this.container.scrollTop(); 63 var k, _imgs, el, i, len, els; 64 65 this.doms.removeClass('wl'); 66 67 for (k in this.renderContainer) { 68 // if ((parseInt(k) < srollHeight + height + this.step) && (parseInt(k) > srollHeight - this.step)) { 69 if ((parseInt(k) < srollHeight + height - this.step) && (parseInt(k) > srollHeight + this.step)) { 70 71 els = this.renderContainer[k]; 72 for (i = 0, len = els.length; i < len; i++) { 73 el = $(els[i]); 74 el.find('.lazy_wrapper').show(); 75 } 76 } else { 77 els = this.renderContainer[k]; 78 for (i = 0, len = els.length; i < len; i++) { 79 el = $(els[i]); 80 el.find('.lazy_wrapper').hide(); 81 } 82 83 } 84 } // for 85 86 }, 87 88 destroy: function() { 89 //為container綁定事件 90 this.container.off('.fastRender'); 91 } 92 93 }); 94 95 var f = new FastRender({ 96 doms: $('.js_hotel_detail') 97 });
這個demo想法很美好,若是可實現的話,無疑是移動端一大功臣,事實上是
瀏覽器:10分
IOS(4000):6分
android小米(1800):5分
化為4核:4分(1800)
其表現在瀏覽器上很好,手機上便不行了,所以今日的論證失敗,該方案還需優化
這個結果其實可以預見,在渲染上手機根本跟不上,所以平滑度就跟不上,方案拋棄
換個方向想,若是可以繞過DOM樹過多問題也是可取,比如移動時候直接以一個白頁做動畫,這個方案比較可恥
另一個方案是使用cavas為本頁面生成一個縮略圖,每次移動實際上是縮略圖,如此動畫是順暢了,但是此方案甚難,還可能引起其它問題,此方案我得再做驗證
結局
結局並不美好,此問題我未找到很好的解決方案,移動端的動畫還有很長的路要走......