【问题标题】:Image sequence starts animating before it's in view图像序列在它出现之前开始动画
【发布时间】:2021-08-29 22:03:06
【问题描述】:

我正在尝试复制苹果的图像排序动画 - https://www.apple.com/airpods-pro/。我设法找到了一些示例,它们都运行良好,但它们都在页面顶部触发,我希望我的在页面中间触发。我已经尝试将触发事件附加到#graphHolder 容器,但只要您在页面顶部滚动,它仍然会开始循环浏览图像。谁能指出我哪里出错了?这是一个 jsfiddle - https://jsfiddle.net/mvyw2bc3/2/

const html = document.documentElement;
const canvas = document.getElementById("hero-lightpass");
const context = canvas.getContext("2d");

const frameCount = 132;
const currentFrame = index => ( `https://res.cloudinary.com/icebreakernz/image/upload/v1623273037/globalcampaign/plastic-free/sequence-test/IB-Graph_Animation${index.toString().padStart(4, '0')}.jpg`
)

const preloadImages = () => {
  for (let i = 1; i < frameCount; i++) {
    const img = new Image();
    img.src = currentFrame(i);
  }
};

const img = new Image()
img.src = currentFrame(1);
canvas.width=1920;
canvas.height=1080;
img.onload=function(){
  context.drawImage(img, 0, 0);
}

const updateImage = index => {
  img.src = currentFrame(index);
  context.drawImage(img, 0, 0);
}

window.addEventListener('scroll', () => {  
  const scrollTop = html.scrollTop;
  const maxScrollTop = html.scrollHeight - window.innerHeight;
  const scrollFraction = scrollTop / maxScrollTop;
  const frameIndex = Math.min(
    frameCount - 1,
    Math.ceil(scrollFraction * frameCount)
  );
  
  requestAnimationFrame(() => updateImage(frameIndex + 1))
});

preloadImages()

【问题讨论】:

    标签: javascript html scrolltop


    【解决方案1】:

    对于遇到同样问题的任何人,我最终选择了ScrollTrigger,这使它变得超级简单。在这里查看我的小提琴,看看它应该如何工作 - https://jsfiddle.net/jdrebugL/

    const canvas = document.getElementById("hero-lightpass");
    const context = canvas.getContext("2d");
    
    canvas.width = 1920;
    canvas.height = 1080;
    
    const frameCount = 132;
    const currentFrame = index => ( `https://res.cloudinary.com/icebreakernz/image/upload/v1623273037/globalcampaign/plastic-free/sequence-test/IB-Graph_Animation${(index + 1).toString().padStart(4, '0')}.jpg`
    );
    
    const images = []
    const airpods = {
      frame: 0
    };
    
    for (let i = 0; i < frameCount; i++) {
      const img = new Image();
      img.src = currentFrame(i);
      images.push(img);
    }
    
    gsap.to(airpods, {
      frame: frameCount - 1,
      snap: "frame",
      scrollTrigger: {
        scrub: 1,
        trigger: "#hero-lightpass",
        start: "top top",
        pin: true
      },
      onUpdate: render // use animation onUpdate instead of scrollTrigger's onUpdate
    });
    
    images[0].onload = render;
    
    function render() {
      context.clearRect(0, 0, canvas.width, canvas.height);
      context.drawImage(images[airpods.frame], 0, 0); 
    }
    

    【讨论】:

      【解决方案2】:

      难道你不能做一个交点观察者,让它在一个被推到图像底部的 div 上触发(可能是绝对位置和底部零,或者你知道什么),然后触发内的任何回调函数观察者?我不确定这是否有任何帮助,但这是我制作的一个函数,可让您在元素相交时调用回调函数

      export const elementObserver = (callback, options) => {
       if (typeof options.element != "undefined") {
         return new IntersectionObserver(
           (entries, observer) => {
             entries.forEach(entry => {
               let target = entry.target;
               if (entry.isIntersecting) {
                 callback(options);
               }
             });
           },
           {
             threshold: 0.5
           }
         ).observe(options.element);
       }
      }
      

      您需要在 javascript 映射中传递所有回调函数变量,并且映射必须有一个名为“元素”的键才能工作(元素是要监视交叉点的元素)......也在它的当前状态它是用 es6 编写的,但您可以轻松翻译它。 哦,也许可以使用阈值,但将其设置为 1 以进一步延迟动作

      【讨论】:

      • 感谢您的回复!最后我最终选择了 gsaps scrollTrigger。是一个非常优雅的解决方案。
      • 太棒了!很高兴你找到了一个好的解决方案。您提到的插件听起来不错,但是如果您要走这条路,您可能应该考虑摇树,因为该插件可能比您需要的要多得多,而且您不希望所有这些额外的 js 拖慢您的速度。跨度>
      • 是的,当然,谢天谢地,当您滚动浏览页面的其余部分时,我的设计中有很多动画元素,因此非常适合我的需要。我最初使用的是scrollmagic,但已经将其替换为支持此功能,否则如果它是一次性的,我会按照您所说的那样使用精简版。
      猜你喜欢
      • 2010-11-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-23
      • 1970-01-01
      • 2021-04-22
      • 1970-01-01
      相关资源
      最近更新 更多