1

I have few elements I need to slide, but I don't want to attach whole jQ lib. I like jQ a lot, but whole lib is just overkill in this example.

How to convert jq slideUp/slideDown/toggle to vanilla JS with support of multiple elements passed to function?

JQ code:

var $context = getContext(context);

$($context).on('click', '.menu', function () {
    $('.nav').slideToggle();
});

JS code:

var list = document.getElementsByClassName("class1", "class2", "class3");
//or
var list = document.querySelectorAll("class1", "class2", "class3");

var slideUp = function(targets, duration){
    // execution
};

slideUp(list, 500);

SO wizards make it happen! :)

proto
  • 11
  • 4
  • Since SO isn't a code writing service, I would post your attempts to solve the problem. Right now, you haven't posted any attempt to accomplish the sliding, you just posted the creation of an empty function. – imvain2 Jul 05 '22 at 18:47
  • You are right. But writing my own ANOTHER vanilla JS toggle is pointless. There are many, I just haven't found one that can use multiple selectors. I'm sure there is one somewhere and some SO wizard can link it. If no I will try to show the solution - ATM it is simply iterating through selectors and slide one by one immediately, after another. One I consider - https://dev.to/bmsvieira/vanilla-js-slidedown-up-4dkn – proto Jul 05 '22 at 19:51

3 Answers3

1

I wasn't happy with the last solution I gave you it was rushed and buggy totally unacceptable, Hope you can forgive me...so this is a better version with the clicks of each item working too

const clicker = document.getElementsByClassName("clicker")[0];
clicker.addEventListener("click", function() {
  process(document.querySelectorAll(".js-toggle"));
});
[...document.querySelectorAll(".js-toggle")].forEach((element) =>
  element.addEventListener("click", function() {
    process(this)
  })
)
const container = [];

function process(linkToggle) {
  container.length = 0
  if (linkToggle.length > 0) {
    for (let i = 0; i < linkToggle.length; i++) {
      container.push(
        document.getElementById(linkToggle[i].dataset.container))
      animate(container[i])
    }
  } else {

    container.push(
      document.getElementById(linkToggle.dataset.container))
    animate(container[0])
  }
}


function animate(element) {
  if (!element.classList.contains("active")) {
    element.classList.add("active");
    element.style.height = "auto";
    let height = parseInt(element.clientHeight || 0)
    element.style.height = "0px";
    setTimeout(function() {
      for (let t = 0; t < container.length; t++) {
        do {
          container[t].style.height =
            parseInt(container[t].style.height || height) +
            1 + 'px'
        } while (parseInt(container[t].style.height || height) < height);
      }
    }, 0);
  } else {
    element.style.height = "0px";
    element.addEventListener(
      "transitionend",
      function() {
        element.classList.remove("active");
      }, {
        once: true
      }
    );
  }
}
.clicker {
  cursor: pointer;
  background: red;
}

.box {
  width: 300px;
  border: 1px solid #000;
  margin: 10px;
  cursor: pointer;
}

.toggle-container {
  transition: height 0.35s ease-in-out;
  overflow: hidden;
}

.toggle-container:not(.active) {
  display: none;
}
<div class="clicker">CLICK ME</div>
<div class="box">
  <div class="js-toggle" data-container="toggle-1">Click1</div>
  <div class="toggle-container" id="toggle-1">I have an accordion and am animating the the height for a show reveal - the issue is the height which i need to set to auto as the information is different lengths.<br><br> I have an accordion and am animating the the height fferent lengths.
  </div>
</div>

<div class="box">
  <div class="js-toggle" data-container="toggle-2">Click2</div>
  <div class="toggle-container open" id="toggle-2">I have an accordion and am animating the the height for a show reveal - the issue is the height which i need to set to auto as the information is different lengths.<br><br> I have an accordion and am animating the the height fferent lengths.
  </div>
</div>

<div class="box">
  <div class="js-toggle" data-container="toggle-3">Click3</div>
  <div class="toggle-container" id="toggle-3">I have an accordion and am animating the the height for a show reveal - the issue is the height which i need to set to auto as the information is different lengths.<br><br> I have an accordion and am animating the the height fferent lengths.
  </div>
</div>

I hope this helps

Patrick Hume
  • 2,064
  • 1
  • 3
  • 11
0

you could just use css like so ( wasn't sure witch way you wanted to slid but this gives you an idea of how to do it):

var $slider = document.getElementById('slider');
var $toggle = document.getElementById('toggle');

$toggle.addEventListener('click', function() {
  var isOpen = $slider.classList.contains('slide-in');

  $slider.setAttribute('class', isOpen ? 'slide-out' : 'slide-in');
});
#slider {
  position: absolute;
  width: 100px;
  height: 100px;
  background: blue;
  transform: translateX(-100%);
  -webkit-transform: translateX(-100%);
}

.slide-in {
  animation: slide-in 0.5s forwards;
  -webkit-animation: slide-in 0.5s forwards;
}

.slide-out {
  animation: slide-out 0.5s forwards;
  -webkit-animation: slide-out 0.5s forwards;
}

@keyframes slide-in {
  100% {
    transform: translateX(0%);
  }
}

@-webkit-keyframes slide-in {
  100% {
    -webkit-transform: translateX(0%);
  }
}

@keyframes slide-out {
  0% {
    transform: translateX(0%);
  }
  100% {
    transform: translateX(-100%);
  }
}

@-webkit-keyframes slide-out {
  0% {
    -webkit-transform: translateX(0%);
  }
  100% {
    -webkit-transform: translateX(-100%);
  }
}
<div id="slider" class="slide-in">
  <ul>
    <li>Lorem</li>
    <li>Ipsum</li>
    <li>Dolor</li>
  </ul>
</div>

<button id="toggle" style="position:absolute; top: 120px;">Toggle</button>

I can't take credit for this its lifted from:

CSS 3 slide-in from left transition

I hope this helps

Patrick Hume
  • 2,064
  • 1
  • 3
  • 11
0

Could you not simply include the css in the page header so wouldn't need to edit any style sheets, well in any case then how about this:

function SlideDown() {
  const element = document.getElementById("slider");
  let top = 0;
  const up = setInterval(MoveDown, 10);

  function MoveDown() {
    if (top == 50) {
      clearInterval(up);
    } else {
      top++;
      element.style.top = top + '%';
    }
  }
}

function SlideUp() {
  const element = document.getElementById("slider");
  let top = parseInt(element.style.top);
  const down = setInterval(MoveUp, 10);

  function MoveUp() {

    if (top == -100) {
      clearInterval(down);
    } else {
      top--;
      element.style.top = top + '%';
    }
  }
}
<!DOCTYPE html>
<html>
  <body>
    <div id="slider" style="position:absolute; top: -100px;">
      <ul>
        <li>Lorem</li>
        <li>Ipsum</li>
        <li>Dolor</li>
      </ul>
    </div>
    <button onclick="SlideDown()">Slide Down</button>
    <button onclick="SlideUp()">Slide Up</button>
  </body>
</html>

I hope this helps

Patrick Hume
  • 2,064
  • 1
  • 3
  • 11
  • Way better for my specific needs! However I was thinking about something like this - https://jsfiddle.net/spamator1212/7495Lv80/11/ - be able to toggle many elements at once. – proto Jul 05 '22 at 20:42
  • Are you wanting each "cl" to slide to move together or one after the other like a cascade effect? – Patrick Hume Jul 05 '22 at 22:26
  • Hi Patrick! Together with option of the cascade :) - https://codepen.io/spamator12/pen/abYdoVz I have almost done it, just need some more time cause of work. – proto Jul 06 '22 at 10:44
  • posted an update to give you what you wanted, hope it helps – Patrick Hume Jul 09 '22 at 20:35
  • I'm sorry, I didn't have time t update it, I will try your new version ASAP and let you know how it goes. Sorry but it is a crazy week at work! – proto Jul 13 '22 at 23:39
  • let me know how it goes or if you need help – Patrick Hume Jul 14 '22 at 11:37