共计 3240 个字符,预计需要花费 9 分钟才能阅读完成。
场景
demo 演示记录鼠标在一个区域内的动作,并记录下来。点击回放时,按时序回放动作
源代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title> 鼠标事件记录并回放 </title>
<style>
* {
margin: 0;
padding: 0;
}
.container {
display: flex;
height: 600px;
}
.ctrls {display: flex;}
.ctrls div {flex: 1 1 auto;}
.p-action,
.p-repay {
width: 50%;
height: 100%;
position: relative;
display: flex;
flex-wrap: wrap;
flex-direction: row;
}
.p-action {background: #f0f0f0;}
.p-repay {background: #5aab94;}
.mouse-img {
width: 30px;
position: absolute;
left: 0;
top: 0;
}
.btn {
width: 60px;
height: 30px;
line-height: 2em;
margin: 2em;
background-color: #eee;
display: flex;
justify-content: center;
align-items: center;
}
.btn.hover {background-color: #888888;}
</style>
</head>
<body>
<div class="ctrls">
<div>
<button class="btn" onclick="start()"> 开始记录 </button>
</div>
<div>
<button class="btn" onclick="replay()"> 开始播放 </button>
</div>
</div>
<div class="container">
<div class="p-action">
<button class="btn btn1" onclick="btnClicked(1)">button1</button>
<button class="btn btn2" onclick="btnClicked(2)">button2</button>
<button class="btn btn3" onclick="btnClicked(3)">button3</button>
<button class="btn btn4" onclick="btnClicked(4)">button4</button>
</div>
<div class="p-repay">
<button class="btn btn-r-1" onclick="btnClicked(1)">button1</button>
<button class="btn btn-r-2" onclick="btnClicked(2)">button2</button>
<button class="btn btn-r-3" onclick="btnClicked(3)">button3</button>
<button class="btn btn-r-4" onclick="btnClicked(4)">button4</button>
<img class="mouse-img" style="left:0;top:0;" src="./timg.png" alt="">
</div>
</div>
</body>
<script>
const eventL = [];
const rootEl = document.getElementsByClassName("p-action")[0];
const rootElTop = rootEl.getBoundingClientRect().y,
rootElLeft = rootEl.getBoundingClientRect().x;
const mouseImg = document.getElementsByClassName("mouse-img")[0];
let startTime;
let replayLastEvtTime = 0; // 上一个事件的时间(用于计算下一次事件需要等待时间)// 记录鼠标轨迹
function mouseMove(e) {
store({
evtType: "mousemove",
data: {
x: e.clientX - rootElLeft,
y: e.clientY - rootElTop
}
});
}
// 记录按钮点击事件
function btnClicked(id) {
store({
evtType: "click",
data: {metaId: id,}
});
}
/***
* 记录当前事件
*/
function store(data) {
// 记录当前事件的时间(等待时间:即开始点击开始记录后,多少毫秒后执行这个动作)const time = new Date().getTime();
eventL.push(Object.assign(data, {time: time - startTime}));
}
// 重现
function replay() {console.log("事件总数:", eventL);
rootEl.removeEventListener("mousemove", mouseMove, false);
replayMeta();};
function replayMeta() {let currentEvt = eventL.shift();
if (!currentEvt) {
replayLastEvtTime = 0;
console.log("end……")
return;
}
// 等待本次事件的时间到了才执行,完成后下一次事件进入等待
awateEvtTime(currentEvt.time - replayLastEvtTime)
.then(() => {switch (currentEvt.evtType) {
case "mousemove":
console.log("do mousemove");
mouseImg.style.left = currentEvt.data.x + "px";
mouseImg.style.top = currentEvt.data.y + "px";
break;
case "click":
console.log("do click");
let btn = document.getElementsByClassName("btn-r-" + currentEvt.data.metaId)[0];
btn.classList.add("hover");
setTimeout(() => {btn.classList.remove("hover");
}, 800);
break;
}
replayLastEvtTime = currentEvt.time;
replayMeta();});
}
// 本次事件的需要等待的时间
function awateEvtTime(timeout) {return new Promise((resolve, reject) => {setTimeout(() => {resolve();
}, timeout);
})
}
function start() {rootEl.addEventListener("mousemove", mouseMove, false);
startTime = new Date().getTime();
}
</script>
</html>
效果图
没有 gif -_-!!!
可能存在的问题
- 未测试最大可记录事件数量
- 如果一次事件未在 1ms 内完成,进入下个动作会怎么样
正文完