You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为多个元素添加addEventListener,避免元素不存在时触发TypeError

How to Avoid TypeError When Adding Hover Events for Multiple Bodymovin/SVG Animation Elements

Great question! Dealing with multiple elements and event listeners while preventing crashes from missing elements is a common gotcha—let’s break down some straightforward, reliable solutions:

1. Check for Element Existence Before Binding Events

First, using a shared class name for all your animation divs (instead of relying solely on IDs) makes it easy to grab all targets at once. Then, you can loop through them and only bind events if the element actually exists.

You’ll also need a way to link each element to its Bodymovin animation instance—here’s how to do that with a Map:

// Step 1: Initialize animations and map them to their elements
const animationsMap = new Map();
const animationElements = document.querySelectorAll('.animate-on-hover');

animationElements.forEach(element => {
  // Skip if the element somehow doesn't exist (extra safety)
  if (!element) return;

  // Initialize your Bodymovin animation
  const animation = bodymovin.loadAnimation({
    container: element,
    renderer: 'svg',
    loop: true,
    autoplay: false,
    path: `./animations/${element.dataset.animationFile}.json` // Use data attribute to store animation path
  });

  // Map the element to its animation instance
  animationsMap.set(element, animation);

  // Step 2: Add hover event listeners safely
  element.addEventListener('mouseenter', () => {
    // Grab the animation and play it only if it exists
    const targetAnimation = animationsMap.get(element);
    if (targetAnimation) targetAnimation.play();
  });

  element.addEventListener('mouseleave', () => {
    const targetAnimation = animationsMap.get(element);
    if (targetAnimation) targetAnimation.stop();
  });
});

This approach ensures you never try to bind events to a non-existent element, and you avoid trying to call play()/stop() on an undefined animation instance.

2. Use Optional Chaining for Cleaner Modern Code

If you’re targeting modern browsers (most are now), the optional chaining operator (?.) lets you skip verbose existence checks. It short-circuits the code if the left-hand value is null or undefined, so no TypeError is thrown.

Here’s how to apply it to both element selection and animation calls:

// Single element example (no crash if element doesn't exist)
document.getElementById('animationDiv')?.addEventListener('mouseenter', () => {
  animation?.play();
});

// Multiple elements example
document.querySelectorAll('.animate-on-hover').forEach(element => {
  element.addEventListener('mouseenter', () => {
    animationsMap.get(element)?.play();
  });
  element.addEventListener('mouseleave', () => {
    animationsMap.get(element)?.stop();
  });
});

This keeps your code concise while maintaining safety—just make sure your target browsers support optional chaining (all major browsers released after 2020 do).

3. Create a Reusable Safe Event Binding Function

If you need to support older browsers or want a reusable utility, wrap the existence check in a function. This way you don’t repeat the same check everywhere:

function safeBindEvent(element, eventType, handler) {
  // Only bind if the element exists and has the addEventListener method
  if (element && typeof element.addEventListener === 'function') {
    element.addEventListener(eventType, handler);
  }
}

// Use it for single elements
const singleAnimDiv = document.getElementById('animationDiv');
safeBindEvent(singleAnimDiv, 'mouseenter', () => animation?.play());
safeBindEvent(singleAnimDiv, 'mouseleave', () => animation?.stop());

// Use it for multiple elements
document.querySelectorAll('.animate-on-hover').forEach(element => {
  safeBindEvent(element, 'mouseenter', () => animationsMap.get(element)?.play());
  safeBindEvent(element, 'mouseleave', () => animationsMap.get(element)?.stop());
});

This utility adds an extra layer of compatibility and keeps your main code clean.

Key Takeaway

The core idea is twofold:

  • Always verify that elements and animation instances exist before interacting with them
  • Use batch selection (like querySelectorAll) and mapping to manage multiple animations efficiently

内容的提问来源于stack exchange,提问作者CK MacLeod

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 03:32:22