shake.js监测手机摇一摇 无法开启重力感应(兼容ios13.3以上)

傅兴平
2023-12-01
/*
 * Author: Alex Gibson
 * https://github.com/alexgibson/shake.js
 * License: MIT license
 */

(function(global, factory) {
    if (typeof define === 'function' && define.amd) {
        define(function() {
            return factory(global, global.document);
        });
    } else if (typeof module !== 'undefined' && module.exports) {
        module.exports = factory(global, global.document);
    } else {
        global.Shake = factory(global, global.document);
    }
} (typeof window !== 'undefined' ? window : this, function (window, document) {

    'use strict';
    function Shake(options) {
        //feature detect
        this.hasDeviceMotion = 'ondevicemotion' in window;

        this.options = {
            threshold: 15, //默认摇动阈值
            timeout: 1000  //默认两次事件间隔时间
        };

        if (typeof options === 'object') {
            for (var i in options) {
                if (options.hasOwnProperty(i)) {
                    this.options[i] = options[i];
                }
            }
        }

        //使用date防止重复调用
        this.lastTime = new Date();

        //accelerometer values
        this.lastX = null;
        this.lastY = null;
        this.lastZ = null;

        //创建自定义事件
        if (typeof document.CustomEvent === 'function') {
            this.event = new document.CustomEvent('shake', {
                bubbles: true,
                cancelable: true
            });
        } else if (typeof document.createEvent === 'function') {
            this.event = document.createEvent('Event');
            this.event.initEvent('shake', true, true);
        } else {
            return false;
        }
    }

    //重置时间计时器
    Shake.prototype.reset = function () {
        this.lastTime = new Date();
        this.lastX = null;
        this.lastY = null;
        this.lastZ = null;
    };

    //开始监听 devicemotion
    Shake.prototype.start = function () {
        this.reset();
        var ua = navigator.userAgent.toLowerCase();
        if (this.hasDeviceMotion) {
            if (ua.indexOf("like mac os x") > 0) {
             // 正则判断手机系统版本
                var reg = /os [\d._]*/gi ;
                var verinfo = ua.match(reg) ;
                var version = (verinfo+"").replace(/[^0-9|_.]/ig,"").replace(/_/ig,".");
                var arr=version.split(".");
                console.log(arr[0]+"."+arr[1]+"."+arr[2]) //获取手机系统版本
                if (arr[0]>12&&arr[1]>2) {  //对13.3以后的版本处理,包括13.3
                    DeviceMotionEvent.requestPermission().then(permissionState => {
                        if (permissionState === 'granted') { //已授权
                             window.addEventListener('devicemotion', this, false);//摇一摇
                        } else if(permissionState === 'denied'){// 打开的链接不是https开头
                            alert("当前IOS系统拒绝访问动作与方向。请退出微信,重新进入活动页面获取权限。")
                        }
                    }).catch((err)=>{
                        	layer.open({
								content: '<div style="height: 50px; text-align: center; padding-top: 20px">苹果设备申请摇动权限</div>',
								btn: '允许',
								// style: 'padding: 50px 30px;',
								shadeClose: false,
								yes: function(index){
									ios13granted();
									layer.close(index);
								}
							})
                    });
                }else{  //13.3以前的版本
                   window.addEventListener('devicemotion', this, false);

                }
   
     } else {
            window.addEventListener('devicemotion', this, false);
            }
        }
    };
    
    function ios13granted() {
    if (typeof DeviceMotionEvent.requestPermission === 'function') {
        DeviceMotionEvent.requestPermission().then(permissionState => {
            if (permissionState === 'granted') {
               var myShakeEvent = new Shake({
                        threshold: 12
                    });
                    myShakeEvent.start();
                    window.addEventListener('shake', function () {
                          start();
                    }, false); //摇一摇
            } else if(permissionState === 'denied'){// 打开的链接不是https开头
                alert("当前IOS系统拒绝访问动作与方向。请退出微信,重新进入活动页面获取权限。")
            }
        }).catch((error) => {
            alert("请求设备方向或动作访问需要用户手势来提示")
        })
    } else {
        // 处理常规的非iOS 13+设备
        alert("处理常规的非iOS 13+设备")
    }
}
    //停止监听 devicemotion
    Shake.prototype.stop = function () {
        if (this.hasDeviceMotion) {
            window.removeEventListener('devicemotion', this, false);
        }
        this.reset();
    };

    //计算是否触发摇动
    Shake.prototype.devicemotion = function (e) {
        var current = e.accelerationIncludingGravity;
        var currentTime;
        var timeDifference;
        var deltaX = 0;
        var deltaY = 0;
        var deltaZ = 0;

        if ((this.lastX === null) && (this.lastY === null) && (this.lastZ === null)) {
            this.lastX = current.x;
            this.lastY = current.y;
            this.lastZ = current.z;
            return;
        }

        deltaX = Math.abs(this.lastX - current.x);
        deltaY = Math.abs(this.lastY - current.y);
        deltaZ = Math.abs(this.lastZ - current.z);

        if (((deltaX > this.options.threshold) && (deltaY > this.options.threshold)) || ((deltaX > this.options.threshold) && (deltaZ > this.options.threshold)) || ((deltaY > this.options.threshold) && (deltaZ > this.options.threshold))) {
            //calculate time in milliseconds since last shake registered
            currentTime = new Date();
            timeDifference = currentTime.getTime() - this.lastTime.getTime();

            if (timeDifference > this.options.timeout) {
                window.dispatchEvent(this.event);
                this.lastTime = new Date();
            }
        }

        this.lastX = current.x;
        this.lastY = current.y;
        this.lastZ = current.z;

    };

    //事件处理
    Shake.prototype.handleEvent = function (e) {
        if (typeof (this[e.type]) === 'function') {
            return this[e.type](e);
        }
    };

    return Shake;
}));

在页面中创建新实例进行调用

//创建实例
 var myShakeEvent = new Shake({
            threshold: 12 // 摇动阈值
        });
// 监听设备动作
        myShakeEvent.start();

//添加一个监听事件
        window.addEventListener('shake', function () {
              start();
}, false);

IOS端无法使用摇一摇功能,主要方法是对devicemotion的监听

 ① 必须是https协议,即打开h5页面的链接开头必须是https://… ②
摇一摇功能开启必须经过用户授权,必须用户手动点击确定。

PS:相关H5页面操作,均是在微信浏览器打开

shakejs是一个摇一摇的工具参看https://blog.csdn.net/chclvzxx/article/details/46325053

 类似资料: