How to correctly toggle classes using document.getElementsByClassName and Element.classList

被刻印的时光 ゝ 提交于 2019-12-24 23:06:12

问题


I have a page where I want to be able to toggle classes on particular elements on or off.

In an attempt to do this I have written a function:

function toggleClass(obj) {
    alert(obj.className);
      Array.from(document.getElementsByClassName(obj.className)).forEach(function(element) {
        element.classList.toggle(obj.className);
    });
}

which is called by items in a table e.g <td style=""><span class="determiner" onclick="toggleClass(this)">Determiner</span></td>.

This works fine when I first click the item, the alert is triggered and the class is removed. When I click the same item in the table again to try and toggle/add the class the alert fires (empty because the class has been removed) but the class is not added.

Can anyone advise what I am doing wrong here?

function toggleClass(obj) {
    alert(obj.className);
      Array.from(document.getElementsByClassName(obj.className)).forEach(function(element) {
        element.classList.toggle(obj.className);
    });
}
.determiner {
  /* color: rgb(248, 8, 8); */
  border: 1px solid rgb(248, 8, 8);
}

.preposition {
  color: rgb(40, 18, 236);
  /* border: 1px solid rgb(40, 18, 236); */
}

.verb-present {
  color: rgb(13, 146, 68);
  /* border: 3px solid rgb(13, 146, 68); */
}

span[class^='noun-'], span[class*=' noun-']{
  color: #F00;
}
<table class="grammar table table-hover" data-toggle="table" data-sort-name="instance_use" data-sort-order="desc">
            <thead><tr><th style="" data-field="grammar_type" tabindex="0"><div class="th-inner sortable both">Grammar Type</div><div class="fht-cell"></div></th><th style="" data-field="instance_use" tabindex="0"><div class="th-inner sortable both desc">Instances of Use</div><div class="fht-cell"></div></th></tr></thead>
            <tbody><tr data-index="0"><td style=""><span class="adverb" onclick="toggleClass(this)">Adverb</span></td><td style="">2 </td></tr><tr data-index="1"><td style=""><span class="verb-present" onclick="toggleClass(this)">Verb, present</span></td><td style="">2 </td></tr><tr data-index="2"><td style=""><span class="determiner" onclick="toggleClass(this)">Determiner</span></td><td style="">2 </td></tr><tr data-index="3"><td style=""><span class="noun-sing-or-mass" onclick="toggleClass(this)">Noun, sing. or mass</span></td><td style="">1 </td></tr><tr data-index="4"><td style=""><span class="" onclick="toggleClass(this)">Preposition</span></td><td style="">1 </td></tr><tr data-index="5"><td style=""><span class="noun-plural" onclick="toggleClass(this)">Noun, plural</span></td><td style="">1 </td></tr><tr data-index="6"><td style=""><span class="comma" onclick="toggleClass(this)">Comma</span></td><td style="">1 </td></tr><tr data-index="7"><td style=""><span class="personal-pronoun" onclick="toggleClass(this)">Personal pronoun</span></td><td style="">1 </td></tr></tbody>
        </table>
        
<div id="story_text">
            <span style="white-space: pre-line">
            <span class="adverb">here</span> <span class="verb-present">is</span> <span class="determiner">a</span> <span class="noun-sing-or-mass">story</span> <span class="">with</span> <span class="determiner">no</span> <span class="noun-plural">commas</span><span class="comma">,</span> <span class="adverb">now</span> <span class="personal-pronoun">it</span> <span class="verb-present">does</span>
            </span>
        </div>

回答1:


The problem is that you keep referencing obj.className, but in the forEach loop, once the clicked element is iterated over, the obj.className becomes blank, so on further iterations (such as the "a" in is a story), the string passed to element.classList.toggle is blank.

Another problem is that when you try to click the element again, it has no existing class, so obj.className is empty - there's no class to toggle back on.

Instead of adding handlers in HTML attributes (which is as bad as eval), try iterating through all elements that need a handler beforehand, so you can build an array of elements for each className you want to be able to toggle.

A less elegant solution (that would require many fewer changes) would be to toggle a different class which overrides the color and border properties of the determiner and other classes:

function toggleClass(obj) {
  const className = obj.classList[0];
  document.querySelectorAll('.' + className).forEach(element => {
    element.classList.toggle('blank');
  });
}
.determiner {
  /* color: rgb(248, 8, 8); */
  border: 1px solid rgb(248, 8, 8);
}

.preposition {
  color: rgb(40, 18, 236);
  /* border: 1px solid rgb(40, 18, 236); */
}

.verb-present {
  color: rgb(13, 146, 68);
  /* border: 3px solid rgb(13, 146, 68); */
}

span[class^='noun-'],
span[class*=' noun-'] {
  color: #F00;
}

.blank {
  border: 0;
  color: black !important;
}
<table class="grammar table table-hover" data-toggle="table" data-sort-name="instance_use" data-sort-order="desc">
            <thead><tr><th style="" data-field="grammar_type" tabindex="0"><div class="th-inner sortable both">Grammar Type</div><div class="fht-cell"></div></th><th style="" data-field="instance_use" tabindex="0"><div class="th-inner sortable both desc">Instances of Use</div><div class="fht-cell"></div></th></tr></thead>
            <tbody><tr data-index="0"><td style=""><span class="adverb" onclick="toggleClass(this)">Adverb</span></td><td style="">2 </td></tr><tr data-index="1"><td style=""><span class="verb-present" onclick="toggleClass(this)">Verb, present</span></td><td style="">2 </td></tr><tr data-index="2"><td style=""><span class="determiner" onclick="toggleClass(this)">Determiner</span></td><td style="">2 </td></tr><tr data-index="3"><td style=""><span class="noun-sing-or-mass" onclick="toggleClass(this)">Noun, sing. or mass</span></td><td style="">1 </td></tr><tr data-index="4"><td style=""><span class="" onclick="toggleClass(this)">Preposition</span></td><td style="">1 </td></tr><tr data-index="5"><td style=""><span class="noun-plural" onclick="toggleClass(this)">Noun, plural</span></td><td style="">1 </td></tr><tr data-index="6"><td style=""><span class="comma" onclick="toggleClass(this)">Comma</span></td><td style="">1 </td></tr><tr data-index="7"><td style=""><span class="personal-pronoun" onclick="toggleClass(this)">Personal pronoun</span></td><td style="">1 </td></tr></tbody>
        </table>
        
<div id="story_text">
            <span style="white-space: pre-line">
            <span class="adverb">here</span> <span class="verb-present">is</span> <span class="determiner">a</span> <span class="noun-sing-or-mass">story</span> <span class="">with</span> <span class="determiner">no</span> <span class="noun-plural">commas</span><span class="comma">,</span> <span class="adverb">now</span> <span class="personal-pronoun">it</span> <span class="verb-present">does</span>
            </span>
        </div>


来源:https://stackoverflow.com/questions/51005330/how-to-correctly-toggle-classes-using-document-getelementsbyclassname-and-elemen

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!