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为本页面生成一个缩略图,每次移动实际上是缩略图,如此动画是顺畅了,但是此方案甚难,还可能引起其它问题,此方案我得再做验证
结局
结局并不美好,此问题我未找到很好的解决方案,移动端的动画还有很长的路要走......