js記錄鼠標動作並按發生時間重現

場景

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 -_-!!!

clipboard.png

可能存在的問題

  1. 未測試最大可記錄事件數量
  2. 如果一次事件未在1ms內完成,進入下個動作會怎麼樣
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章