网页按钮点击动画

2023-11-18

要求

一个按钮,每点击一次在大小可随时变化的按钮表面生成一个实心圆形,对每个圆形配置的时间 T T T(单位:毫秒)内有如下过程:

  1. i i i次点击生成一个圆形 C i C_i Ci,并设置 t i = 0 t_i=0 ti=0
  2. 时间 t i = 0 t_i=0 ti=0时实心圆形直径为0, t i = T t_i=T ti=T时整个按钮表面的任意一点都在圆形内, t i < T t_i<T ti<T时整个按钮表面始终存在一点不在圆形内;
  3. t i = 0 t_i=0 ti=0时圆形透明度为半透明, t i = T t_i=T ti=T时为透明。

实现

动态添加DOM元素

诶哟图丢了

<!DOCTYPE html>
<html>
<style>
    body {
        text-align: center;
        padding: 5rem;
    }

    .content {
        display: inline-block;
        position: relative;
        overflow: hidden;
        margin: 20px;
        box-sizing: border-box;
        transition: all ease-in-out .2s;
    }

    .content:hover {
        background-color: #f001;
    }

    .circle {
        width: 0;
        height: 0;
        border-radius: 100%;
        border-style: solid;
        z-index: 1;
        position: absolute;
        border-color: #f003;
        box-sizing: border-box;
        opacity: 0;
    }

    .text {
        display: table-cell;
        width: 300px;
        height: 100px;
        text-align: center;
        vertical-align: middle;
    }

    @keyframes ani {
        0% {
            border-width: 0px;
            opacity: .8;
            transform: translate(0, 0);
        }

        100% {
            opacity: 0;
        }
    }
</style>

<body>
    <div class="container">
        <span class="content" id="content">
            <div class="text">
                button
            </div>
        </span>
    </div>
</body>

<script>
    const TIME = 500;
    document.getElementById('content').addEventListener(
        'click',
        (e) => {
            var e = event || window.event;
            var target = document.getElementById('content');
            var rect = target.getBoundingClientRect();
            var circle = document.createElement('div');
            circle.className = 'circle'
            var x = e.clientX - rect.left;
            var y = e.clientY - rect.top;
            var w = Math.max(target.offsetWidth - x, x);
            var h = Math.max(target.offsetHeight - y, y);
            var d = Math.sqrt(w * w + h * h);
            circle.style = `border-width:${d}px;left:${x}px;top:${y}px;animation:ani ${TIME}ms ease-out 0s 1;transform:translate(-${d}px,-${d}px)`;
            target.appendChild(circle);
            setTimeout(() => { circle.parentElement.removeChild(circle) }, TIME); // 动画结束就去掉元素,要不然元素越来越多
        }
    )
</script>

</html>

canvas动画+Interval

诶哟图丢了

<!DOCTYPE html>
<html>
<style>
    body {
        text-align: center;
        padding: 5rem;
    }

    .content {
        display: inline-block;
        position: relative;
        overflow: hidden;
        margin: 20px;
        box-sizing: border-box;
        transition: all ease-in-out .2s;
    }

    .content:hover {
        background-color: #f001;
    }

    #canvas {
        position: absolute;
        left: 0;
        right: 0;
        top: 0;
        bottom: 0;
        width: 100%;
        height: 100%;
    }

    .text {
        display: table-cell;
        width: 30vw;
        height: 10vw;
        text-align: center;
        vertical-align: middle;
    }
</style>

<body>
    <div class="container">
        <span class="content" id="content">
            <canvas id="canvas"></canvas>
            <div class="text">
                button
            </div>
        </span>
    </div>
</body>

<script>
    const TICK = 1000 / 30;
    const TIME = 500;
    const CONTENT = document.getElementById('content');
    const CANVAS = document.getElementById("canvas");
    const DEBUG = document.getElementById("debug");
    const ROUND_RAD = 2 * Math.PI;
    const ZOOM = 3;  // 因为动画很快所以图形边缘是否锐利没那么重要,故适度缩小绘图
    var circles = [];

    CONTENT.addEventListener(
        'click',
        (e) => {
            let rect = CONTENT.getBoundingClientRect();
            let w = CONTENT.offsetWidth;
            let h = CONTENT.offsetHeight;
            let x = (e.clientX - rect.left) / w;
            let y = (e.clientY - rect.top) / h;
            let dx = Math.max(x, 1 - x);
            let dy = Math.max(y, 1 - y);
            circles.push({
                x: x,
                y: y,
                rMax: Math.sqrt(dx * dx + dy * dy) / Math.sqrt(2),
                age: 0,
            })
        }
    )

    function callback () {
        let rect = CONTENT.getBoundingClientRect();  // 元素大小是可变的,考虑到css动画,元素大小和窗口大小也没必然联系
        let width = CONTENT.offsetWidth / ZOOM;
        let height = CONTENT.offsetHeight / ZOOM;
        let scale = Math.sqrt(width * width + height * height);
        CANVAS.width = width;
        CANVAS.height = height;

        var ctx = CANVAS.getContext("2d");
        while (circles[0] && circles[0].deleted) {
            circles.shift();
        }
        for (let i = 0, len = circles.length; i < len; i++) {
            const circle = circles[i];

            var age = circle.age * TICK / TIME;
            var opacity = (1 - age) * .3;
            if (opacity <= 0) {
                circle.deleted = true;
                continue;
            }
            circle.age += 1

            ctx.beginPath();
            ctx.fillStyle = `rgba(255,0,0,${opacity})`;
            ctx.arc(circle.x * width, circle.y * height, age * circle.rMax * scale, 0, ROUND_RAD);
            ctx.fill();
            ctx.closePath();
        }
    }

    setInterval(callback, TICK);
</script>

</html>

canvas动画+requestAnimationFrame

诶哟图丢了

<!DOCTYPE html>
<html>
<style>
    body {
        text-align: center;
        padding: 5rem;
    }

    .content {
        display: inline-block;
        position: relative;
        overflow: hidden;
        margin: 20px;
        box-sizing: border-box;
        transition: all ease-in-out .2s;
    }

    .content:hover {
        background-color: #f001;
    }

    #canvas {
        position: absolute;
        left: 0;
        right: 0;
        top: 0;
        bottom: 0;
        width: 100%;
        height: 100%;
    }

    .text {
        display: table-cell;
        width: 30vw;
        height: 10vw;
        text-align: center;
        vertical-align: middle;
    }
</style>

<body>
    <div class="container">
        <span class="content" id="content">
            <canvas id="canvas"></canvas>
            <div class="text">
                button
            </div>
        </span>
    </div>
</body>

<script>
    const TIME = 500;
    const CONTENT = document.getElementById('content');
    const CANVAS = document.getElementById("canvas");
    const DEBUG = document.getElementById("debug");
    const ROUND_RAD = 2 * Math.PI;
    const ZOOM = 3;
    var circles = [];
    var lastTime = new Date().getTime();

    CONTENT.addEventListener(
        'click',
        (e) => {
            let rect = CONTENT.getBoundingClientRect();
            let w = CONTENT.offsetWidth;
            let h = CONTENT.offsetHeight;
            let x = (e.clientX - rect.left) / w;
            let y = (e.clientY - rect.top) / h;
            let dx = Math.max(x, 1 - x);
            let dy = Math.max(y, 1 - y);
            circles.push({
                x: x,
                y: y,
                rMax: Math.sqrt(dx * dx + dy * dy) / Math.sqrt(2),
                age: 0,
            })
        }
    )

    function callback () {
        let now = new Date().getTime();
        let tick = now - lastTime;
        lastTime = now;
        let rect = CONTENT.getBoundingClientRect();
        let width = CONTENT.offsetWidth / ZOOM;
        let height = CONTENT.offsetHeight / ZOOM;
        let scale = Math.sqrt(width * width + height * height);
        CANVAS.width = width;
        CANVAS.height = height;

        var ctx = CANVAS.getContext("2d");
        while (circles[0] && circles[0].deleted) {
            circles.shift();
        }
        for (let i = 0, len = circles.length; i < len; i++) {
            const circle = circles[i];

            var age = circle.age * tick / TIME;
            var opacity = (1 - age) * .3;
            if (opacity <= 0) {
                circle.deleted = true;
                continue;
            }
            circle.age += 1

            ctx.beginPath();
            ctx.fillStyle = `rgba(255,0,0,${opacity})`;
            ctx.arc(circle.x * width, circle.y * height, age * circle.rMax * scale, 0, ROUND_RAD);
            ctx.fill();
            ctx.closePath();
        }
        requestAnimationFrame(callback);
    }
    requestAnimationFrame(callback);
</script>

</html>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

网页按钮点击动画 的相关文章