横竖屏切换检测
事件名:orientationchange
属性:window.orientation
值:90|-90:竖屏 0|180:横屏
function setOrientation() {
switch (window.orientation) {
case 90:
case -90:
alert("竖屏");
break;
default:
console.log("横屏");
break;
}
}
setOrientation();
window.addEventListener("orientationchange",setOrientation)
手机加速度检测
属性:acceleration
window.addEventListener("devicemotion",(e)=>{
const motion = e.acceleration; // 手机加速度
const {x,y,z} = motion;
box.innerHTML = `
x:${x.toFixed(0)}<br/>
y:${y.toFixed(0)}<br/>
z:${z.toFixed(0)}
`;
});
手机重力加速度
属性:accelerationIncludingGravity
window.addEventListener("devicemotion",(e)=>{
const motion = e.accelerationIncludingGravity; // 手机加速度 + 重力
const {x,y,z} = motion;
box.innerHTML = `
x:${x.toFixed(0)}<br/>
y:${y.toFixed(0)}<br/>
z:${z.toFixed(0)}
`;
});
体感操作
(IOS系统)
let box = document.querySelector("#box");
let translateX = 0;
let translateY = 0;
// 监听手机加速度发生变化
window.addEventListener("devicemotion",(e)=>{
const motion = e.accelerationIncludingGravity; // 手机加速度 + 重力
const motion2 = e.acceleration; // 加速度
let {x,y} = motion;
let {x:x2,y:y2} = motion2;
x -= x2;
y -= y2;
/*x=-x;y=-y;(Android系统需加上)**/
translateX += x;
translateY -= y;
box.style.transform = `translate(${translateX}px,${translateY}px)`;
});
加速检测系统存在的问题
-
安卓下和IOS的差异
安卓下 和 IOS 下,加速度方向取值相反:如 IOS x = 10,安卓 x = -10;IOS y = 10,安卓 y = -10,IOS z = 10,安卓 z = -10
-
协议问题
IOS 中,如果要使用加速度 API,当前应用则必须使用 https 协议
-
IOS12.2
IOS 12.2 中,用户可以在手机设置中关闭掉,动作与方向的访问权限
-
IOS13
IOS 13 及之后,当应用中想要使用动作与方向的访问权限时,需要请求用户授权。
-
IOS13.3
IOS 13.3 及之后,申请授权,必须用户手动触发。 统一解决
// 在 IOS 12 中,判断用户是否关闭了动作与方向的访问权限
{
let timer = setTimeout(() => {
alert("请开启动作与方向的访问权限,否则将无法使用本应用");
}, 200);
window.addEventListener("devicemotion", () => {
clearTimeout(timer);
}, { once: true });
}
// 判断当前是否是安卓系统
function isAndroid() {
const u = window.navigator.userAgent;
return u.indexOf("Android") > -1 || u.indexOf("Adr") > -1;
}
/*
setMotion 设置监听加速变化要处理的事情
cb 加速度变化后要做的处理函数
return 取消事件注册
*/
function setMotion(cb) {
let fn = (e) => {
if (isAndroid()) { // 处理安卓取反问题
e.acceleration.x = -e.acceleration.x;
e.acceleration.y = -e.acceleration.y;
e.acceleration.z = -e.acceleration.z;
e.accelerationIncludingGravity.x = -e.accelerationIncludingGravity.x;
e.accelerationIncludingGravity.y = -e.accelerationIncludingGravity.y;
e.accelerationIncludingGravity.z = -e.accelerationIncludingGravity.z;
}
cb(e);
};
// 区分 IOS 13 及之前
if (typeof DeviceMotionEvent.requestPermission === "function") { // IOS 13 及之后
DeviceMotionEvent.requestPermission()
.then(permissionState => {
if (permissionState === 'granted') {
// 权限允许
window.addEventListener("devicemotion", fn);
}
}).catch(() => {
alert("请开启授权否则无法使用本应用");
})
} else { //安卓及IOS 13之前
window.addEventListener("devicemotion", fn)
}
return ()=>{
window.removeEventListener("devicemotion",fn);
}
}
防抖和节流
防抖
隔一段事件执行,希望函数只执行一次,哪怕进行了多次调用
/*
debounce 防抖函数
fn:需要进行防抖的函数
deley: 防抖时长
start: 是否在开始时执行函数
return 经过防抖处理的函数
*/
function debounce(fn, deley = 200, start = false) {
let timer;
return function (...args) { // 经过防抖处理的函数
const _this = this;
if(timer){
clearTimeout(timer);
}
start && fn.apply(_this, args);
timer = setTimeout(() => {
(!start) && fn.apply(_this, args);
}, deley);
}
}
节流
减少执行频率,让函数保持在一个可接受的固定频率执行
/**
* 节流
* fn:
* dalay:
* start:
* return
*/
function throttle(fn,deley = 200,start = true) {
let timer;
return function(...args) { // 经过防抖处理的函数
const _this = this;
if(timer){
return;
}
start&&fn.apply(_this,arg);
timer = setTimeout(() => {
(!start)&&fn.apply(_this,args);
timer = null;
}, deley);
}
}
function throttle(fn, deley = 200, start = true) {
let startTime = Date.now();
return function (...args) {
const _this = this;
if (Date.now() - startTime < deley) {
return;
}
startTime = Date.now();
start && fn.apply(_this, args);
}
}
写一个摇一摇
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button id="btn">开启摇一摇</button>
<button id="stopBtn">关闭摇一摇</button>
<div id="info"></div>
<script src="motion.js"></script>
<script>
let btn = document.querySelector("#btn");
let stopBtn = document.querySelector("#stopBtn");
/*
摇一摇:当前次的加速度和上一次的加速之间有了一个比较大的差值
*/
function throttle(fn, deley = 200, start = true) {
let timer = 0;
return function (...arg) { // 经过防抖处理的函数
const _this = this;
if (timer) {
return;
}
start && fn.apply(_this, arg);
timer = setTimeout(() => {
(!start) && fn.apply(_this, arg);
timer = 0;
}, deley);
}
}
/*
setShake 摇一摇
ops : {
start:fn // 开始摇一摇时要做的事情
shake:fn // 摇一摇中要做得事情
end: fn// 摇一摇结束后要做的事情
}
*/
function setShake(ops) {
const { start = () => { }, shake = () => { }, end = () => { } } = ops;
let lastX = 0,
lastY = 0,
lastZ = 0;
const maxRange = 50;
const minRange = 5;
let isShake = false;
const unMotion = setMotion(throttle((e) => {
const { x, y, z } = e.acceleration;
const range = Math.abs(x - lastX) + Math.abs(y - lastY) + Math.abs(z - lastZ);
if (range > maxRange && (!isShake)) {
start(e);
isShake = true;
} else if (range > maxRange && isShake) {
shake(e);
} else if (range < minRange && isShake) {
end(e);
isShake = false;
}
lastX = x;
lastY = y;
lastZ = z;
}));
return unMotion; //取消摇一摇监听
}
let unShake;
btn.addEventListener("touchend", () => {
unShake = setShake({
start:()=>{
info.innerHTML += "开始摇一摇<br/>";
},
shake:()=>{
info.innerHTML += "摇一摇中<br/>";
},
end: ()=>{
info.innerHTML += "摇一摇结束<br/>";
}
})
});
stopBtn.addEventListener("touchend",()=>{
if(unShake){
unShake();
}
})
</script>
</body>
</html>