年前在一个程序中需要用到摇一摇这个功能,忽然发现 devicemotion 这个事件在 IOS 下不起效果,查了一堆资料终于解决了这个问题。DeviceMotion 是什么?摇一摇这个功能具体怎么实现,在各个设备下需要处理什么样的问题,我们通过一篇文章来好好掰扯掰扯这个事情。
在 window 对象中存在一个专门的事件 devicemotion,这个事件可以用来监听设备的加速度变化等信息.
在该事件的 Event 对象中(DeviceMotionEvent),包含了 acceleration 对象,我们可以同过 acceleration 对象来获取设备的加速度信息。演示代码如下:
acceleration 对象中 x、y、z 分别代表了手机长、宽、厚,3个方向的加速度,具体如下图:
在这里我们已经了解 acceleration 的具体使用,接下来我们是不是就可以上手应用呢?先别急,接下来才是我们的踩坑之旅。接着往下我们来细聊一下,想要在手机上使用 acceleration 还有哪些坑在等着我们。
先从最简单的开始说起,在 安卓 下,使用 acceleration 时,在 X,Y,Z 三个方向取值时,要注意和IOS下刚好相反。
什么意思呢?比如 现在我使用的是一部安卓手机,向左移动,x轴得到一个速度为 10,那么相应 IOS 下 我们拿到的就是一个 -10,其他的Y轴和Z轴同理,处理一下兼容,得出下列代码:
爬过了第一个坑之后,我们继续探坑,上述代码使用 IOS 的小伙伴可能一直看不到效果,这是为什么呢,一个版本一个版本的来说。
在 IOS 一开始的版本中是可以和安卓一样直接运行的,但是从 IOS 10 之后的某个版本(实在记不起来大家原谅), IOS 做了安全限制,要使用 devicemotion 事件则必须使用 https 协议。好吧,那既然官方要求了,咱也没有办法是吧,配吧。
终于在 IOS 协议配置好之后,问题应该能解决吧,少年你把这个问题想得太简单了。
在 IOS 12.2 之后,苹果的开发团队又给我们添了一个大乐子,用户可以在手机的设置关闭掉“动作与方向访问”,如下图所示。如果用户关闭了,那么我们就只能“呵呵”了,顺便说一下,目前为止,开发人员有没有有效的办法直接获取到用户是否关闭了“动作与方向访问”。
这个问题怎么处理呢?我这做了一个取巧的办法,分享给大家,代码如下:
if(!window.DeviceMotionEvent){
alert("您的设备不支持DeviceMotion");
} else {
let timer = setTimeout(function(){
alert('请开启您设备中"动作和方向的权限",否则您将无法使用本应用');
},100);
window.addEventListener("devicemotion",(e)=>{
clearTimeout(timer);
},{once:true});
}
第一步,我们先通过 window.DeviceMotionEvent 排除掉不支持获取加速度的设备,如电脑,如果该设备支持就会有 window.DeviceMotionEvent 这个属性。
第二步,设备如果支持 window.DeviceMotionEvent,开始一个事件监测(这里注意加速度获取时特别敏感的哪怕我们认为我们的手机静止了也会有一些加速给它,所以devicemotion这个事件会时时触发,触发间隔极小),如果该事件没有执行,说明用户关闭了动作和方向的权限。
到这我们解决了 IOS 12.2 之后用户可以关闭权限的问题,那获取加速度的问题就应该解决了吧。但是,苹果的开发团队会就这样放过我们的吗?不要太天真少年!
到了 IOS 13 之后苹果开发团队又开始作妖了,尤其到了现在的 13.3 。
具体怎么回事呢?我们看看下列代码:
这是 IOS 13 之后的,苹果给我新增的一个方法用来获取用户权限,获取到用户权限之后,我们就可以来检测加速度了,但是注意该方法是 IOS 13 之后才有的,在 IOS 13 之前这么写的话,DeviceMotionEvent下并没有requestPermission方法就会报错,另外注意在最新的 IOS 13.3里,该方法需要用户触发获取,所以我们来看看最终版要写成什么样子,代码如下:
到这一步,我们终于有了一个兼容的加速度监听处理,接下来我们就可以看看摇一摇的相关功能实现,这一步就比较简单了。
可以获取到手机的加速度之后,摇一摇的功能就比较简单了。当我们在晃动手机时,手机本身会产生一个加速度。我们可以截取手机的两次加速度比较,中间会有一个差值,当差值大于某个幅度时就可以认定用户进行了摇一摇这个操作。
这里要注意一个问题,在检测用户摇动手机的时候,我们也没有办法预知到用户摇动的是哪一个轴,所以咱们三个轴都会进行检测,具体代码如下:
在这里我们有了一个基本的摇一摇功能,但是还有功能不太完善:
1. 摇一摇这个功能一般我们是在用户停止摇动之后才去做某些事情
2. devicemotion 执行间隔特别的小,可以到达几毫米,但是从性能上来说,我们并不需要这么小的执行间隔,另外用户摇动手机也需要一定时间,基本上没有人可以在几毫米内摇动我们的手机。
3. 前边我们讲的 devicemotion 的兼容处理还没有加进来
我们把这些问题都整体处理一下,代码如下:
ndex = addShake(()=>{
alert(“您进行了摇一摇”)
})
});
closeBtn.addEventListener(“touchend”,()=>{
if(!isStartShake)return;
isStartShake = false;
remveShake(shakeIndex);
});
}
到这一步,我们终于就有了一个比较完整的摇一摇的功能处理函数,当然代码还可以继续处理,比如我们可以把 shake 定义成一个事件等等,不过这些和我们今天要说的主题无关,我就不再复述了。
往期推荐:
使用vue+node搭建前端异常监控系统
想用Vuejs突破20K?这几个面试题必会掌握