跑马灯效果demo

包含手动拖动,点击暂停,循环播放

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>

    <style>
        .container {
            width: 300px;
            border: solid 2px red;
            overflow: hidden;
            margin: 1em 0;
        }

        .marquee {
            width: fit-content;
            overflow: hidden;
            position: relative;
            display: flex;
        }

        .item {
            padding: 2px 3px;
            background-color: rgb(17, 49, 77);
            margin: 0 5px;
            color: azure;
            font-size: 2em;
            white-space: nowrap;
            user-select: none;
        }

        .marquee-1 {
            background-color: rgb(153, 82, 143);
        }
    </style>
</head>

<body>
    <div class="container">
        <div class="marquee">
            <div class="item">1动画在每个循环中反向播放</div>
            <div class="item">2换句话说,每次动画循环时</div>
            <div class="item">3动画将重置为结束状态并重新开始</div>
        </div>
    </div>

    <div class="container">
        <div class="marquee marquee-1">
            <div class="item">1动画在每个循环中反向播放</div>
            <div class="item">2换句话说,每次动画循环时</div>
            <div class="item">3动画将重置为结束状态并重新开始</div>
        </div>
    </div>
    <script>
        function getTranslateX(element) {
            // 获取元素的transform样式
            let transform = window.getComputedStyle(element).transform || "none";

            // 检查transform是否为none,或者为空字符串
            if (transform === "none" || transform === "") {
                return 0;
            }

            // 正则表达式匹配translateX的值
            // 注意:这个正则表达式假设translateX是transform属性中唯一或第一个出现的变换
            // 如果translateX不是第一个,或者transform包含多个translateX,这个正则表达式可能需要调整
            let matrixValues = transform
                .match(/matrix.*\((.+?)\)/)?.[1]
                .split(",")
                .map(Number);

            // 根据CSS变换矩阵,translateX的值是matrix的第四个元素(索引为3)
            // 注意:如果transform包含的是translate3d(x, y, z),则translateX是第一个元素
            // 这里我们假设只处理2D变换(matrix或translate/translateX)
            if (matrixValues) {
                // 对于matrix(a, b, c, d, e, f),translateX的值是e
                // 但对于translateX(x),我们需要从字符串中直接提取x的值
                // 这里我们假设transform属性只包含translateX或matrix
                if (transform.startsWith("matrix")) {
                    return matrixValues[4] || 0; // 索引从0开始,所以translateX是索引4
                } else if (transform.startsWith("translateX")) {
                    // 直接从transform字符串中提取translateX的值
                    // 假设transform是'translateX(10px)'这样的格式
                    let match = transform.match(/translateX\(([^)]+)\)/);
                    return match ? parseFloat(match[1]) : 0;
                }
            }

            // 如果没有找到translateX,或者transform属性格式不符合预期,返回0
            return 0;
        }

        const PxPerSecond = 100;

        function marquee($marquee, from, to) {
            const animate = $marquee.animate(
                [
                    {
                        transform: `translateX(${from}px)`,
                    },
                    {
                        transform: `translateX(${to}px)`,
                    },
                ],
                {
                    duration: (Math.abs(to - from) / PxPerSecond) * 1000,
                    fill: "forwards",
                }
            );
            animate.addEventListener("finish", (e) => {
                marquee($marquee, 0, to);
            });
        }

        document.querySelectorAll(".container").forEach(($container) => {
            const $marquee = $container.querySelector(".marquee");

            const containerWidth = $container.clientWidth;
            const marqueeWidth = $marquee.offsetWidth;
            const $items = Array.from($marquee.querySelectorAll(".item"));
            const $clones = $items.map(($item) => $item.cloneNode(true));
            //首尾相接,如果不够长多加几次
            $marquee.append(...$clones);

            marquee($marquee, 0, -marqueeWidth);

            let touchStartX = 0;
            $marquee.addEventListener("touchstart", (e) => {
                const currX = getTranslateX($marquee);
                $marquee.getAnimations().forEach((animate) => {
                    animate?.cancel();
                });
                $marquee.style.transform = `translateX(${currX}px)`;

                const [touch] = e.touches;
                touchStartX = touch.clientX;
            });
            $marquee.addEventListener("touchend", (e) => {
                const currX = getTranslateX($marquee);
                marquee($marquee, currX, -marqueeWidth);
            });

            $marquee.addEventListener("touchmove", (e) => {
                e.preventDefault();
                const [touch] = e.touches;
                const currX = getTranslateX($marquee);

                let translateX = currX + touch.clientX - touchStartX;
                // console.log(
                //   touch.clientX,
                //   touchStartX,
                //   currX,
                //   translateX,
                //   marqueeWidth
                // );
                if (translateX < -marqueeWidth) {
                    //最右边
                    translateX += marqueeWidth;
                } else if (translateX >= 0) {
                    translateX -= marqueeWidth;
                }
                $marquee.style.transform = `translateX(${translateX}px)`;
                touchStartX = touch.clientX;
            });
        });
    </script>
</body>

</html>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值