CSS生成GIF,为什么获取的都是同一帧?

新手上路,请多包涵

我使用html2canvas库截取页面元素,为什么生成的图片全是最后一帧的?
以下代码可直接复制运行

<!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>
</head>
<style>
  .index {
    width: 300px;
    height: 200px;
    background-color: #eee;
  }

  .box {
    width: 100px;
    height: 50px;
    background-color: #bbb;
  }

  .box2 {
    width: 300px;
    height: 200px;
    background-color: #ccc;
  }

  .animate {
    transform: translateX(200px);
    transition: all 3s ease;
  }
</style>

<body>
  <div class="index">
    <button class="btn">do</button>
    <button class="btn2">transform</button>
    <div class="box"></div>
  </div>
  <div class="box2"></div>

</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.5.0-beta4/html2canvas.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gifshot/build/gifshot.min.js"></script>
<script>
  const btn = document.querySelector('.btn')
  const btn2 = document.querySelector('.btn2')
  const ele = document.querySelector('.index')
  const box = document.querySelector('.box')
  const box2 = document.querySelector('.box2')
  let frameArr = []
  btn.addEventListener('click', () => {
    box.classList.add('animate')
    const dur = 3000 // 动画持续时间
    frameArr = [] // 存储每一帧
    const now = Date.now()
    const captureFrame = async () => {
      const canvas = await html2canvas(ele, {
        useCORS: true, // 【重要】开启跨域配置
        scale: window.devicePixelRatio < 3 ? window.devicePixelRatio : 2,
        allowTaint: true, // 允许跨域图片
      })
      const url = canvas.toDataURL("image/png", 1.0)
      console.log('url', url)
      frameArr.push(url)
      if (Date.now() - now < dur) {
        requestAnimationFrame(captureFrame)
      } else {
        console.log('frameArr---22', frameArr)
        // 获取完所有截图后,可以进行下一步操作
      }
    }
    captureFrame()
  })

  btn2.addEventListener('click', () => {
    console.log('btn2 click', frameArr)
    gifshot.createGIF({
      images: frameArr,
      gifWidth: 300,
      gifHeight: 200,
      interval: 0.15,
      numWorkers: 2,
      progressCallback: function (progress) {
        // 显示 GIF 转换进度
        console.log('GIF 转换进度:' + progress * 100 + '%');
      },
      completeCallback: function (gifUrl) {
        // 在页面上显示 GIF 图像
        console.log('GIF 转换完成:' + gifUrl);
      }
    }, (obj) => {
      console.log('obj', obj);
      if (!obj.error) {
        const animatedImage = document.createElement('img');
        animatedImage.src = obj.image
        box2.appendChild(animatedImage);
      }
    });
  })
</script>

</html>
阅读 2.6k
3 个回答

因为 html2canvas,顾名思义,它是自己画的界面,不是直接从浏览器获取的画面截图,那么自然每次 GIF 都是第一帧。

要解决的话,可能必须在截图的时候手动替换成按时间换算出来的那一帧截图。

<!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>
  </head>
  <style>
    .index {
      width: 300px;
      height: 200px;
      background-color: #eee;
    }

    .box {
      width: 100px;
      height: 50px;
      position: relative;
      background-color: #bbb;
      transition: all 0.1s linear;
    }

    .box2 {
      width: 300px;
      height: 200px;
      background-color: #ccc;
    }
  </style>

  <body>
    <div class="index">
      <button class="btn">do</button>
      <button class="btn2">transform</button>
      <div class="box"></div>
    </div>
    <div class="box2"></div>
  </body>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.5.0-beta4/html2canvas.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/gifshot/build/gifshot.min.js"></script>
  <script>
    const btn = document.querySelector(".btn");
    const btn2 = document.querySelector(".btn2");
    const ele = document.querySelector(".index");
    const box = document.querySelector(".box");
    const box2 = document.querySelector(".box2");
    let frameArr = [];
    btn.addEventListener("click", () => {
      box.classList.add("animate");
      let i = 0;
      let timer = setInterval(() => {
        if (i < 200) {
          box.style.left = ++i + "px";
        } else {
          clearInterval(timer);
        }
      }, 50);
      const dur = 3000; // 动画持续时间
      frameArr = []; // 存储每一帧
      const now = Date.now();
      const captureFrame = async () => {
        const canvas = await html2canvas(ele, {
          useCORS: true, // 【重要】开启跨域配置
          scale: window.devicePixelRatio < 3 ? window.devicePixelRatio : 2,
          allowTaint: true, // 允许跨域图片
        });
        const url = canvas.toDataURL("image/png", 1.0);
        console.log("url", url);
        frameArr.push(url);
        if (Date.now() - now < dur) {
          requestAnimationFrame(captureFrame);
        } else {
          console.log("frameArr---22", frameArr);
          // 获取完所有截图后,可以进行下一步操作
        }
      };
      captureFrame();
    });

    btn2.addEventListener("click", () => {
      console.log("btn2 click", frameArr);
      gifshot.createGIF(
        {
          images: frameArr,
          gifWidth: 300,
          gifHeight: 200,
          interval: 0.15,
          numWorkers: 2,
          progressCallback: function (progress) {
            // 显示 GIF 转换进度
            console.log("GIF 转换进度:" + progress * 100 + "%");
          },
          completeCallback: function (gifUrl) {
            // 在页面上显示 GIF 图像
            console.log("GIF 转换完成:" + gifUrl);
          },
        },
        (obj) => {
          console.log("obj", obj);
          if (!obj.error) {
            const animatedImage = document.createElement("img");
            animatedImage.src = obj.image;
            box2.appendChild(animatedImage);
          }
        }
      );
    });
  </script>
</html>
btn.addEventListener('click', () => {
  box.classList.add('animate')
  const dur = 3000 // 动画持续时间
  const frames = 30 // 帧数
  frameArr = [] // 存储每一帧
  const now = Date.now()
  const captureFrame = async () => {
    const canvas = await html2canvas(ele, {
      useCORS: true,
      scale: window.devicePixelRatio < 3 ? window.devicePixelRatio : 2,
      allowTaint: true, 
    })
    const url = canvas.toDataURL("image/png", 1.0)
    console.log('url', url)
    frameArr.push(url)
    if (frameArr.length < frames) {
      setTimeout(captureFrame, dur / frames)
    } else {
      console.log('frameArr---22', frameArr)
      // 获取完截图,下一步操作
    }
  }
  captureFrame()
})
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题