Search code examples
javascripthtmlshopifygsap

trigger animations independently for elements with the same class Javascript using greensock


I have multiple products on the collection page and I would like to trigger animation each time I hover the product cards independently.

Problem: The animation triggers for all the product cards at the same time when I hover each of them.
I reviewed other similar questions here but could not find the solution to my specific problem.

var main = document.querySelectorAll(".main-card");
var anime = document.querySelectorAll(".bottom-card");
        
        if (main.length !== 0){
  for (var i=0; i<main.length; i++) {
(this).main[i].addEventListener("mouseenter", function(){

  TweenMax.to(anime, 0.3, {opacity: 1, height: "143px"});
//   .staggerFrom(".size", 0.5, {y: 10, opacity:0, ease:Elastic.easeOut}, 0.1)
  });

(this).main[i].addEventListener("mouseleave", function(){
  TweenMax.to(anime, 0.3, {opacity: 0, height: '0px'});
  });
    
  };
          
        
        }
<form  action="/cart/add" method="post" id="AddToCartForm">
  <a class="grid-view-item__link grid-view-item__image-container" href="{{ product.url | within: collection }}">
  <div id="card" class="product-card__image-with-placeholder-wrapper" data-image-with-placeholder-wrapper>
    <div id="{{ wrapper_id }}" class="grid-view-item__image-wrapper product-card__image-wrapper js">
      <div style="padding-top:{% unless product.featured_image == blank %}{{ 1 | divided_by: product.featured_image.aspect_ratio | times: 100 }}%{% else %}100%{% endunless %};">
        <div id="id" class="main-card">
          <div class="image-card">
        <img id="{{ img_id }}"
              class="grid-view-item__image lazyload"
              alt="{{ product.featured_image.alt }}"
              data-src="{{ img_url }}"
              data-widths="[180, 360, 540, 720, 900, 1080, 1296, 1512, 1728, 2048]"
              data-aspectratio="{{ product.featured_image.aspect_ratio }}"
              data-sizes="auto"
              data-image>
        
            </a>
         
          
          <a class="grid-view-item__link grid-view-item__image-container" href="{{ product.url | within: collection }}">
          
          <div class="h4 grid-view-item__title product-card__title" aria-hidden="true">{{ product.title }}</div>
  
  {% include 'product-price', variant: product.selected_or_first_available_variant %}
          </a>
          
          <div id="bottom" class="bottom-card">
            
            
  
  {% if product.title == "Blue Silk Tuxedo" %}

            
 
    
  <div class="flex">
<select name="id" id="{{ product.handle }}" style="display: none;">

  
{% for variant in product.variants %}
  {% if variant.available == true %}
<option {% unless variant.available %} disabled="disabled" {% endunless %} {% if variant == current_variant %} selected="selected" {% endif %} data-sku="{{ variant.sku }}" value="{{ variant.id }}">{{ variant.title }} - {% if variant.available %}{{ variant.price | money_with_currency }}{% else %}{{ 'products.product.sold_out' | t }}{% endif %}</option> 
  

  
{% else %}
  <option disabled="disabled">{{ variant.title }} - Sold Out</option> 

  {% endif %}
  {% endfor %} 
</select> 
    {% if product.available and product.variants.size > 1 %}
  {% for option in product.options %}
    {% include 'swatch' with option %}
  {% endfor %}
{% endif %}
  </div>
  
  
 <button type="submit" name="add" id="AddToCart" class="btn">
<span id="AddToCartText">Add to cart</span>
  
  
</form>

Each of the products have this html code. So each product has the same classes. This is in a shopify theme.


Solution

  • You are targeting all the elements with class .bottom-card using the 2 lines below.

    // This returns all the elements with class .bottom-card in the document
    var anime = document.querySelectorAll(".bottom-card");
    
    // Here you are animating all the elements
    TweenMax.to(anime, 0.3, {opacity: 1, height: "143px"})
    

    You can run a querySelector on the .main-card div to get only its children with class .bottom-card.

    TweenMax.to(main[index].querySelector(".bottom-card"), 0.3, { opacity: 1, height: "143px" })
    

    Try the blow SO snippet to see the animation in effect.

    var main = document.querySelectorAll(".main-card");
    
    if (main.length !== 0) {
      for (var i = 0; i < main.length; i++) { 
        // Closure for each function
        let index = i; 
        main.item(i).addEventListener("mouseenter", function() {          
        TweenMax.to(main[index].querySelector(".bottom-card"), 0.3, { opacity: 1, height: "143px" });
        });
    
        main[i].addEventListener("mouseleave", function() {
          TweenMax.to(main[index].querySelector(".bottom-card"), 0.3, { opacity: 0, height: "0px" });
        });
      }
    }
    html, body {
      height: 100%;
    }
    
    body {
      background-color:#1d1d1d;
      font-family: "Asap", sans-serif;
      color:#989898;
      margin:0 10px;
      font-size:16px;
    }
    
    h1, h2, h3 {
      font-family: "Signika Negative", sans-serif;
      margin: 10px 0 10px 0;
      color:#f3f2ef;
    }
    
    h1 { 
      font-size:36px;
    }
    
    h2 {
      font-size:30px;
    }
    
    h3 {
      font-size:24px;
    }
    
    p{
      line-height:22px;
      margin-bottom:16px;
      width:650px;
    }
    
    #demo {
      height:100%;
      position:relative;
    }
    .main-card {
      width:50px;
      min-height:50px;
      position:relative;
      border-radius:6px;
      margin-top:4px;
      display:inline-block
    }
    
    .bottom-card {
      color: yellow;
    }
    .green{
      background-color:#6fb936;
    }
    
    .orange {
      background-color:#f38630;
    }
    .grey {
      background-color:#989898;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.2/TweenMax.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
    
    
    <link href='https://fonts.googleapis.com/css?family=Asap:400,700' rel='stylesheet' type='text/css'>
    <link href='https://fonts.googleapis.com/css?family=Signika' rel='stylesheet' type='text/css'>
     <div>
        <div class="main-card green">
            <div class="bottom-card"></div>
        </div>
        <div class="main-card grey">
            <div class="bottom-card"></div>
        </div>
        <div class="main-card orange">
            <div class="bottom-card"></div>
        </div>
        <div class="main-card green">
            <div class="bottom-card"></div>
        </div>
        <div class="main-card grey">
            <div class="bottom-card"></div>
        </div>
        <div class="main-card orange">
            <div class="bottom-card"></div>
        </div>
        <div class="main-card green">
            <div class="bottom-card"></div>
        </div>
        <div class="main-card grey">
            <div class="bottom-card"></div>
        </div>
        <div class="main-card orange">
            <div class="bottom-card"></div>
        </div>
      </div>