js记录鼠标动作并按发生时间重现

4次阅读

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

可能存在的问题

  1. 未测试最大可记录事件数量
  2. 如果一次事件未在 1ms 内完成,进入下个动作会怎么样
正文完
 0