20230315----重返学习-动画-轮播图

day-028-twenty-eight-20230315-动画-轮播图

动画

动画的处理

  1. css3的动画
    • transform 是变形属性,不是动画

      • translate 位移
      • scale 缩放
      • rotate 旋转
      • skew 倾斜
      • matrix 矩阵
    • transition 过渡动画

      • 步骤: 设置过渡效果,当改变元素样式的时候,会按照过渡效果进行运动
        • transition-property: all;
        • transition-duration: 0.3s;
        • transition-timing-function: linear;
        • transition-delay: 0s;
      • 简写: transition:property duration timing-function delay;
    • animation 帧动画

      • 步骤
        • 首先基于@keyframes设置动画运动的轨迹( 0%[from] -> 100%[to]),即关键帧名称
        • 最后基于animation按照指定的轨迹进行播放运动
          • animation-name: 关键帧名称; 要执行动画的关键帧名称
          • animation-duration: 0s; 动画持续时间
          • animation-timing-function: linear; 动画运动函数,即运动方式
          • animation-delay: 0ms; 动画延迟时间
          • animation-iteration-count: 5; 动画执行次数
          • animation-direction: reverse; 动画执行方向
          • animation-fill-mode: both; 动画填充模式,即动画运动终点与动画运动起点的关系
          • animation-play-state: paused/running; 动画播放状态
          • 简写: animation: name duration timing-function delay iteration-count direction fill-mode;
    • css3动画方案选取规则

      • 简单动画优先使用transition复杂动画使用animation
      • 如果运动轨迹/运动样式需要动态管理的,则使用transition
    • 总原则:

      • 能用CSS3解决的动画,优先使用CSS3 - 性能体验最好
      • CSS3解决不了的,再基于js实现
      • 如果js解决不了,很早之前是基于flash处理。现在应该直接换需求,不行可能是产品经理问题
  • 设置动画
    • JavaScriptcss3组合
      • 一般是用css3先设置过渡用css3先设置动画帧,之后用JavaScript元素的样式
        • JavaScript配合css3先设置过渡

          • 也可以在JS中设置元素的过渡效果

          • 也可以使用ontransitionend()DOM元素对象上监听DOM元素对象运行结束后的事件

            • 几个样式发生过渡效果,则transitionend事件就会被触发几次
            DOCTYPE html>
            <html>
            <head>
                <meta charset="UTF-8">
                <meta http-equiv="X-UA-Compatible" content="IE=edge">
                <meta name="viewport" content="width=device-width, initial-scale=1.0">
                <title>动画title>
                <style>
                    .box {
                        position: absolute;
                        top: 10px;
                        left: 10px;
                        box-sizing: border-box;
                        width: 100px;
                        height: 100px;
                        background: lightcoral;
            
                        transition: all 1s linear;/* 1. 设置过渡效果 */
                    }
                style>
            head>
            
            <body>
                <div class="box" id="box">div>
            
                
                <script>
                    let box = document.querySelector('#box');
                    // 可以在JS中设置元素的过渡效果
                    // box.style.transition = 'all 1s linear';
                    box.style.transitionDuration = '2s';
                    box.onclick = function () {
                        // 2. 直接改元素的样式,元素就会按照指定的过渡效果去运动
                        this.style.top = '210px';
                        this.style.left = '310px';
                    };
                    // 3. 我们还可以监听到元素运动结束/开始等阶段,从而做一些事情
                    box.ontransitionend = function () {
                        // 有几个样式(方向)发生过渡效果,则transitionend事件就会被触发几次
                        console.log('哈哈哈,我终于运动完成了!');
                    };
                script>
            body>
            html>
            
        • JavaScript配合css3先设置动画帧

          1. 设置动画关键帧名称关键帧具体参数

          2. 设置单独的动画类

          3. JavaScriptDOM元素对象设置动画

            • 可以直接设置style的animation属性
            • 也可以给元素设置样式类,来控制播放
            DOCTYPE html>
            <html>
              <head>
                <meta charset="UTF-8" />
                <title>动画title>
                <style>
                  .box {
                    position: absolute;
                    top: 10px;
                    left: 10px;
                    box-sizing: border-box;
                    width: 100px;
                    height: 100px;
                    background: lightcoral;
                  }
            
                  /* 2. 设置单独的动画类.run */
                  .box.run {
                    animation: run 2s linear 0s both;
                  }
                  /* 1. 设置动画关键帧名称和关键帧具体参数 */
                  @keyframes run {
                    0% {
                      top: 10px;
                      left: 10px;
                    }
            
                    100% {
                      top: 210px;
                      left: 310px;
                    }
                  }
                style>
              head>
            
              <body>
                <div class="box" id="box">div>
            
                <script>
                  let box = document.querySelector("#box");
                  box.onclick = function () {
                    // 3-1. 可以直接设置style的animation属性
                    // this.style.animation = 'run 2s linear 0s both';
            
                    // 3-2. 我们更喜欢给元素设置样式类,来控制播放
                    this.classList.add('run');
                    console.log("变量--->");
                  };
                  box.onanimationend = function () {
                    // 帧动画结束后触发的事件
                    console.log("哇咔咔");
                  };
                script>
              body>
            html>
            

animate.css

  • 直接用,用单个粘贴复制
    • 直接用
      1. 引入css文件

      2. 给DOM元素对象设置类名

        • this.className='box animate__animated animate__infinite animate__bounce'
        • 基础类 animate__animated
        • 无限循环 animate__infinite
        • 效果类 animate__bounce
        DOCTYPE html>
        <html>
        
        <head>
            <meta charset="UTF-8">
            <title>动画title>
            <link rel="stylesheet" href="css/animate.min.css">
            <style>
                .box {
                    position: absolute;
                    top: 10px;
                    left: 10px;
                    box-sizing: border-box;
                    width: 100px;
                    height: 100px;
                    background: lightcoral;
                }
            style>
        head>
        
        <body>
            <div class="box" id="box">div>
        
            <script>
                let box = document.querySelector('#box');
                box.onclick = function () {
        
                    // 基于animate.css管理运动效果
                    this.className = 'box animate__animated animate__infinite animate__bounce';
                };
                box.onanimationend = function () {
                    // 帧动画结束后触发的事件
                    console.log('哇咔咔');
                };
            script>
        body>
        
        html>
        

原生JavaScript动画

JavaScript的动画基于定时器处理

  • 定时器

    • setTimeout(callback,interval)

      • 到达时间只执行一次定时器结束了,后续不再触发执行
        • 但是结束不代表清除
    • setInterval(callback,interval)

      • 轮询定时器,每间隔一段时间,都会把定时器触发执行,直至手动清除定时器
      • callback 回调函数-定时器到时间后执行的回调函数
      • interval 时间因子-需要等待的时间
    • clearTimeout()/clearInterval() 清除定时器

    • 定时器的返回值: 数字,代表当前设置的定时器系统中的第几个定时器

      • 每一次定时器结束后,最好手动从系统中移除该定时器
        • clearTimeout()传递一个数字,就是把系统中编号为这个数字的定时器移除掉
          • 不论是setTimeout()还是setInterval(),只要设置定时器编号就会累积,所以基于任何一种清除定时器的方法(clearTimeout()/clearInterval()),只要把编号传递进来,都可以清除指定编号的定时器
    • 把控定时器是否已经设置

      //只有等上一次点击创建的定时器被清除后,都会创建新的定时器
      //依据 timer是否为null,如果是null,就认为已经清除了。但是需要我们在每一次从系统中移除定时器后,手动把timer赋值为null才可以。
      let timer = null;
      document.onclick = function () {
        console.log("console");
        if (timer === null) {
          timer = setTimeout(function () {
            console.log("定时器");
            clearTimeout(timer);//从系统中移除了编号为timer的定时器,但是此时timer的值还是数字。
            timer = null//手动赋值timer为初始值
          }, 1000);//定时器编号数字
        }
      };
      
      • 用一个初始值为null的变量来存储定时器返回的编号
      • 定时器执行后,手动清除定时器后把变量手动设置为null
      • 之后判断变量是否为null,来判断是否已经设置了定时器
    • 养成习惯: 定时器一旦设置了,就用变量存储定时器编号定时器执行完就要清除定时器,并手动把变量设置为初始值null

      • 每一个定时器执行完毕,我们都最好把从系统中移除掉

        // 需求:每隔1秒中,让数字累加1,但是累加到5后,则结束累加操作
        
        let timer = null;
        let num = 0;
        timer = setInterval(() => {
            num++;
            console.log(num);
            // 累加到了5,则结束定时器
            if (num === 5) {
                clearInterval(timer);
                timer = null;
            }
        }, 1000);
        
        /* // 思路:循环设置5个定时器,但是执行的时间需要间隔开
        let num = 0;
        for (let i = 1; i <= 5; i++) {
            let timer = null;
            timer = setTimeout(() => {
                num++;
                console.log(num);
                // 每一个定时器处理完毕,我们都最好把其从系统中移除掉
                clearTimeout(timer);
                timer = null;
            }, i * 1000);
        } */
        
        /* // 基于递归操作,还是设置5个定时器
        let num = 0,
            timer = null;
        const sum = function sum() {
            // 每一次执行sum,首先清除上一次设置的定时器
            clearTimeout(timer);
            num++;
            console.log(num);
            if (num === 5) {
                timer = null; //当递归结束,不再设置新的定时器的时候,再把timer赋值为null即可
                return;
            };
            timer = setTimeout(sum, 1000);
        };
        timer = setTimeout(sum, 1000); */
        
  • requestAnimationFrame(指定的回调函数)

    • 类似于setTimeout()定时器,只不过不需要指定等待的时间
      • 电脑有一个屏幕刷新率: 1秒内屏幕刷新了多少次
        • 一般都是60次,但还有120次
          • 60次(60HZ)计,大概16.666...毫秒刷新一次
    • 它会自动按照电脑屏幕刷新率的时间进行处理
      • 会等待到每次屏幕刷新的时候,把指定的回调函数执行一次

        requestAnimationFrame(() => {
            console.log('哇咔咔');
        });
        

DOM元素样式

  • 设置DOM元素的样式
    • 元素.style.xxx = xxx样式设置在元素的行内
      • 优势: 这样设置样式优先级
    • 样式类名
      • 元素.className='xxx'
      • 元素.classList.add('xxx')/元素.classList.remove('xxx')
      • 样式表先把样式写好,最后在JavaScript中,基于操作样式类名,来管理DOM元素的样式
  • 获取DOM元素的样式
    • 元素.style.xxx 只能获取写在元素行内上的样式
      • 不常用,因为一般很少把样式写在行内上
    • window.getComputedStyle(元素,伪类) 获取元素(或者其伪元素{::after/::before})所有经过浏览器计算过的样式
      • 只要DOM元素浏览器渲染了,那么其所有的样式都是经过计算的,不管我们以何种方式编写的样式,即不管是用JavaScript写的还是css样式表的
      • 即便不写样式浏览器也会为被渲染的DOM元素设置默认样式

JavaScript写动画步骤

  • 方案一: 固定步长匀速运动

    • setTimeout()setInterval()

      • 设置定时器,每间隔16ms一步

      • 首先获取现在元素的样式

      • 每一步都是在当前样式的基础上加步长即可

      • 最新的样式赋值给现在元素

      • 最后做一个边界处理

        <div class="box" id="box">div>
        <script>
          const run2 = function run2() {
            let box = document.querySelector("#box");
            //初始位置10px 结束位置310px 总距离300px
            //方案一: 固定步长的匀速运行
            let step = 2;
            let timer = null;
            timer = setInterval(() => {
              //1. 首先获取现在元素的样式
              let obj = window.getComputedStyle(box);
              let currentLeft = parseFloat(obj.left);
              let currentTop = parseFloat(obj.top);
        
              //2. 在此基础上累加步长
              currentLeft += step;
              currentTop += step;
        
              //4. 边界处理
              if (currentLeft >= 310) {
                currentLeft = 310;
              }
              if (currentTop >= 210) {
                currentTop = 210;
              }
              if (currentLeft >= 310 && currentTop >= 210) {
                //所有方向都到达边界时
                box.style.left = `310px`;
                box.style.top = `210px`;
        
                clearInterval(timer);
                timer = null;
                return;
              }
        
              //3. 再把最新的样式赋值给元素
              box.style.left = currentLeft + `px`;
              box.style.top = currentTop + `px`;
            }, 16); //一般设置的时间就是16毫秒走一次,为了贴进于60HZ刷新率。
          };
          run2();
        script>
        
    • requestAnimationFrame()

      • 基于它实现动画,只能固定步长,不能固定时间

        DOCTYPE html>
        <html>
        
        <head>
            <meta charset="UTF-8">
            <meta http-equiv="X-UA-Compatible" content="IE=edge">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>动画title>
            <style>
                .box {
                    position: absolute;
                    top: 10px;
                    left: 10px;
                    box-sizing: border-box;
                    width: 100px;
                    height: 100px;
                    background: lightcoral;
                }
            style>
        head>
        
        <body>
            <div class="box" id="box">div>
        
            <script>
                // requestAnimationFrame:基于它实现动画,只能固定步长,不能固定时间
                let box = document.querySelector('#box'),
                    targetLeft = 310,
                    stepLeft = 2;
                const move = function move() {
                    // 获取当前最新的位置
                    let curLeft = parseFloat(getComputedStyle(box).left);
                    // 累加步长
                    curLeft += stepLeft;
                    // 边界判断
                    if (curLeft >= targetLeft) {
                        box.style.left = targetLeft + 'px';
                        return;
                    }
                    // 运动到这个位置
                    box.style.left = curLeft + 'px';
                    // 轮询控制move的执行
                    requestAnimationFrame(move);
                };
                move();
            script>
        body>
        
        html>
        
  • 方案二: 固定时间匀速运动

    • 真实项目中的动画,一般都是固定时间的动画

      DOCTYPE html>
      <html>
      
      <head>
          <meta charset="UTF-8">
          <title>动画title>
          <style>
              .box {
                  position: absolute;
                  top: 10px;
                  left: 10px;
                  box-sizing: border-box;
                  width: 100px;
                  height: 100px;
                  background: lightcoral;
              }
          style>
      head>
      
      <body>
          <div class="box" id="box">div>
      
          <script>
              /* 真实项目中的动画,一般都是固定时间的运动 */
              // 计算元素当前位置的匀速运动公式
              // t:time已经运动的时间  b:begin元素的起始位置  c:change运动的总距离  d:duration总时间
              const Linear = (t, b, c, d) => {
                  // t/d:已经运动的时间除以总时间 -> 已经运动的比例
                  // 已经运动的比例*总距离 -> 已经运动的距离
                  // 已经运动的距离+起始位置 -> 元素当前的位置
                  return t / d * c + b;
              };
      
              let box = document.querySelector('#box'),
                  objStyle = getComputedStyle(box),
                  beginLeft = parseFloat(objStyle.left),
                  beginTop = parseFloat(objStyle.top),
                  changeLeft = 310 - beginLeft,
                  changeTop = 210 - beginTop,
                  duration = 2000,
                  time = 0,
                  timer = null;
              const move = function move() {
                  // 运动的时间累计
                  time += 16;
                  // 边界处理:已经运动的时间超过总时间
                  if (time >= duration) {
                      box.style.left = '310px';
                      box.style.top = '210px';
                      clearInterval(timer);
                      timer = null;
                      return;
                  }
                  // 基于Liner公式获取到当前元素各方向的位置
                  let curLeft = Linear(time, beginLeft, changeLeft, duration),
                      curTop = Linear(time, beginTop, changeTop, duration);
                  // 按照计算的结果运动
                  box.style.left = curLeft + 'px';
                  box.style.top = curTop + 'px';
              };
              move();
              timer = setInterval(move, 16);
          script>
      body>
      
      html>
      
  • 方案三:

jQuery动画

  • 少用或者没人用了,但它的api好用。

    • 有蛮多第三方库参考了它的设计
    • 代码少简洁
  • jQuery中的动画都是基于JS/定时器实现的匀速运动动画

    • 不如CSS3动画性能
DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title>动画title>
    <style>
        .box {
            position: absolute;
            top: 10px;
            left: 10px;
            box-sizing: border-box;
            width: 100px;
            height: 100px;
            background: lightcoral;
        }
    style>
head>

<body>
    <div class="box" id="box">div>

    
    <script src="js/jquery.min.js">script>
    <script>
        let $box = $('#box');
        $box.animate({
            left: 310,
            top: 210,
            width: 300
        }, 2000, () => {
            console.log('动画运动完毕后触发');
        });

        /* let $box = $('#box');
        // JQ中的动画都是基于“JS/定时器”实现的匀速运动动画「都不如CSS3动画性能好」
        $box.click(function () {
            // 快捷动画:需要我们设定运动的时间「或者是'fast/slow'」
            //  + hide/show/toggle
            //  + fadeOut/fadeIn/fadeToggle
            //  + slideUp/slideDown/slideToggle
            $box.slideUp(2000);
        }); */

        /* // 固定时间的匀速运动:就是把我们刚才写的那套代码做了封装
        //  + finish:结束正在运行的动画{让元素立即处于上一个动画最后一帧的位置}
        //  + stop:也是结束正在运行的动画,只不过在哪停止的,元素就在哪个位置
        $box.finish().animate({
            left: 310,
            top: 210,
            width: 300
        }, 2000, () => {
            console.log('动画运动完毕后触发');
        }); */
    script>
body>

html>

轮播图

  • swiper

    1. 引入css文件js文件
    2. 建立HTML骨架使用swiper的类名来做
    3. jsnew Swiper()建立一个swiper实例,并配置好。
      • 最好用一个变量保存这个实例,以便后面进行操作
    4. 浏览器控制台查看swiper实例html骨架,复制想要改的样式类名,在本地的css中改对应样式类名的样式
    DOCTYPE html>
    <html>
    
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>基于Swiper实现轮播图title>
        
        <link rel="stylesheet" href="css/reset.min.css">
        <link rel="stylesheet" href="css/swiper-bundle.min.css">
        <style>
            .swiper,
            .swiper-slide,
            .swiper-slide img {
                width: 800px;
                height: 300px;
            }
    
            .swiper-pagination-bullet {
                width: 12px;
                height: 12px;
            }
    
            .swiper-pagination-bullet-active {
                width: 30px;
                border-radius: 6px;
            }
        style>
    head>
    
    <body>
        <div class="swiper" id="AAA">
            <div class="swiper-wrapper">
                <div class="swiper-slide">
                    <img src="images/1.jpg" alt="">
                div>
                <div class="swiper-slide">
                    <img src="images/2.webp" alt="">
                div>
                <div class="swiper-slide">
                    <img src="images/3.webp" alt="">
                div>
                <div class="swiper-slide">
                    <img src="images/4.webp" alt="">
                div>
            div>
            <div class="swiper-pagination">div>
            <div class="swiper-button-prev">div>
            <div class="swiper-button-next">div>
        div>
    
        
        <script src="js/swiper-bundle.min.js">script>
        <script>
            let sw = new Swiper('#AAA', {
                /* 基于这些配置,告诉Swiper插件我想要的效果 
                https://www.swiper.com.cn/api/index.html */
                // 开启无限循环切换「实现了无缝衔接」
                loop: true,
                // 开启自动切换
                autoplay: {
                    delay: 3000,
                    disableOnInteraction: false
                },
                // 控制切换效果
                // "slide"(普通位移切换)、"fade"(淡入)、"cube"(方块)、"coverflow"(3d流)、"flip"(3d翻转)、"cards"(卡片式)
                effect: 'slide',
                // 开启分页器
                pagination: {
                    el: '.swiper-pagination',
                    clickable: true
                },
                // 开启导航按钮
                navigation: {
                    nextEl: '.swiper-button-next',
                    prevEl: '.swiper-button-prev'
                },
                // 事件监听
                on: {
                    slideChangeTransitionEnd(sw) {
                        console.log(`当前切换到索引为 ${sw.activeIndex}/${sw.realIndex} 的这一张!`);
                    }
                }
            });
    
            /* setTimeout(() => {
                sw.slideNext(0);
            }, 1000); */
        script>
    body>
    
    html>
    

进阶参考

  1. 牛X轰轰的帧动画库:animate.css - 帧动画库- css动画库,用类名控制动画效果
  2. 查询JavaScript函数的兼容性
  3. swiper - 轮播图
  4. animejs.com - JavaScript实际上真正常用的动画库
  5. animejs官方文档-英文的 - JavaScript实际上真正常用的动画库
  6. dynamicsjs.com - 物理效果的动画 - 引入方法,并对DOM元素设置JavaScript动画效果,用法类似于jQuery动画
  7. parallax.js - 偏向于视差的JavaScript动画效果
  8. CreateJS - 游戏引擎 - 用来做h5小游戏的-自然也可以做JavaScript动画效果

你可能感兴趣的:(重返学习,原生js学习,css,学习,动画,css3)