【问题标题】:How to toggle elements' class from an `onClick` event (from jQuery to pure JS)?如何从 `onClick` 事件(从 jQuery 到纯 JS)切换元素的类?
【发布时间】:2022-01-08 08:57:06
【问题描述】:

我想在单击另一个元素时在所有具有相同类的元素上切换一个 css 类。

我让它使用 jQuery,但需要切换到纯 JavaScript。

有效的 jQuery 版本:

$(function() {
  $("#logo").click(function() {
    $(".grey").toggleClass("white", 1000);
    $(".red").toggleClass("orange", 1000);
  });
});

当您单击带有id="logo" 的元素时,带有class="grey" 的所有内容都会切换white 类,而带有class="red" 的所有内容都会切换orange

更新新问题!

我正在使用运行良好的@Vektor 代码——除了在 iPhone 5 上没有任何反应。 (它适用于我的 iPhone 12 和 7。)用于试验的简化代码:

<body>
    
<div id="logo"  class="grey"><p class="red">Hello.</p>
</div>

<script>

    const logo = document.getElementById('logo');
    
    logo.addEventListener('click', () => {
        const grey = document.querySelectorAll('.grey');
        const red = document.querySelectorAll('.red');
        grey.forEach(e => e.classList.toggle('white'));
        red.forEach(e => e.classList.toggle('orange'));
    }, false);
</script>
</body>
body{background-color: #000000;}
div#logo{
  position:fixed;
  top:0;
  left:0;
  height: 100vh;
  width:30vw;
  cursor: pointer;
}
.red{background-color:#4C0000;}
.orange{background-color:#d69215}
.grey{background-color:#485055;}
.white{background-color:white;}

我读到添加 cursor:pointer 将修复 JavaScript 在旧版 iPhone 浏览器的非传统可点击元素上不起作用的问题。没有。

【问题讨论】:

  • 你自己的尝试在哪里?
  • 最后一段 (I've googled … Thank you in advance.) 没有为您的问题添加任何见解。而不是那段,您应该展示您尝试过的内容并解释您的方法遇到的问题
  • 我自己的最佳尝试(仅在一个元素上切换)已被长期删除,取而代之的是随后更糟糕的尝试,并且可能令人尴尬的绝望黑客也被删除了。
  • 为徽标使用锚或按钮标签。

标签: javascript jquery css


【解决方案1】:

首先获取“id”。然后听那个“点击”事件。当点击发生时,首先抓取所有“白色”类元素。 “queryselectorAll”返回一个类似数组的NodeList,因此您可以使用“forEach”数组方法。然后一一迭代所有元素。同样的逻辑也适用于“红色”类元素。

 let  logo = document.getElementById('logo');

    logo.addEventListener('click', ()=>{
        let grey = document.querySelectorAll('.grey');
        grey.forEach((e)=>{
            e.classList.toggle('white')
        })
        let red = document.querySelectorAll('.red');
        red.forEach((e)=>{
            e.classList.toggle('orange')
        })
    })

【讨论】:

  • 请为您本来不错的答案添加一些解释。
  • 先获取“id”。然后听一个“点击”事件。听完先抢全“白”课。 “queryselectorAll”返回一个类似数组的节点。所以你可以使用“forEach”循环。然后逐个迭代所有元素。同样的逻辑也适用于“红色”类。
  • 我在我的代码中找不到任何错误。如果您遇到问题,请提及。其实我是新来的
  • 要给出一个好的答案,你不应该只显示代码而不做任何解释。并且解释应该在答案本身中,而不是作为评论添加。
  • 这很有效——谢谢——但@Vektor 看起来更优雅,所以我正在使用它......虽然我已经问过他(?)一个新问题。跨度>
【解决方案2】:

首先,通过id 属性选择logo 元素。在其上注册一个click 事件侦听器以触发该过程。事件处理函数将选择所有包含 greyred 类名的元素,生成一个节点列表,遍历它们,并为每个元素切换 whiteorange 类名类列表。

const logo = document.getElementById('logo');

logo.addEventListener('click', () => {
    const grey = document.querySelectorAll('.grey');
    const red = document.querySelectorAll('.red');
    grey.forEach(e => e.classList.toggle('white'));
    red.forEach(e => e.classList.toggle('orange'));
}, false);
body {
  background-color: #666;
}

.grey {
  color: #bbb;
}

.red {
  color: red;
}

.white {
  color: white;
}

.orange {
  color: orange;
}
<button id="logo">LOGO!</button>

<p class="grey">Hello World</p>
<p class="red">Hello World</p>
<p class="grey">Hello World</p>
<p class="red">Hello World</p>
<p class="grey">Hello World</p>

我希望这能解决你的问题。

更新

根据 OP 的要求,我添加了这些更新以解决在上述解决方案中旧 iPhone 版本(即 iPhone 5)上未触发点击事件的问题。由于我无权使用这些设备,因此我无法保证以下建议的可行性。

<a href="javascript:handleClick();">LOGO1!</a>
<a href="#" onclick="handleClick(); return false;">LOGO2!</a>
<a href="#" ontouchstart="handleClick();">LOGO3!</a>
const handleClick = function handleClick() {
    const grey = document.querySelectorAll('.grey');
    const red = document.querySelectorAll('.red');
    grey.forEach(e => e.classList.toggle('white'));
    red.forEach(e => e.classList.toggle('orange'));
}

【讨论】:

  • 这很好用。谢谢你。但是我不得不让两个元素能够触发切换,所以我制作了那个东西 id="logov" 并在其中复制了你的脚本,将“logo”切换为“logov”。工作正常......除了在 iPhone 5 上,我假设其他(我猜不是当前)平台。关于为什么会这样的任何线索?
  • 请注意,我正在内联 svg 中执行此操作。刚刚注意到 a href 在旧 iPhone 上也不起作用。
  • 我不确定我是否在关注,你能用代码更新问题帖子吗?您在 iPhone 5 上运行什么浏览器,或者您指的是 chrome 中的模拟器?我的示例是使用按钮,可能是您的锚标记触发了旧设备上的页面刷新,但这只是我的猜测......
  • 经过进一步调查,我认为这是早期 iOS 上 SVG 中的点击事件(它们不起作用)的问题。显然 jQuery 解决了它,并且有一些 JS 的小提琴似乎不能应用于这个......
  • 我在原来的Q中添加了新问题
【解决方案3】:

你可以通过类获取一个元素,然后对其进行操作:

document.getElementById('logo').addEventListener('click', function(){
  var redElements = document.getElementsByClassName('red');
  Array.from(redElements).forEach(el => el.classList.toggle('orange'));

  var greyElements = document.getElementsByClassName('grey');
  Array.from(greyElements).forEach(el => el.classList.toggle('white'));
});

【讨论】:

  • document.querySelector只会找到第一个匹配项。
  • 是的,我自己也注意到了这一点。固定
  • for (const redElement of redElements)为您省去了Array.from的麻烦并且使代码更具可读性。它也不需要像forEach 这样的谓词。
  • In 的印象是 for of 不起作用,因为 HTMLCollection 不能开箱即用地迭代。
  • 这就是重点,它开箱即用可迭代的,它只是不自然地在其原型上实现forEach。见stackoverflow.com/questions/41758982/…
【解决方案4】:

您的代码带有转换为纯 js 的注释:

$(function() // not even necessary in jQuery

$("#logo").click(function() {
// **replace with 
document.querySelector(`#logo`).addEventListener(`click`, /*[you handler function]*/)

// your handler function
function myLogoHandler() {
  $(".grey").toggleClass("white", 1000);
  //                              ^ invalid/unnecessary parameter
  // **replace with
  document.querySelectorAll(`.grey`).forEach(el => el.classList.toggle(`white`));
  /* ... etc */
}

有几种方法可以处理这种“切换”。这里有两个使用classList.replace 的例子。 sn-ps 使用event delegation。对于...-语法,请参见MDN

  • 为什么是replace?在所有.grey 元素的代码中,您最终会得到&lt;[element] class="grey white"&gt;&lt;[element] class="grey"&gt;。这令人困惑,并可能导致无法预料的副作用(例如矛盾的 css 值)。

  • 为什么是event delegationthis 的情况可能看起来有点矫枉过正,但对于动态网页来说,这是一种处理动态创建的元素而无需重新分配处理程序的方法,可以用更少的(处理)代码做更多的事情,@987654324 @。

document.addEventListener(`click`, handle);

function handle(evt) {
  // if the click originated from the button
  if (evt.target.id === `toggle`) {
    // find all elements with className green or red
    document.querySelectorAll(`.green, .red`)
      .forEach(el => {
        // create parameters for the replace
        // if current is red then red should be replaced by green
        // otherwise green should be replaced by red
        const colors = el.classList.contains(`red`)
          ? [`red`, `green`] : [`green`, `red`];
        el.classList.replace(...colors);
        //                   ^ spread the array into variables
      })
  }
}
.green:before {
  content: 'Green';
  color: green;
}

.red:before {
  content: 'Red';
  color: red;
}
<div class="green"></div>
<div class="green"></div>
<div class="red"></div>
<div class="red"></div>
<button id="toggle">toggle color</button>

使用data-attribute 为类名切换增加更多灵活性。

document.addEventListener(`click`, handle);

function handle(evt) {
  if (evt.target.id === `toggle`) {
    // find all elements with the data-colors attribute
    document.querySelectorAll(`[data-colors]`)
      .forEach(el => {
        // convert the data-colors value to array
        const colors = el.dataset.colors.split(`,`);
        el.classList.replace(...colors);
        // swap the colors.
        el.dataset.colors = colors.reverse();
        //                  ^ note: 
        // the array is automatically converted 
        // to a string here
      })
  }
}
.green:before {
  content: 'Green';
  color: green;
}

.red:before {
  content: 'Red';
  color: red;
}

.orange:before {
  content: 'Orange';
  color: orange;
}
<div class="green" data-colors="green,orange"></div>
<div class="red" data-colors="red,green"></div>
<div class="orange" data-colors="orange,red"></div>
<button id="toggle">toggle color</button>

【讨论】:

  • 您本可以使用content: attr(class); 来进一步让初学者更难理解您的答案。
  • 那显然是错误的(多个类名)。
  • 对单个按钮使用事件委托确实是过度设计事物的一个很好的例子(顺便说一句。不是我的反对意见)。
  • @connexo 解释了一些事情。
  • 它提高了性能但这里的情况正好相反。
【解决方案5】:

javascript 的简化是 jquery,所以朋友不需要太辛苦。

    var grey = document.getElementByClassName("grey");
   grey.classList.toggle("white");

   

【讨论】:

  • document 上没有 getElementByClass
  • 该方法称为getElementsByClassName,它返回一个实时HTMLCollection,因此您需要修复名称并对其进行迭代,以便能够对每个元素执行某些操作。此外,如果您花时间以更简洁的方式编写和格式化答案,那就太好了。
猜你喜欢
  • 2013-09-23
  • 2021-08-05
  • 2016-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-12
  • 1970-01-01
相关资源
最近更新 更多