首页 > 解决方案 > 如何将 jQuery 函数转换为 JavaScript?

问题描述

我正在努力将一些东西从 jQuery 切换到 vanilla JS。我在某些方法上遇到了麻烦。我想我有一些,但有些没有。

jQuery

$(".control-ct .arrow").on("click", function () {
  if ($(this).is("#left-arrow")) {
    $("#testimonialSlides .customer-block.active")
      .removeClass("active")
      .prev(".customer-block")
      .add("#testimonialSlides .customer-block:last")
      .first()
      .addClass("active");
  } else {
    $("#testimonialSlides .customer-block.active")
      .removeClass("active")
      .next(".customer-block")
      .add("#testimonialSlides .customer-block:first")
      .last()
      .addClass("active");
  }
});

JavaScript

let control = document.querySelector('.control-ct .arrow');
control.addEventListener('click', function() {
  let activeSlides = document.querySelector('#testimonialSlides .customer-block.active');
  if (control.matches('#left-arrow')) {
    activeSlides.classList.remove('active')
    activeSlides.prevElementSibling('.customer-block')
    activeSlides.add('#testimonialSlides .customer-block:last')
    activeSlides.at(0)
    activeSlides.classList.add('active');
  } else {
    activeSlides.classList.remove('active')
    activeSlides.nextElementSibling('.customer-block')
    activeSlides.add('#testimonialSlides .customer-block:first')
    activeSlides.at(-1)
    activeSlides.classList.add('active');
  }
});

let control = document.querySelector('.control-ct .arrow');
control.addEventListener('click', function() {
  let activeSlides = document.querySelector('#testimonialSlides .customer-block.active');
  if (control.matches('#left-arrow')) {
    activeSlides.classList.remove('active')
    activeSlides.prevElementSibling('.customer-block')
    activeSlides.add('#testimonialSlides .customer-block:last')
    activeSlides.at(0)
    activeSlides.classList.add('active');
  } else {
    activeSlides.classList.remove('active')
    activeSlides.nextElementSibling('.customer-block')
    activeSlides.add('#testimonialSlides .customer-block:first')
    activeSlides.at(-1)
    activeSlides.classList.add('active');
  }
});
#testimonialSlides {
  position: relative;
}
.testimonials-2020 {
  padding-top: 256px;
  padding-bottom: 128px;
}
.testimonials-2020 .container-fluid {
  background: #f2f5f9;
}
.testimonials-2020 .customer-block {
  visibility: hidden;
  opacity: 0;
  display: none;
}
.testimonials-2020 .customer-block.active {
  visibility: visible;
  opacity: 1;
  display: flex;
}
.testimonials-2020 .img-ct {
  position: relative;
}
.testimonials-2020 .img-ct img {
  position: absolute;
  bottom: -70px;
  right: 0;
  display: block;
}
.testimonials-2020 .txt-ct {
  padding: 80px 40px 30px 0;
}
.quote-slider h3 {
  max-width: 500px;
}
.quote-slider p.quote {
  font-size: 28px;
  line-height: 40px;
  margin: 36px 0 24px;
  min-height: 96px;
}
.quote-slider p.quote-small {
  margin: 36px 0 24px;
  padding-right: 48px;
  font-size: 20px;
  line-height: 32px;
}
.quote-slider p.quote span {
  color: #005fec;
  font-size: inherit;
}
.quote-slider p {
  font-size: 16px;
  line-height: 24px;
}
.quote-slider p.name {
  font-weight: 700;
}
.testimonials-2020 .control-ct {
  padding-bottom: 48px;
}
.testimonials-2020 .control-ct #right-arrow {
  margin-left: 22px;
}
.testimonials-2020 .control-ct .arrow {
  cursor: pointer;
}
.testimonials-2020 .control-ct .arrow g {
  transition: all 0.2s ease;
}
.testimonials-2020 .control-ct .arrow:hover g {
  stroke: #005fec;
}
<section class="testimonials-2020">
  <div class="container-fluid no-pad">
    <div class="container no-pad">
      <div class="quote-slider" id="testimonialSlides">
        <div class="row customer-block justify-content-center" data-customer-quote="01">
          <h2>One</h2>
        </div>
        <div class="row customer-block justify-content-center" data-customer-quote="02">
          <h2>Two</h2>
        </div>
        <div class="row customer-block justify-content-center" data-customer-quote="03">
          <h2>Three</h2>
        </div>
        <div class="control-ct">
          <svg id="left-arrow" class="arrow" fill="none" height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg">
            <g stroke="#000a70" stroke-width="2.5">
              <path d="m9 1-7 7 7 7"></path>
              <path d="m2.5 8h13.5"></path>
            </g>
          </svg><svg id="right-arrow" class="arrow" fill="none" height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg">
            <g stroke="#000A70" stroke-width="2.5">
              <path d="m1 8h13.5"></path>
              <path d="m8 15 7-7-7-7"></path>
            </g>
          </svg>
        </div>
      </div>
    </div>
  </div>
</section>

标签: javascriptjquery

解决方案


我可以看到的问题是:

  1. jQuery 代码将处理程序连接到所有匹配的元素上。您的代码querySelector只使用了第一个元素。您需要使用querySelectorAll一个循环来执行您的 jQuery 代码正在执行的操作。

  2. jQuery 的.prev(".customer-block")(and .next(...)) 为您提供了一个集合,其中包含您调用它的集合中每个元素的立即前一个元素,如果它们与选择器匹配。您的代码试图将previousElementSibling用作函数,但它是一个元素,而不是函数,并且有 o DOM 等效于“给我上一个,或者null如果它与这个选择器不匹配”。

  3. 您的选择器仍在使用:lastand :first,这是 jQuery 添加的东西,而不是 DOM 原生的。

以下是解决这些问题的方法:

// Loop through all matching elements
for (const control of document.querySelectorAll(".control-ct .arrow")) {
    // Handle click on this element
    control.addEventListener("click", function() {
        // Get the active slide
        let activeSlide = document.querySelector("#testimonialSlides .customer-block.active");
        if (control.id === "left-arrow") { // No need for `.matches` here
            // This slide is no longer active
            activeSlide.classList.remove("active");
            // Get the previous element
            let prev = activeSlide.previousElementSibling;
            // If there is none or it doesn't match, use the last instead
            if (!prev || !prev.classList.contains("customer-block")) {
                // No previous slide, use the last instead
                const slides = document.querySelectorAll("#testimonialSlides .customer-block");
                prev = slides[slides.length - 1];
            }
            // Make it active
            prev.classList.add("active");
        } else {
            // This slide is no longer active
            activeSlide.classList.remove("active");
            // Get the next element
            let next = activeSlide.nextElementSibling;
            // If there is none or it doesn't match, use the first instead
            if (!next || !next.classList.contains("customer-block")) {
                // `querySelector` only returns the first match, not a list like `querySelectorAll` does
                next = document.querySelector("#testimonialSlides .customer-block");
            }
            next.classList.add("active");
        }
    });
}

或者实际上,我认为我们可以简化上一个/下一个部分:

// Loop through all matching elements
for (const control of document.querySelectorAll(".control-ct .arrow")) {
    // Handle click on this element
    control.addEventListener("click", function() {
        // Get all slides and the active slide
        const slides = [...document.querySelectorAll("#testimonialSlides .customer-block")];
        // Get the active slide's index
        let index = slides.findIndex(slide => slide.classList.contains("active"));
        // This slide is no longer active
        slides[index].classList.remove("active");
        // Make the new one active via its index (with wrap-around)
        index = (index + (control.id === "left-arrow" ? -1 : 1) + slides.length) % slides.length;
        slides[index].classList.add("active");
    });
}

现场示例:

// Loop through all matching elements
for (const control of document.querySelectorAll(".control-ct .arrow")) {
    // Handle click on this element
    control.addEventListener("click", function() {
        // Get all slides and the active slide
        const slides = [...document.querySelectorAll("#testimonialSlides .customer-block")];
        // Get the active slide's index
        let index = slides.findIndex(slide => slide.classList.contains("active"));
        // This slide is no longer active
        slides[index].classList.remove("active");
        // Make the new one active via its index (with wrap-around)
        index = (index + (control.id === "left-arrow" ? -1 : 1) + slides.length) % slides.length;
        slides[index].classList.add("active");
    });
}
.customer-block {
    display: inline-block;
    width: 20px;
    text-align: center;
    color: grey;
    border: 1px solid transparent;
}
.customer-block.active {
    font-weight: bold;
    color: green;
    border: 1px solid green;
}
<div class="control-ct">
    <input class="arrow" type="button" id="left-arrow" value="&lt;">
    <input class="arrow" type="button" id="right-arrow" value="&gt;">
</div>
<div id="testimonialSlides">
    <div class="customer-block active">1</div>
    <div class="customer-block">2</div>
    <div class="customer-block">3</div>
    <div class="customer-block">4</div>
    <div class="customer-block">5</div>
</div>


推荐阅读