简体   繁体   English

在比较 classList.contains 的 if-else 语句时,如何在没有 setInterval 的情况下更新类?

[英]How can I update the class without setInterval when comparing if-else statement for classList.contains?

I need a solution for if-else comparing the classList.contains in JavaScript.我需要一个 if-else 比较 JavaScript 中的classList.contains的解决方案。 when I compare without setInterval the classList not working but I need a solution without setInterval because it's updating everything I need only to work the classList.contains when onclick .当我在没有setInterval的情况下进行比较时, classList 不起作用,但我需要一个没有setInterval的解决方案,因为它正在更新我只需要在onclick时工作classList.contains所有内容。 please see the code below.请看下面的代码。

 let ctx = document.querySelector('.control'); ctx.onclick = () => { box.classList.toggle('rds'); document.onclick = null; // important idea box.classList.remove('ok') } setInterval(() => { if (box.classList.contains('rds')) { document.onclick = () => { box.classList.remove('rds'); box.classList.add('ok') } } else { document.onclick = null; // important idea } }, 1)
 .box { width: 200px; height: 200px; background: red; transition: 1s; } .rds { border-radius: 50%; } .ok { border: 10px dotted blue; }
 <button class="control">Control here</button> <div class="box" id="box"></div>

I understood you.我理解你。 But you should also provide behavior of yours animation.但是你也应该提供你的动画的行为。 I did 2 variants without setInterval please check.我做了 2 个没有 setInterval 的变体,请检查。 And if it is okay for you, mark answer like correct.如果你觉得没问题,请将答案标记为正确。

jsfiddle 1: https://jsfiddle.net/shuts13/dvp4tea9/21/ jsfiddle 1: https ://jsfiddle.net/shuts13/dvp4tea9/21/

jsfiddle 2: https://jsfiddle.net/shuts13/0emocq7j/1/ jsfiddle 2: https ://jsfiddle.net/shuts13/0emocq7j/1/

<button class="control" onclick="update()">Control here</button>

    <div class="box" id="box">

    </div>


    function update() {
  const box = document.getElementById('box');

              box.classList.add('rds');
              box.classList.add('ok');

  setTimeout(()=> {
            if(box.classList.contains('rds')){
                            console.log('ECIS')
                box.classList.remove('rds');
            } 
  }, 1000)
  }

Problems问题

The OP 1 (aka O riginal P oster -- aka @NIKHIL CHANDRA ROY ) use ( misuse?...abuse? ) of setInterval() is just a means to switch the "state" ( ex. .ok and .rds ) of .box I assume.OP 1(又名Øriginal P奥斯特-又名@NIKHIL钱德拉ROY )使用(?...误用滥用setInterval()只是切换“状态”的手段(例如, .ok.rds.box我假设。

Concerning OP's misconceptions about (or perhaps failure to properly explain) the following statement:关于 OP 对以下陈述的误解(或可能未能正确解释):

document.onclick = null; // important idea

From what I gather is that OP is worried that document will detect the click event and call the event handler, thereby incurring two calls to the event handler in rapid succession.据我所知,OP 担心document会检测到单击事件并调用事件处理程序,从而导致快速连续两次调用事件处理程序。 Once by document and the other by .control -- hence the misunderstanding that setInterval() was useful in this particular situation.一次通过document ,另一个通过.control因此误解setInterval()在这种特殊情况下很有用。


Event Handlers / Callbacks 2 事件处理程序/回调2

OP treats the event handlers as normal anonymous functions (which is why OP is creating two separate functions to change two separate "states" and struggling with when a call happens and when a call shouldn't ). OP 将事件处理程序视为普通的匿名函数(这就是为什么 OP 正在创建两个单独的函数来更改两个单独的“状态”,并在呼叫发生和呼叫不应该发生时挣扎)。

  • Standard Anonymous Function标准匿名函数
    Anonymous functions are defined and invoked when parsed.匿名函数在解析时被定义和调用。 When the browser notices the parenthesis ( ex. function() ) it will interpret it as: "Run this function NOW " ).当浏览器注意到括号(例如, function()将它解释为:“立即执行此功能”)。

     const nodeRef = () => {... /* or */ var nodeRef = function() {...
  • Event Handler事件处理程序
    Event handlers are functions that wait for a registered event to happen before they run .事件处理程序是在运行之前等待注册事件发生的函数。 Note the similarities they share:请注意它们的相似之处:

     //~~~~ Defined (aka Named) domNode.onclick = functionName; /* or */ domNode.addEventListener('click', functionName); function functionName(eventObject) {... /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ //~~~ Anonymous domNode.onclick = function(eventObject) {... /* or */ domNode.addEventListener('click', function(eventObject) {...
    • When registered event is triggered the event handler is called, thus the only time parenthesis are included is when an event handler is defined.当注册的事件被触发时,将调用事件处理程序,因此只有在定义事件处理程序时才包含括号。 Note a defined event handler does not have parenthesis () because their definitions are hoisted to the top.请注意,定义的事件处理程序没有括号()因为它们的定义被提升到顶部。

    • Also by default event handlers pass the Event Object .默认情况下,事件处理程序也会传递Event Object Always include it as the first parameter when defining an event handler.定义事件处理程序时,始终将其作为第一个参数包含在内。 By explicitly passing the event object (typically as e , event , evt ...) the event handler can access the event object's properties such as event.type , event.currentTarget , and event.target .通过显式传递事件对象(通常为eeventevt ...),事件处理程序可以访问事件对象的属性,例如event.typeevent.currentTargetevent.target

    • event.currentTarget is an object (typically a HTMLElement ) that is registered to an event (it "listens" for a specific event to happen). event.currentTarget是一个注册到事件的对象(通常是HTMLElement )(它“监听”特定事件的发生)。 It is also referred to as this within the definition of its associated event handler.它在其关联事件处理程序的定义中也称为this
    • event.target is the object to which the registered event originated from. event.target是注册事件源自的对象。 For example, if the fifth button out of a hundred identical buttons was clicked, event.target will accurately reference that particular button.例如,如果单击了一百个相同按钮中的第五个按钮, event.target将准确引用该特定按钮。

Hopefully what an event handler is and what it does is a little more clearer.希望事件处理程序是什么以及它做什么更清楚一些。 Moreover how indispensable Event Object is.何况 Event Object 是多么的不可或缺。 The next section explains Event Phases which details the unseen chain of events happening within the DOM tree .下一节将解释事件阶段,其中详细介绍了DOM 树中发生的不可见事件链。


Event Phases 事件阶段

<!DOCTYPE html><!--document------------------🔻-->
<html><!-----------document.documentElement--🔻-->
 ...
   <body><!--------document.body-------------🔻-->
     <form id="ui"><!--document.forms.ui-----➕--HTMLFormElement Interface
                    ---event.currentTarget---➕--Registered to click event
                    ---this------------------🔽-->
       <button class='ctx'><!--event.target--⏬-->
         CLICKED!
       </button>
       <fieldset class='box ok'><!--event.target.nextElementSibling--🆗-❙-🚫-->
       </fieldset>
     </form>
    </body>
 </html>

👇 Capture Phase 👇捕获阶段

  • ex.前任。 User clicks button.ctx and becomes event.target用户点击button.ctx并变成event.target
    • event.target parent is event.currentTarget (ie form ) event.target父级是event.currentTarget (即form
    • Event path: document , html , body , form .事件路径: documenthtmlbodyform
    • The path (and current capture phase) ends when the parent of the event origin (aka event.target ) has been reached.当到达事件源(又名event.target )的父级时,路径(和当前捕获阶段)结束。
    • This phase is rarely used specifically by the developer and is usually disregarded (there some exceptions such as key events)这个阶段很少被开发者专门使用,通常会被忽略(有一些例外,比如关键事件)

🎯 Target Phase 🎯 目标阶段

  • ex.前任。 After completing the path from document to the parent element (ie document.forms.ui ) of the button the target phase begins完成从documentbutton的父元素(即document.forms.ui )的路径后,目标阶段开始
    • Once event.target is determined, the element positioned immediately after it (ie event.target.nextElementSibling ) will change "state" ( .box.ok OR .box.rd ).一旦event.target被确定,紧跟在它之后的元素(即event.target.nextElementSibling )将改变“状态”.box.ok OR .box.rd )。
    • The event handler stops propagation (ie stops the bubbling phase from continuing) when target phase is completed or .ctx wasn't clicked.当目标阶段完成或.ctx未被点击时,事件处理程序停止传播(即停止冒泡阶段继续)。 This desired behavior is done by ending statement: event.stopPropagation() .这种期望的行为是通过结束语句完成的: event.stopPropagation()
    • Event path has only a single reference to event.target .事件路径只有一个对event.target引用。
    • This phase is the most important one because it singles out the clicked button even if there were a thousand buttons.这个阶段是最重要的阶段,因为即使有一千个按钮,它也会挑出被点击的按钮。

👆 Bubbling Phase 👆 冒泡阶段

  • ex.前任。 Normally, after the target phase is complete the path is reversed.通常,在目标阶段完成后,路径会反转。
    • Since there where no other objectives it's pointless to continue the event chain so event.stopPropagation() prevents the click event from going any further up the DOM tree.因为在那里没有其他目标,继续事件链是没有意义的,所以event.stopPropagation()阻止单击事件进一步向上 DOM 树。
    • Incidentally, this also excludes ancestor elements / objects such as document from the click event.顺便说一句,这也从单击事件中排除了祖先元素/对象,例如document

Consider the programming pattern called Event Delegation .考虑称为事件委托的编程模式。

  • Advantages好处

    • Multiple targeted elements 3 (aka event.target ) -- ex.多个目标元素3 (又名event.target )——例如。 a <button> user has clicked) can be specified and exclude non-targeted elements 4 ( ex. document or body which could interfere and inhibit proper behavior if a click anywhere triggered an event handler). <button>用户已单击)可以指定并排除非目标元素4例如,如果单击任何地方触发事件处理程序, documentbody可能会干扰和抑制正确的行为)。

    • Only register one element to handle one or more targeted elements at once.一次只注册一个元素来处理一个或多个目标元素。

    • The targeted elements include ones that are dynamically added in the future as well.目标元素也包括将来动态添加的元素。

  • Requirements要求

    • An ancestor element that all te have in common.所有te都有的祖先元素。 It can be a top-level object such as document or window but it's better to assign or create an element that is as close to the te as possible.它可以是顶级对象,例如documentwindow但最好分配或创建一个尽可能接近te的元素。 The closer the less likely buggy behavior will occur (such as double calls to event handlers).越接近错误行为发生的可能性就越小(例如对事件处理程序的双重调用)。

    • Register the event to said ancestor element.将事件注册到所述祖先元素。 There are three ways to register an element to an event using plain JavaScript.使用纯 JavaScript 可以通过三种方法将元素注册到事件。

      • On-event Property Event事件属性事件
        My personal favorite because it's terse我个人最喜欢的,因为它很简洁

        document.forms.ui.onclick = ctrl;
      • EventListener事件监听器
        In general the most recommended way -- the only significant difference between them is that the third optional parameter will use the capture phase instead of the default bubbling phase by passing true .一般来说,最推荐的方式——它们之间唯一的显着区别是第三个可选参数将通过传递true来使用捕获阶段而不是默认的冒泡阶段。

         document.forms.ui.addEventListener('click', ctrl, true);
      • On-event Attribute Event事件属性事件
        This way of event handling is as old as dirt and its use is not recommended due to it's many limitations.这种事件处理方式与污垢一样古老,由于存在许多限制,因此不推荐使用。 I have included it just the sake of completeness, DO NOT IMPLEMENT THIS TECHNIQUE .我只是为了完整性而将其包含在内,请勿实施此技术

         <form id='ui' onclick="ctrl(e); return false"> <button class='ctx' type='button'>THIS IS LAME!</button> <fieldset class='box ok'></fieldset> </form>
    • When defining the event handler, establish the following:在定义事件处理程序时,建立以下内容:

      • Ensure that the current event.target (remember the event phases are not idle) isn't event.currentTarget .确保当前的event.target (记住事件阶段不是空闲的)不是event.currentTarget Once that's establish narrow down the possibilities further by using control or ternary statements.一旦确定,通过使用控制或三元语句进一步缩小可能性。

         ... if (event.target !== this) { if (event.target.classList.contains('ctx')) {... ...
      • By implementing narrow criterion and using event.stopPropagation() , excluding everything else is simple.通过实施窄标准并使用event.stopPropagation() ,排除其他一切都很简单。

         ... } else { event.stopPropagation(); } } event.stopPropagation(); }

Demo演示

 const ui = document.forms.ui; ui.onclick = ctrl; function ctrl(event) { const clicked = event.target; if (clicked !== this) { if (clicked.classList.contains('ctx')) { const box = clicked.nextElementSibling; box.classList.toggle('ok'); box.classList.toggle('rd'); } else { event.stopPropagation(); } } event.stopPropagation(); }
 .ctx { font-size: 1.5rem; cursor: pointer; } .box { width: 200px; height: 200px; background: red; border: 0; transition: 1s; } .rd { border-radius: 50%; } .ok { border: 10px dotted blue; }
 <form id='ui'> <button class="ctx" type='button'>Control</button> <fieldset class="box ok"></fieldset> </form>


Footnotes脚注

1 In the SO community (not sure about the SE as a whole), OP is used interchangeably between O riginal P oster (the member asking the question) or O riginal P ost (the question itself). 1SO社区(不知道的SE作为一个整体),OP可互换öriginal P奥斯特(成员提出问题)或O- riginal P OST(问题本身)之间使用。

2 At times the terms event handler , event listener , and callback may be used to refer to a function called after an event happens. 2有时,术语事件处理程序事件侦听器回调可用于指代事件发生后调用的函数。 For the purpose of this answer that holds true.就这个答案而言,这是正确的。 For a more definitive explanation refer to this post .有关更明确的解释,请参阅此帖子

3 The term targeted elements ( te )is coined by myself to refer to elements within the DOM that share a common ancestor and can be a potential event.target made possible by well crafted HTML/CSS and JavaScript configured to effectively delegate events. 3术语靶向元件(TE)是由自己创造来指代元件的共用祖先共享DOM内,并且可以是一个潜在的event.target成为可能,以及制作的HTML / CSS和JavaScript构造成有效地委派的事件。

4 Non-targeted elements ( nte ) is an ad-hoc term to describe elements that should be excluded from reacting to certain events for various reasons. 4非目标元素( nte ) 是一个临时术语,用于描述因各种原因应被排除在对某些事件作出反应之外的元素。 Commonly nte are the ancestor elements/objects of the event.currentTarget such as document , body , etc. While there are times when high level nodes on the DOM tree serve well as event.currentTarget , it's best to keep event.currentTarget as close to the te as possible.通常nteevent.currentTarget的祖先元素/对象,例如documentbody等。 虽然有时 DOM 树上的高级节点可以很好地用作event.currentTarget ,但最好保持event.currentTarget尽可能接近te尽可能。


References参考

The following references cover other aspects I didn't cover thoroughly in order to avoid info overload (in retrospect I believe I have failed).以下参考资料涵盖了我没有完全涵盖的其他方面,以避免信息过载(回想起来,我认为我失败了)。

HTMLFormElement HTML表单元素

const ui = document.forms.ui;

.nextElementSibling .nextElement 兄弟姐妹

clicked.nextElementSibling;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM