場景
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內完成,進入下個動作會怎麼樣