js paquete de función de animación lenta

js paquete de función de animación lenta

Una sección del proceso de aprendizaje del curso webAPIs del profesor rosa, ahora tome nota y resuma mis pensamientos. Por último, haz un poco de desarrollo personal.

demanda:

  • Encapsula una función animateX (obj, target, callback), que puede realizar el efecto de animación del movimiento horizontal del objeto del elemento.
  • El parámetro formal obj recibe el objeto de elemento que se va a mover, el objetivo recibe la posición de destino del objeto de elemento y la devolución de llamada es la función de devolución de llamada que se ejecuta después de que el elemento alcanza la posición de destino.
  • Registre los eventos que hacen que la caja alcance las dos posiciones objetivo para los dos botones para verificar la función de la función.
  • La velocidad del elemento se volverá cada vez más lenta a medida que se mueve (animación fácil).
  • El objeto elemento puede moverse hacia adelante y hacia atrás entre dos o más posiciones objetivo, y si se activa un evento de otro objetivo antes de alcanzar la última posición objetivo, el elemento puede girar para alcanzar otra posición en el medio.

Principio de realización

1. Principio de realización de la animación
  • Principio básico: la posición de la caja se mueve constantemente a través del temporizador setInterval ().
  • Pasos de implementación:
    • Obtiene la posición actual del cuadro (obj.offsetLeft).
    • Deje que el cuadro agregue 1 distancia a la posición actual (establezca el valor style.left del cuadro de posicionamiento).
    • Utilice el temporizador para seguir repitiendo esta operación de movimiento.
    • Establezca una condición para finalizar el temporizador, se ha alcanzado la posición de destino o la función de animación se activa de nuevo. (Si el último temporizador no se borra cuando se activa de nuevo, existirán varios temporizadores al mismo tiempo y el error se discutirá a continuación).
2. El principio de realizar el efecto de relajación
  • Principio básico: La distancia entre el elemento y la posición objetivo disminuye durante el movimiento. Al dividir la distancia por 10 como la distancia del movimiento del elemento, se logra el objetivo de reducir continuamente el tamaño del paso (velocidad de movimiento).
  • Pasos de implementación:
    • Active el temporizador para recuperar la posición del elemento actual.
    • Reste la posición actual de la posición objetivo para obtener la distancia total restante de movimiento.
    • Algoritmo central: (valor objetivo-posición actual) / 10 como tamaño de paso (paso).
    • El paso debe redondearse; de ​​lo contrario, no se puede alcanzar la posición objetivo y habrá un problema de decimales.
3. El principio de que el redondeo puede hacer que la caja finalmente alcance la posición de destino.
  • Si el tamaño del paso es un número entero, se redondea.
  • Si el tamaño del paso es negativo, se redondea hacia abajo.
  • principio:
    • Suponiendo que el elemento finalmente alcanza la posición a 10px ~ 20px de la posición de destino, el tamaño del paso será de 2px después de redondear hacia arriba cada vez, y el tamaño del paso será de 1px cuando sea menor o igual a 10px, y finalmente solo 1px El tamaño de paso de 1 px / 10 se redondeará a 1 px.
    • El principio de redondeo hacia abajo de los números negativos es el mismo que el de los números positivos.

Código de implementación final y resultados

Código
<div>
    <button class="btn1">点击到第一个位置100</button>
    <button class="btn2">点击到第二个位置300</button>
    <span></span>
</div>
<script>
    function animateX(obj, target, callback) {
     
     
        // 先清除以前的定时器,只保留当前的一个定时器执行
        clearInterval(obj.timer);
        obj.timer = setInterval(function() {
     
     
            // 步长值写到定时器的里面
            // 把我们步长值改为整数 不要出现小数的问题
            var step = (target - obj.offsetLeft) / 10;
            step = step > 0 ? Math.ceil(step) : Math.floor(step);
            if (obj.offsetLeft == target) {
     
     
                // 停止动画 本质是停止定时器
                clearInterval(obj.timer);
                // 如果传入回调函数则执行,如果没有则不执行
                callback && callback()
            }
            // 把每次加固定值的步长值改为一个慢慢变小的值  步长公式:(目标值 - 现在的位置) / 10
            obj.style.left = obj.offsetLeft + step + 'px';

        }, 15);
    }
    var span = document.querySelector('span');
    var btn1 = document.querySelector('.btn1');
    var btn2 = document.querySelector('.btn2');

    btn1.addEventListener('click', function() {
     
     
        animateX(span, 30);
    })
    btn2.addEventListener('click', function() {
     
     
        animateX(span, 300, function() {
     
     
            span.style.backgroundColor = 'red';
        });
    })
    // 匀速动画 就是 盒子是当前的位置 +  固定的值 10 
    // 缓动动画就是  盒子当前的位置 + 变化的值(目标值 - 现在的位置) / 10)
</script>

resultado

Tenga en cuenta que cuando presiono el botón 2 antes de que el elemento alcance la posición de 300 (se vuelve rojo cuando llega), hago clic en el botón 1 nuevamente, y el elemento se vuelve directamente a la posición de 100, por lo que cumple con la demanda.

Procesamiento de detalles

1. Limpiar el temporizador
  • El temporizador se borra después de que el elemento alcanza la posición de destino para evitar que el elemento ya no se mueva (el paso es 0) después de que llega el elemento, pero el temporizador sigue funcionando, ocupando recursos de memoria.
  • Borre el temporizador antes de que se declare el temporizador. Esto es para evitar que el evento de último clic aún se esté ejecutando, es decir, cuando el temporizador en la última función de animación aún se está ejecutando, hacemos clic en el botón nuevamente o hacemos clic en otro botón para activar otra función de animación. En este momento, habrá varios temporizadores ejecutándose al mismo tiempo en este objeto de elemento. Afecta el estado de movimiento del elemento. Como se muestra abajo.

Cuando el temporizador anterior para el movimiento hacia la derecha no ha finalizado, se inicia otro temporizador de movimiento hacia la izquierda y aparece la situación que se muestra en la figura anterior.

[Error en la transferencia de la imagen del enlace externo. Es posible que el sitio de origen tenga un mecanismo anti-sanguijuelas. Se recomienda guardar la imagen y subirla directamente (img-mE26qa4z-1611173022840) (https://s3.ax1x.com/2021/01 /11/sG3yCQ.gif)]

Sigue tocando el temporizador en la misma dirección para acelerar la animación.

2. Problema con el estado de cuenta del temporizador
  • Al declarar el temporizador, el maestro no ha mencionado borrar el temporizador antes de ejecutar el temporizador declarado, por lo que el maestro usará var timer = setInterval () para cambiar la forma de declarar el temporizador al motivo y la razón para agregar el temporizador como un atributo del objeto obj. La idea es que si varios elementos utilizan esta función de animación, el temporizador debe declararse con var cada vez (ocupando memoria). Podemos usar diferentes temporizadores para diferentes elementos (usamos nuestros propios temporizadores para poder distinguirlos fácilmente). Principio básico: el uso de JS es un lenguaje dinámico que puede agregar atributos fácilmente al objeto actual.
  • Pero cuando miré el código, también pensé en una cosa, es decir, cuando activamos el evento de clic, se generará un alcance de función, y si usamos var para declarar el temporizador, la variable del temporizador es una variable local. Entonces, el código para borrar el temporizador anterior en realidad no equivale a nada. Es decir, el temporizador en otra función de animación no se puede borrar en otra función de animación . Por lo tanto, debemos usar el método anterior para agregar temporizadores.

Algunos pequeños intentos por mi cuenta

Inserte la descripción de la imagen aquí

Agregué una función de control de velocidad a esta función de animación, que se divide en tres niveles. Rápido, velocidad media, velocidad lenta. Por supuesto, seguirá moviéndose con las características de velocidad de la animación lenta durante el proceso (sin cambiar las características de reducción del tamaño del paso). También se ha agregado un efecto de tiempo de proceso, por lo que el elemento no se puede girar antes de que alcance la posición de destino (porque no sé cómo cambiar el tiempo, jaja). Entonces utilicé el método de agregar una válvula de mariposa que el maestro mencionó más adelante. Hay una falla en que los tres botones de control de velocidad aún se pueden presionar cuando los elementos están en movimiento y se pueden cambiar más tarde.

<script>
    var btn1 = document.querySelector('.btn1');
    var btn2 = document.querySelector('.btn2');
    var div1 = document.querySelector('.div1');
    var timeCount = document.querySelector('.time_count'); // 计时的span盒子
    var speed = 0; // 默认速度中等
    var span = document.querySelector('.speed')
    var spans = span.querySelectorAll('span'); // 获取三个速度按键元素

    function animateX(obj, target, timingFunction, callback) {
     
      // speed 可以传入的参数自定义有fast slow medium(默认)
        var init = obj.offsetLeft; // 获得该元素对象初始的位置
        var distance = target - init; // 获得移动的距离
        var stepLength = distance / 10; // 计算步长
        var starTime = +new Date(); // 开始的时间
        var flag = 1;
        var counts = 0;
        if (distance != 0) {
     
     
            var t = setInterval(function(f) {
     
      /* 第一次将flag以参数形式传进计时函数发现里面的定时器会在执行完一次后就清除了即计时只停在100ms */
                f = flag;
                if (!f) {
     
     
                    clearInterval(t);
                }
                var nowTime = +new Date();
                counts = nowTime - starTime;
                timeCount.innerHTML = counts + 'ms';
            }, 200);
        }


        if (timingFunction == 2) {
     
     
            time = 180;
        } else if (timingFunction == 0) {
     
     
            time = 60;
        } else {
     
     
            time = 90;
        } // 处理速度的问题
        // clearInterval(obj.timer); 此时也不需要清除定时器了,因为有函数锁只需要在下面清除即可
        // timesCount(starTime, flag);
        obj.timer = setInterval(function() {
     
     
            if (distance == 0) {
     
      // 移动距离为0时移除定时器并执行回调函数
                window.clearInterval(obj.timer);
                callback && callback();
                flag = 0;
            }
            // 如果移动距离不为0则进行移动
            // 处理不能精确到达目标位置和当目标位置在左边时的情况
            stepLength = stepLength > 0 ? Math.ceil(stepLength) : Math.floor(stepLength);
            obj.style.left = init + stepLength + 'px'; // 使定位的盒子的left值发生改变实现移动效果
            init = obj.offsetLeft; // 重新获取对象的初始位置和还需要移动的距离,为计时器下次执行作准备。
            distance = target - init;
            stepLength = distance / 10;
        }, time);
    }
    // 给三个设置速度的按钮注册事件
    for (var i = 0; i < spans.length; i++) {
     
     
        // 使用立即执行函数
        (function(j) {
     
     
            spans[j].setAttribute('data-speed', j);

        })(i);
        spans[i].addEventListener('click', function() {
     
     
            for (var j = 0; j < spans.length; j++) {
     
     
                spans[j].className = '';
            }
            this.className = 'current';
            speed = this.getAttribute('data-speed');
        })
    }
    // 定义一个计时函数,参数是开始的时间,因为只有动画开始时才计时所以只能在开始时再传参

    var lock = 1; // 设置函数锁防止快速点击出现计时问题
    btn1.onclick = function() {
     
     
        if (lock) {
     
     
            lock = 0;
            animateX(div1, 500, speed, function() {
     
     
                div1.style.backgroundColor = 'black';
                lock = 1;
            })
        }


    }
    btn2.onclick = function() {
     
     
        if (lock) {
     
     
            lock = 0;
            animateX(div1, 0, speed, function() {
     
     
                div1.style.backgroundColor = 'green';
                lock = 1;
            })
        }

    }
</script>

Supongo que te gusta

Origin blog.csdn.net/TKOP_/article/details/112503938
Recomendado
Clasificación