javascript 用基本的js把active类中的元素一个接一个地

kkih6yb8  于 2023-06-20  发布在  Java
关注(0)|答案(3)|浏览(103)

我需要“移动”活动类一个接一个地到这5个div元素,但使用非常基本的js,因为仍然在学习基础知识,我发现这个解决方案,它工作,但我想在for循环中转换它,没有任何函数,foreach循环,只有非常基本的?谢谢
这是我的解决方案:

next.addEventListener('click', function(){

    let current = document.querySelector('.active')

    if(current.classList.contains('active')){
        imgItems[1].classList.add('active')
        imgItems[0].classList.remove('active')
    }

    if (current.classList.contains('active')) {
        imgItems[1].classList.remove('active')
        imgItems[2].classList.add('active')
    }
    if (current.classList.contains('active')) {
        imgItems[2].classList.remove('active')
        imgItems[3].classList.add('active')
    }
    if (current.classList.contains('active')) {
        imgItems[3].classList.remove('active')
        imgItems[4].classList.add('active')
    }
    

})

我尝试了很多次,在线解决方案很好,但对我来说太先进了,我只学习了数组和循环。

uttx8gqw

uttx8gqw1#

假设这些项在DOM中是相邻的,您可以使用nextElementSibling转到下一项。

const next = document.getElementById("next");

next.addEventListener("click", function() {
  let current = document.querySelector(".active");
  let nextItem = current.nextElementSibling;
  if (!nextItem) {
    // Go back to the first item
    nextItem = document.querySelector(".item");
  }
  current.classList.remove("active");
  nextItem.classList.add("active");
})
.active {
  color: red;
}
<div id="container">
  <div class="item active">Item 1</div>
  <div class="item">Item 2</div>
  <div class="item">Item 3</div>
  <div class="item">Item 4</div>
  <div class="item">Item 5</div>
</div>

<button id="next">Next</button>
2skhul33

2skhul332#

给你

next.addEventListener('click', function() {
    let current = document.querySelector('.active');
    for (let index = 0; index <= 3; index++) {
        if (current.classList.contains('active')) {
            imgItems[index].classList.remove('active');
            imgItems[index + 1].classList.add('active');
        }
    }
});

JavaScript没有foreach循环。它已经为.. in loop,for ..循环和普通C型循环。在本例中,我使用了后者,因为我们要使用索引。
看起来你打算将active类级联到某个imgItems集合的末尾,所以想法是从0到3循环一个index,每次检查current是否有一个active类,然后从我们当前索引上的实际元素中删除该类,并将该类添加到下一个。你也可以不使用循环,像这样:

let imgItems = [...document.querySelectorAll('div')];
document.getElementById("next").addEventListener('click', function() {
    let current = document.querySelector('.active');
    let index = imgItems.indexOf(current);
    if (index < imgItems.length - 1) {
        imgItems[index].classList.remove('active');
        imgItems[index + 1].classList.add('active');
    } else {
        alert('You are at the last item');
    }
});
div {
    width: 100px;
    height: 100px;
    border: 1px solid black;
    float: left;
}

div.active {
    background-color: green;
}
<div class="active"></div>
<div></div>
<div></div>
<div></div>
<div></div>
<input type="button" value="next" id="next">

基本上,我们使用spread操作符([...]部分)将类似数组的对象imgItems转换为数组,并在事件中获取数组中current的索引,如果它不是最后一个,则删除活动类并将其添加到下一个。

r1zhe5dt

r1zhe5dt3#

这是一种稍微成熟一点的方法--不一定是你要求的“非常基本”的方法--它允许按下<button>来浏览元素列表;代码中有解释性注解,以便您和其他人可以从中学习:

// defining a named function - navigation() - that takes
// one argument, a reference to the Event to which this
// function is bound; this is passed automatically from
// the later use of EventTarget.addEventListener():
const navigation = function(evt) {
  // here we use destructuring assignment to retrieve
  // the currentTarget property from the evt Object,
  // creating a variable of that same name; the
  // currentTarget is the element node to which the
  // event-handler (this function) is bound:
  let {
    currentTarget
  } = evt;
  // we navigate from the currentTarget element to its closest
  // ancestor element that has a "data-active-class" attribute,
  // and from that element we use the HTMLElement.dataset API
  // to retrieve the attribute-value for the "data-active-class"
  // attribute, note that we're also using camelCase notation:
  let activeClassName = currentTarget.closest("[data-active-class]").dataset.activeClass;
  // retrieve the attribute-value of the "data-role" attribute
  // from the currentTarget element, and convert that string
  // to its lower-case equivalent:
  let direction = currentTarget.dataset.role.toLowerCase();
  // as above, we navigate from the currentTarget to its closest
  // ancestor with a "data-iterates" attribute, and then retrieving
  // the attribute-value:
  let selector = currentTarget.closest("[data-iterates]").dataset.iterates;
  // here we use document.querySelectorAll() to find all elements
  // within the document that match the supplied selector (retrieved
  // previously), and convert that NodeList into an Array, using
  // Array.from():
  let elements = Array.from(document.querySelectorAll(selector));
  // using Array.prototype.map() to create a new Array based
  // on the elements Array:
  let currentState = elements.map(
    // these arguments are available automatically to the
    // Array method; the names are entirely user-defined
    // while the relevant arguments are always in this order:
    //  el, a reference to the current Node of the Array of Nodes,
    //  index, the index of the current Array-element in the Array,
    // all, a reference to the current Array over which we're iterating:
    function(el, index, all) {
      // from the Array method we return an Object (creating an
      // Array of Objects derived from the current Array of Nodes):
      return {
        // here we return the named property, and property-values
        // in the form of:
        //      el: el,
        //      index: index
        // taking advantage of the shorthand notation:
        el,
        index,
        // here we return an isActive property with its value
        // a Boolean true/false, according to whether the current
        // element node has a class-name matching the activeClassName
        // value (retrieved above):
        isActive: el.classList.contains(activeClassName),
        // returning a 'progress' property with its value another Object:
        progress: {
          // next: using a conditional (ternary) operator, if the assessment
          // - is index + 1 equal to the length of the whole Array - is true/truthy
          // we return first Array-element, otherwise we return the Array-element
          // at the next index:
          next: (
            (index + 1) === all.length ? all.at(0) : all.at(index + 1)
          ),
          // if index - 1 is less than zero, we return the last Array-element
          // using Array.prototype.at() and an index of -1; otherwise we
          // return the previous Array-element:
          previous: (
            (index - 1) < 0 ? all.at(-1) : all.at(index - 1)
          )
        }
      };
    });
  // we then use Array.prototype.find()
  let currentlyActive = currentState.find(
    // again, we're retrieving the arguments available to the
    // method, which is an Object in this case:
    // {...}, using destructuring assignment to retrieve the named
    // properties (as variables) of the current Array-element (the Object):
    ({
      isActive
      // and we return the Array-element for which the test evaluates to
      // a Boolean true/truthy value; the 'isActive' property is itself
      // a Boolean, and so effectively we're returning (using the implicit
      // return of an Arrow function) either true or false directly:
    }) => isActive);
  // we use destructuring assignment again, to retrieve properties from
  // the currentlyActive Object:
  let {
    // here we retrieve the named property ('el') and assign it to
    // a different variable name 'currentElement', simarly we retrieve
    // and 'index' property, and also assign a new variable name
    // 'currentIndex' so the variable-name implies what its value
    // is/represents:
    el: currentElement,
    index: currentIndex,
    progress
  } = currentlyActive;

  // here we use the Element.classList API to remove the class
  // held in the activeClassName variable:
  currentElement.classList.remove(activeClassName);
  // and here we use bracket-notation to retrieve the
  // relevant property of the progress Object, and again
  // using the Element.classList API we add the
  // activeClassName to that element:
  progress[direction].classList.add(activeClassName);
};

// using document.querySelector to find elements with a "data-role" custom
// attribute that is itself nested within an ancestor with a "data-iterates"
// custom attribute; we then use NodeList.forEach() to iterate over the
// element ndoes that were retrieved:
document.querySelectorAll("[data-iterates] [data-role]").forEach(
  // and pass in a reference to the current Node of the NodeList,
  // and use EventTarget.addEventListener() to bind the
  // navigation() function - note the deliberately omitted
  // parentheses; we want to bind the function itself not the
  // returned property of the function - as the event-handler
  // for the "click" event:
  (el) => el.addEventListener("click", navigation)
);
:root {
  --spacing: 1rem;
}

*,
::before,
::after {
  box-sizing: border-box;
  font: inherit;
  margin: 0;
  padding: 0;
}

body {
  block-size: 100vh;
  font-family: system-ui;
  font-size: 16px;
  font-weight: 400;
  padding: var(--spacing);
}

menu,
ol,
ul,
li {
  list-style-type: none;
}

main {
  border: 1px solid currentColor;
  inline-size: clamp(30rem, 80% + 5vmin, 1200px);
  margin-inline: auto;
  min-block-size: 100%;
  padding: var(--spacing);
}

.controls {}

li a,
button {
  padding-block: calc(var(--spacing)/2);
  padding-inline: var(--spacing);
}

section {
  border: 1px solid currentColor;
  margin-block: var(--spacing);
  padding: var(--spacing);
}

li a {
  display: block;
}

.active {
  background-image: linear-gradient(90deg, lime, transparent);
}
<main>
  <!-- taking advantage of custom data-* attributes to allow the
       user to customise the JavaScript functionality:
          data-active-class: the attribute that defines the class-name
            that will be considered the indicator of the "active" element,
          data-iterates: the attribute that defines the CSS selector for
            the elements over which the JavaScript will iterate.
       -->
  <div
        class="controls"
        data-active-class="active"
        data-iterates="a">
    <!-- using the data-role attribute to define the "role" of the
         current element in the navigation through/over the
         elements: -->
    <button data-role="previous">previous</button>
    <button data-role="next">next</button>
  </div>
  <section>
    <ul>
      <li><a href="#" class="active">Link element 01</a></li>
      <li><a href="#">Link element 02</a></li>
      <li><a href="#">Link element 03</a></li>
      <li><a href="#">Link element 04</a></li>
      <li><a href="#">Link element 05</a></li>
    </ul>
  </section>
  <section>
    <ul>
      <li><a href="#">Link element 06</a></li>
      <li><a href="#">Link element 07</a></li>
      <li><a href="#">Link element 08</a></li>
      <li><a href="#">Link element 09</a></li>
      <li><a href="#">Link element 10</a></li>
    </ul>
  </section>
</main>

JS Fiddle demo
请注意,在上面的演示中,如果没有类名与activeClassName匹配的元素,或者有多个类与该类名匹配,则没有错误处理。如果需要这样做,你需要自己实现它,或者问一个问题,如果你不能写这样的代码,它可能/应该如何处理。
下面的演示展示了可能的自定义的一种用法(请记住美学是可怕的,因为这仅仅是一个概念验证):

// defining a named function - navigation() - that takes
// one argument, a reference to the Event to which this
// function is bound; this is passed automatically from
// the later use of EventTarget.addEventListener():
const navigation = function(evt) {
  // here we use destructuring assignment to retrieve
  // the currentTarget property from the evt Object,
  // creating a variable of that same name; the
  // currentTarget is the element node to which the
  // event-handler (this function) is bound:
  let {
    currentTarget
  } = evt;
  // we navigate from the currentTarget element to its closest
  // ancestor element that has a "data-active-class" attribute,
  // and from that element we use the HTMLElement.dataset API
  // to retrieve the attribute-value for the "data-active-class"
  // attribute, note that we're also using camelCase notation:
  let activeClassName = currentTarget.closest("[data-active-class]").dataset.activeClass;
  // retrieve the attribute-value of the "data-role" attribute
  // from the currentTarget element, and convert that string
  // to its lower-case equivalent:
  let direction = currentTarget.dataset.role.toLowerCase();
  // as above, we navigate from the currentTarget to its closest
  // ancestor with a "data-iterates" attribute, and then retrieving
  // the attribute-value:
  let selector = currentTarget.closest("[data-iterates]").dataset.iterates;
  // here we use document.querySelectorAll() to find all elements
  // within the document that match the supplied selector (retrieved
  // previously), and convert that NodeList into an Array, using
  // Array.from():
  let elements = Array.from(document.querySelectorAll(selector));
  // using Array.prototype.map() to create a new Array based
  // on the elements Array:
  let currentState = elements.map(
    // these arguments are available automatically to the
    // Array method; the names are entirely user-defined
    // while the relevant arguments are always in this order:
    //  el, a reference to the current Node of the Array of Nodes,
    //  index, the index of the current Array-element in the Array,
    // all, a reference to the current Array over which we're iterating:
    function(el, index, all) {
      // from the Array method we return an Object (creating an
      // Array of Objects derived from the current Array of Nodes):
      return {
        // here we return the named property, and property-values
        // in the form of:
        //      el: el,
        //      index: index
        // taking advantage of the shorthand notation:
        el,
        index,
        // here we return an isActive property with its value
        // a Boolean true/false, according to whether the current
        // element node has a class-name matching the activeClassName
        // value (retrieved above):
        isActive: el.classList.contains(activeClassName),
        // returning a 'progress' property with its value another Object:
        progress: {
          // next: using a conditional (ternary) operator, if the assessment
          // - is index + 1 equal to the length of the whole Array - is true/truthy
          // we return first Array-element, otherwise we return the Array-element
          // at the next index:
          next: (
            (index + 1) === all.length ? all.at(0) : all.at(index + 1)
          ),
          // if index - 1 is less than zero, we return the last Array-element
          // using Array.prototype.at() and an index of -1; otherwise we
          // return the previous Array-element:
          previous: (
            (index - 1) < 0 ? all.at(-1) : all.at(index - 1)
          )
        }
      };
    });
  // we then use Array.prototype.find()
  let currentlyActive = currentState.find(
    // again, we're retrieving the arguments available to the
    // method, which is an Object in this case:
    // {...}, using destructuring assignment to retrieve the named
    // properties (as variables) of the current Array-element (the Object):
    ({
      isActive
      // and we return the Array-element for which the test evaluates to
      // a Boolean true/truthy value; the 'isActive' property is itself
      // a Boolean, and so effectively we're returning (using the implicit
      // return of an Arrow function) either true or false directly:
    }) => isActive);
  // we use destructuring assignment again, to retrieve properties from
  // the currentlyActive Object:
  let {
    // here we retrieve the named property ('el') and assign it to
    // a different variable name 'currentElement', simarly we retrieve
    // and 'index' property, and also assign a new variable name
    // 'currentIndex' so the variable-name implies what its value
    // is/represents:
    el: currentElement,
    index: currentIndex,
    progress
  } = currentlyActive;

  // here we use the Element.classList API to remove the class
  // held in the activeClassName variable:
  currentElement.classList.remove(activeClassName);
  // and here we use bracket-notation to retrieve the
  // relevant property of the progress Object, and again
  // using the Element.classList API we add the
  // activeClassName to that element:
  progress[direction].classList.add(activeClassName);
};

// using document.querySelector to find elements with a "data-role" custom
// attribute that is itself nested within an ancestor with a "data-iterates"
// custom attribute; we then use NodeList.forEach() to iterate over the
// element ndoes that were retrieved:
document.querySelectorAll("[data-iterates] [data-role]").forEach(
  // and pass in a reference to the current Node of the NodeList,
  // and use EventTarget.addEventListener() to bind the
  // navigation() function - note the deliberately omitted
  // parentheses; we want to bind the function itself not the
  // returned property of the function - as the event-handler
  // for the "click" event:
  (el) => el.addEventListener("click", navigation)
);

document.querySelectorAll('[data-iterates]').forEach(
  (el) => [...el.children].forEach(
    (k) => k.innerHTML += `: <span>${el.dataset.iterates}</span>`
  )
);
:root {
  --spacing: 1rem;
}

*,
::before,
::after {
  box-sizing: border-box;
  font: inherit;
  margin: 0;
  padding: 0;
}

body {
  block-size: 100vh;
  font-family: system-ui;
  font-size: 16px;
  font-weight: 400;
  padding: var(--spacing);
}

menu,
ol,
ul,
li {
  list-style-type: none;
}

main {
  border: 1px solid currentColor;
  inline-size: clamp(30rem, 80% + 5vmin, 1200px);
  margin-inline: auto;
  min-block-size: 100%;
  padding: var(--spacing);
}

main *:not(button span) {
  background-clip: padding-box;
  border: 2px solid transparent;
  border-radius: 0.5em;
  padding-block: calc(var(--spacing)/2);
  padding-inline: var(--spacing);
  overflow: hidden;
}

.controls {
  display: inline-block;
  inline-size: 45%;
}

section {
  border: 1px solid currentColor;
  margin-block: var(--spacing);
  padding: var(--spacing);
}

li {
  display: flex;
  gap: 1em;
}

li a {
  display: block;
}

.active {
  background-image: linear-gradient(90deg, lime, transparent);
  background-repeat: no-repeat;
}

.special {
  border-image: radial-gradient(at 0 0, purple, aqua) 9;
}

.extraSpecialActive {
  border: 2px solid hsl(280deg 70% 50% / 1);
}
<main>
  <div class="controls" data-active-class="active" data-iterates="a">
    <button data-role="previous">previous</button>
    <button data-role="next">next</button>
  </div>
  <!-- all I've done here is add an extra pair of <button> elements within
       a parent element with relevant "data-active-class" and "data-iterates"
       attributes, and values (though obviously I've added the relevant class
       -names to elements in the document) -->
  <div class="controls" data-active-class="extraSpecialActive" data-iterates=".special">
    <button data-role="previous">previous</button>
    <button data-role="next">next</button>
  </div>
  <section>
    <ul>
      <li><a href="#" class="special extraSpecialActive">Link element 01</a></li>
      <li><a href="#">Link element 02</a></li>
      <li><a href="#">Link element 03</a></li>
      <li>
        <span>span: 1</span>
        <span>span: 2</span>
        <span class="special">span: 3</span>
        <span>span: 4</span>
        <span class="special">span: 5</span>
      </li>
      <li><a href="#">Link element 05</a></li>
      <li><a href="#" class="active">Link element 06</a></li>
    </ul>
  </section>
  <section>
    <ul>
      <li><a href="#">Link element 07</a></li>
      <li><a href="#">Link element 08</a></li>
      <li><a href="#">Link element 09</a></li>
      <li><a href="#">Link element 10</a></li>
      <li><a href="#">Link element 11</a></li>
    </ul>
  </section>
  <article>
    <h3 class="special">Special heading</h3>
  </article>
</main>

JS Fiddle demo
参考文献:

相关问题