我们在开发Web App时,通常会遇到一些兼容性问题,orientationchange事件就是其中之一。严格来说,并不是orientationchange有兼容问题,而是触发orientationchange事件回调函数时有兼容问题(很绕口啊)。具体表现在回调函数中获取window.innerWidth与window.innerHeight属性上的差异。
在safari下,对orientationchange支持很好,当orientationchange触发回调时,使用window.innerWidth能或立刻获取到最新的屏幕高宽。
而在Android浏览器下,需要延迟一定的时间,才能获取到正确的屏幕高宽。如果触发回调函数时,立刻使用window.innerWidth,那么,只能取到方向未改变之前的高宽,在Android下使用下面的一个简单试验可以得出结果:
<script type="text/javascript"> alert(window.innerWidth); // 默认竖屏状态,得到屏宽480px; window.addEventListener('orientationchange', function() { alert(window.innerWidth); // 触发orientationchange回调时,得到屏宽还是480px; setTimeout(function() { alert(window.innerWidth); // 延迟300ms,才能得到正确屏宽960px }, 300); }, false); </script>
对于orientationchange的兼容问题,使用proxy函数是很好的一种方法,下面是我给出的一种解决方案:
<script type="text/javascript"> //我的代码库默认依赖了Zepto框架,所以会有Zepto的接口 function createOrientationChangeProxy(fn, scope) { return function() { /* * 如果是Android浏览器,我们设想一种场景,手机从 竖屏-横屏-竖屏-横屏 时, * 这个过程经历了四次切换,但实际我们只需要处理最后一次切横屏的结果, * 那么,延迟300ms执行回调函数,可以在最开始时清除冗余的orientationChangedTimeout。 */ clearTimeout(scope.orientationChangedTimeout); var args = Array.prototype.slice.call(arguments, 0); scope.orientationChangedTimeout = setTimeout($.proxy(function() { /* * 再设想一种场景,手机从 竖屏-横屏-竖屏 时,在这个过程,系统并未改变任何东西, * 将lastOrientation保存下来,能有效的避免垃圾操作产生的回调处理 */ var ori = window.orientation; if (ori != scope.lastOrientation) { fn.apply(scope, args); // 这里才是真正执行回调函数 } scope.lastOrientation = ori; }, scope), $.os.android ? 500 : 0); }; } window.addEventListener('orientationchange', createOrientationChangeProxy(function() { alert(window.innerWidth); // 无论是Safari还是Android浏览器都能正确的输出屏宽 }, window), false); </script>