手淘移动端适配的方案学习和相关思考

flexible方案是手淘经过多年的摸索和实战,总结出来的一套移动端适配方案。这个方案在多屏幕适配以及相关bug修复上做的还是不错的。这也是在读了源码之后才有了更深一层的理解,后面会详细解读。

项目回顾

首先来说一下之前做的一个项目,是关于腾讯众创空间的H5活动页面的制作。因为那会是刚去实习没多久,算是刚刚熟悉了公司的业务流程,接着项目组长就给我分配了这样一个任务。说实话,当时刚刚接手这个任务的时候,心理还是有点小兴奋的,毕竟之前理论知识学习了这么久,现在能有机会来个实战,这对于我这个入职不就的实习生来说会是一个不错的实践机会。
在拿到设计部门给的设计稿和思路稿之后,便开始了整个页面的制作。因为毕竟第一次接触移动端的开发,刚开始有点小不适应,上手之后就好了。由于这个项目催的急,自己匆匆忙忙的赶着做,在历经4天时间终于把它搞定了(扯了这么白话,下面来具体说说项目的整个实现流程)。

项目实战

当时设计人员给的设计稿是基于iphone5(640×1136)的。整个页面的布局工作还算比较轻松,比较麻烦是的关键帧动画的延迟时间的控制和背景音乐的按时播放问题(主要是时间轴把握不好)。当时项目组长跟我说前一个动画开始的时间加上这个动画的执行时间就是下一个动画的开始时间。尝试了好多次,最后终于搞定了。在把所有的静态页面都完成之后,剩下的一个最大的任务就是移动端的适配工作了。

移动端的适配

当时采用的方法是:首先通过JS获取到当前设备屏幕的宽度(通过document.documentElement.clientWidth获取到),然后求出当前屏幕的宽度和设计稿宽度的比例(高度的处理方法一致)。最后在脚本文件中,获取到页面的所有图片,根据移动设备的不同,动态修改每一张图片的宽度和高度,当时也结合了CSS3中的vw和vh特性来进行适配。当时由于时间比较紧张,在匆匆忙忙完成适配之后便把所有页面打包发给组长了。至此,自己的第一个H5页面告一段落。

首次尝试存在的问题

后来在手机端测试:页面在普通屏幕下是没有问题,但是在retina屏幕下就会出现图片模糊的情况,这是什么鬼?
经过一番网上查阅资料和思考,得到一个结论:是因为位图像素点不够,从而导致图片模糊。因为自己之前做适配的时候,就拿设计稿的尺寸来说640×1136,而iPhone5的屏幕尺寸是320×568。根据之前的方案,求出的页面缩放比为0.5,而这样做相当于把图片的尺寸缩小了一半,结果就导致1个位图像素对应于4个设备物理像素,就会导致图片模糊(后来想想,这么做就把设计稿大小要×2的效果给破坏了)。

理论上:1个位图像素对应于1个物理像素,图片才能得到完美清晰的展示
关于移动端像素的知识,在这里不多说了,详情见我的这篇博客H5移动端开发学习总结

对于dpr=2的retina屏幕而言,1个位图像素对应于4个物理像素,由于单个位图像素不可以再进一步分割,所以只能就近取色,从而导致图片模糊。
所以,对于图片高清问题,比较好的方案就是两倍图片(@2x)。
如:200×300(css pixel)img标签,就需要提供400×600的图片。
如此一来,位图像素点个数就是原来的4倍,在retina屏幕下,位图像素点个数就可以跟物理像素点个数形成 1 : 1的比例,图片自然就清晰了。

手淘flexible方案学习

原理:在所有资源加载之前执行这个JS。执行这个JS后,会在<html>元素上增加一个data-dpr属性,以及一个font-size样式。JS会根据不同的设备添加不同的data-dpr值,比如说2或者3,同时会给html加上对应的font-size的值,比如说75px。如此一来,页面中的元素,都可以通过rem单位来设置。他们会根据html元素的font-size值做相应的计算,从而实现屏幕的适配效果。
之前也用这个方案写过几个小Demo,最近又找时间把里面的实现原理梳理了一下。

;(function(win, lib) {
   
 //源码部分 
})(window, window['lib'] || (window['lib'] = {}));

这个插件也采用了传统插件的封装形式,采用了匿名函数自执行的方式将代码封装起来。这样做的好处是可以避免全局变量的污染,此外将window作为实现传入匿名函数中,这样一来可以减少全部变量的查找,提高性能。
另外一个参数window[‘lib’] || (window[‘lib’] = {} –> 如果lib已经定义(window[‘lib’]能获取到),就传这个lib,如果没有定义就给lib赋值空对象,并传入lib。为了避免重复定义。
这个时候在flexible.js里面的lib其实就已经是window.lib了(js中对象按引用传递)。

flexible.js源码分析

    var doc = win.document;//获取到document
    var docEl = doc.documentElement;//获取到html
    var metaEl = doc.querySelector('meta[name="viewport"]');//获取到视口标签
    var flexibleEl = doc.querySelector('meta[name="flexible"]');//获取手动设置的meta来控制dpr值
    var dpr = 0;//设备缩放比
    var scale = 0;//屏幕缩放比  dpr与scale是倒数关系
    var tid;//定时器变量
    var flexible = lib.flexible || (lib.flexible = {});

这段代码对相应的dom元素进行了缓存获取,这样可以减少dom的访问次数,毕竟dom操作太昂贵,我们在实际编程中应该尽量减少dom操作。

 //如果页面中存在meta标签
    if (metaEl) {
        con
  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值