用html做的简版flip动画

<!DOCTYPE html>
<html lang="en">
  <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>Document</title>
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }

      .container {
        width: 200px;
        margin: 0 auto;
        display: flex;
        flex-wrap: wrap;
      }

      .container div {
        width: 50px;
        height: 50px;
      }
    </style>
  </head>
  <body>
    <button id="btn_add">添加</button>
    <div class="container"></div>

    <script>
      let divs = null;
      const btnAdd = document.querySelector("#btn_add");
      const container = document.querySelector(".container");

      const data = [
        { id: 1, c: "red" },
        { id: 2, c: "pink" },
        { id: 3, c: "purple" },
        { id: 4, c: "orange" },
        { id: 4, c: "yellow" },
      ];

      // 立即执行函数, 初始渲染 页面的 5 个彩色盒子
      (function render() {
        let html = "";
        for (let i = 0; i < data.length; i++) {
          html += `<div style="background-color: ${data[i].c}">${data[i].id}</div>`;
        }
        container.innerHTML = html;
      })();

      // 函数 获取随机颜色
      function getColor() {
        const r = () => parseInt(Math.random() * 256);
        return `rgb(${r()},${r()},${r()})`;
      }

      // 按钮点击事件
      btnAdd.addEventListener("click", () => {
        // 获取最新的 div 节点集合
        divs = document.querySelectorAll(".container div");
        // 旧的位置
        const oldRect = getRect(divs);
        // 添加元素
        const div = document.createElement("div");
        div.innerText = data.length + 1;
        div.style.background = getColor();
        container.insertBefore(div, divs[0]);
        // 获取渲染之后的位置
        const newRect = getRect(divs);

        // 核心原理: 假如有a, b两个节点, c 和 d 两个位置
        // 开始页面只有一个 a 节点, a 节点在 c 位置
        // 插入一个 b 节点在 a 前面之后, a 节点的位置 从 c 到了 d
        // 我们知道 a 节点在插入前的 位置 c 和 插入后的位置 d
        // 那么渲染的时候, 新插入节点 b 固定在 a 位置
        // a 节点 会出现在 d 位置, 然后通过 css3 转换, 移动到 c 位置 (最开始)
        // 然后 a 节点 从 c 缓慢移动到 d  <== 动画
        // 就造成了的 b 把 a 挤过去 的假象

        for (let i = 0; i < divs.length; i++) {
          const left = -(newRect[i].left - oldRect[i].left);
          const top = -(newRect[i].top - oldRect[i].top);
          const animate = [
            {
              transform: `translate(${left}px, ${top}px)`,
            },
            {
              transform: "translate(0, 0)",
            },
          ];
          divs[i].animate(animate, 300);
        }
      });

      // 函数 获取元素的具体方位
      function getRect(doms) {
        const domArea = [];
        for (let i = 0; i < doms.length; i++) {
          const rect = doms[i].getBoundingClientRect();
          domArea.push({
            top: rect.top,
            left: rect.left,
          });
        }
        return domArea;
      }
    </script>
  </body>
</html>

 

上一篇:C/C++const修饰彻底搞懂


下一篇:Python正则表达式在线练习(网页版)和离线练习(本地版)