使用事件监听器来创建更好的动画

2025-06-04

使用事件监听器来创建更好的动画

如果你想超越标准的悬停、聚焦和点击动画,那你肯定看对了文章!这一切都是为了将​​用户输入转化为更好的动画。

事件监听器

JavaScript 中有很多事件监听器,有些你可能听说过,但大多数你可能永远都不需要或用不到。我最常用的是触摸/鼠标和滚动事件。我也在尝试理解这些devicemotion事件,但进展不大,如果有人有什么阅读技巧,请告诉我!

在第一个例子中,我使用mouseover事件来确定鼠标在屏幕上的位置(xy 坐标)。

示例 1 鼠标悬停时倾斜

以下是我如何在我的投资组合中运用此方法的示例
以下是我如何在我的投资组合中使用它的一个例子

HTML 非常简单:

<div class="skew">
  <div class="skew__item">
    <img src="https://pbs.twimg.com/media/BcvmxibIYAAH8a3.jpg" /> 
    <!-- TIP: always use an image you really enjoy
    looking at for codepens 😻 -->
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode

JavaScript 变得更加复杂了:

const skewItemContainer = document.querySelector('.skew'); 
// Get the container element to add the mouseover 
// event and css variable to
const skewItem = document.querySelector('.skew__item').getBoundingClientRect();
// getBoundingClientRect() returns an object with the
// coordinates and width, height etc of an element

const imageCenterX = skewItem.left + skewItem.width / 2;
const imageCenterY = skewItem.top + skewItem.height / 2;
// Calculating the center coordinates for the image

// Add the event to the container around the image 
// (more room to mouseover == more better😎)
skewItemContainer.addEventListener("mousemove", function(e) {
  // the event, e, is an object with a lot of
  // information, I only use clientX and clientY
  // for this animation

  const clientX = e.clientX;
  const clientY = e.clientY;
  // Get x and y positions of the 
  const xCalc = (clientX - imageCenterX) * 0.000001;
  // increasing 0.000001 will make the animation more pronounced
  const yCalc = (clientY - imageCenterY) * 0.000001;
  // Subtracting the X & Y coordinates by the image
  // center ensures that the center of the image 
  // (where ever it may be positioned on the page) is 0, 0 🧐

  skewItemContainer.style.setProperty("--x-translate", `${xCalc}`);
  skewItemContainer.style.setProperty("--y-translate", `${yCalc}`);
  // using setProperty to add css variables to the container element
});
Enter fullscreen mode Exit fullscreen mode

好吧,我撒了个小谎,我其实没用skew()变换函数,我用的是matrix3d(),它能让你更好地控制。这个 matrix3d 变换非常复杂,我发现可以通过不断尝试不同的值来创建类似倾斜的效果。

.skew {
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  // Centering the element with flexbox ❤️
  background: black;
  width: 100vw;
  height: 100vh;
  overflow: hidden;
  --x-translate: 0;
  --y-translate: 0;
  // creating defaults for the css variables
  &:hover {
    .skew__item {
      transform: matrix3d(1, 0, 0.00, var(--x-translate), 0.00, 1, 0.00, var(--y-translate), 0, 0, 1, 0, 0, 0, 0, 1); 
      // By adding the transform only on hover you 
      // make sure that when the user hovers out it
      // will return to it's non transformed standard
      // position, which saves you some code ;)
    }
  }
  &__item {
    width: 60vw;
    max-width: 500px;
    transition: 0.4s cubic-bezier(0.64, 0.57, 0.67, 1.53);
    img {
      width: 100%;
      height: 100%;
      object-fit: cover; // ❤️❤️❤️❤️ object-fit
    }
    &:hover {
      transition: 0.4s ease-out;
      // adding a different animation on hover than
      // hover out makes animations more playful
    }
  }
}

Enter fullscreen mode Exit fullscreen mode

示例 2 滚动时放大

以下是我如何在我的投资组合中运用此方法的示例
以下是我如何在我的投资组合中使用它的一个例子

我在codepen里用了三个视频,这完全没必要!在这里的代码示例中,我会演示如何只用一个视频来实现。

向我工作的公司(Matise)致以最诚挚的谢意,他们制作了这段视频并展示了视频中展示的设计。👏

<section class="scale-video">
  <video class="video" autoplay muted loop playsinline src="https://cdn.matise.nl/content/uploads/2018/03/20092418/02_bbbSingleProduct.mp4"></video>
</section>
<section class="row">
  <h1>Scroll!!</h1>
</section>
Enter fullscreen mode Exit fullscreen mode
const videoContainer = document.querySelector('.scale-video');
const video = document.querySelector('.video');
// Create variables for the container and the video for easy access

window.addEventListener('scroll', function(e) {
  let scrollY = window.scrollY  / window.innerHeight * 5;
  // Create a calculation to base the scale amount on

  // Create min and max values for the scaling:
  if (scrollY <= 0.3) {
    scrollY = 0.3;
    // We don't want the video to become smaller than (scale(0.3))
  }
  if (scrollY >= 1) {
    scrollY = 1;
    // We don't want the video to become bigger than (scale(1))
  }
  videoContainer.style.setProperty('--scale', `${ scrollY }`);
  // Set css variable on the video container
});
Enter fullscreen mode Exit fullscreen mode
:root {
  // setting defaults can also be done on the root pseudo class
  // https://tympanus.net/codrops/css_reference/root/
  --scale: 0.3;
}

.scale-video {
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
  // Center the content with flexbox
  width: 100vw;
  box-sizing: border-box;
  height: 300vh;
  // The height here is quite outrageous, haha.
  // It's to make sure that you have enough place
  // to scroll to let the animation do its thing.
  overflow: hidden;
  background: black;
}

.video {
  position: fixed;
  top: 0; 
  transition: 1s ease-out;
  width: 100vw;
  z-index: 2;
  overflow: hidden;
  object-fit: cover;
  transform: scale(var(--scale));
  // Add the scale via css variable
}

Enter fullscreen mode Exit fullscreen mode

就这些了,如果你做过类似的动画,请告诉我。我很想看看!

文章来源:https://dev.to/cydstumpel/using-event-listeners-to-create-better-animations-3c7
PREV
我的2025年AI工程师路线图清单
NEXT
像半专业人士一样制作动画形式✨