单击时禁用按钮一分钟

Disable Button for one minute when it's clicked

我正在尝试制作一个按钮,当您单击它时将禁用 1 分钟。 仅当启用该按钮并单击它时,才应将 25 点添加到 div(div 从 0 开始)。 每次点击后,按钮将被禁用,计时器将启动 运行.

这里有一些图片可以让整个事情更容易理解:

类似于:

const button = document.getElementById("myBtn")

function freeze () {
  button.disabled = true
  setTimeout(function() { 
    button.disabled = false
  }, 60000);
}

button.onclick = function () {
 if(button.disabled) { // Avoid user removing disable in the html
  // Add 25 to whatever
    freeze()
  }
}

另一种可能是:

这是你的按钮:

<button id="MyBtn" onclick="disable_button_3_secs(); return false;">Disabled me for 3 seconds</button>

这是你的脚本:

    var timeout_lenght = 3000;
    var myBtn = document.getElementById("MyBtn");

    function disable_button_3_secs() {
        myBtn.disabled = true;
        Enable_at_timer_out();
    }

    function Enable_at_timer_out() {
        setTimeout(function () {myBtn.disabled = false; }, timeout_lenght);
    }

我个人喜欢对我的代码有更多的控制权,所以我总是尽可能地使用变量。我已将计时器设置为 3 秒,但您可以根据需要更改它。

大卫

Here is your code

$('#btn').prop('disabled',true);
startCountDown();

function getCounter(){
  return  parseInt($('#counter').html());
}
function setCounter(count) {
  $('#counter').html(count);
}

$("#btn").click(function() {
  setCounter(getCounter()+25);
  $('#btn').prop('disabled',true);
  startCountDown();
});

function startCountDown() {
  var minutes = 0,
    seconds = 59;
  $("#countdown").html(minutes + ":" + seconds);
  var count = setInterval(function() {
    if (parseInt(minutes) < 0 || parseInt(seconds) <=0 ) {
      $("#countdown").html(minutes + ":" + seconds);
      clearInterval(count);
      $('#btn').prop('disabled',false);
    } else {
      $("#countdown").html(minutes + ":" + seconds);
      seconds--;
      if (seconds < 10) seconds = "0" + seconds;
    }
  }, 1000);
}
#counter{
  font-size: 25px;
  color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="counter">0</div>
<button id="btn">
<span id="countdown">0:00</span>
</button>

可以创建 Custom Element.
这需要了解以下主题:

基本结构

定义一个 自定义元素 需要一个 JS class 扩展 HTMLElement(或其子元素之一-classes).

此 class 然后通过使用其 HTML 元素名称调用 customElements.define() 注册为 HTML 元素(必须包含 -(连字符) 它的名字,例如“example-element”)和它关联的class。

我决定调用 class CounterElement 和 HTML 元素 <counter-instance>:

class CounterElement extends HTMLElement {
  constructor() {
    super(); // Required since we are extending a class
  }
}
customElements.define('counter-instance', CounterElement);

设置影子根

设置影子根是这样完成的:

  1. 通过调用 Element.attachShadow()
  2. 创建影子根
  3. 创建并附加其 HTML-元素
  4. 为影子根添加样式

由于一些评论提到访问元素仍然很容易,我决定使用 {mode: 'closed'} 来防止不知情的用户访问它们。但是,并非无法访问。这将需要一个 MutationObserver,但此答案中未包含它以使其(有点)简短,heh.

使用{mode: 'closed'}时,需要手动保留对影子根的引用。我决定使用私有成员变量 #shadow.

现在,需要创建和追加影子根的元素。同样,我保留了“重要”元素的私人参考:#samp#button.

我还添加了一些样式。

class CounterElement extends HTMLElement {
  #shadow;
  #samp;
  #button;
  
  constructor() {
    super();
    
    // Shadow Root
    this.#shadow = this.attachShadow({mode: 'closed'});
    
    let div = document.createElement('div');
    let style = document.createElement('style');
    style.innerHTML = 'div{padding:0.2rem;border:1px solid black}'
        + 'samp{display:block}button{font-family:monospace}';
    
    this.#samp = document.createElement('samp');
    this.#button = document.createElement('button');
    
    div.append(this.#samp, this.#button);
    this.#shadow.append(style, div);
  }
}
customElements.define('counter-instance', CounterElement);

设置元素

既然所有重要元素都存在,我们需要正确设置它们。那样的话,我的意思是添加他们应该有的文本。

由于我们将跟踪计数器和秒数,因此将它们声明为成员变量是有意义的。

为了将秒格式化为 mm:ss 格式,我编写了一个实用函数 formatTime()。好像还蛮好用的,所以可以在全局范围内。
注意您应该尽量不要用太多变量使全局范围混乱。您可以使用 IIFEs 将它们保存在本地。

现在,添加文本就像使用 HTMLElement.innerText 一样简单。

在评论中,您要求在秒数达到 0 时让按钮显示“收集”。这可以使用 if-else 语句来完成,但为了简洁起见,我使用了 Ternary Operator.

function formatTime(seconds) {
  var min = new String(Math.floor(seconds / 60));
  var sec = new String(seconds % 60);

  while (min.length < 2) min = '0' + min;
  while (sec.length < 2) sec = '0' + sec;

  return min + ':' + sec;
};

class CounterElement extends HTMLElement {
  counter = 0;
  seconds = 0;
  #shadow;
  #samp;
  #button;
  
  constructor() {
    super();
    
    // Shadow Root
    // ...
    
    this.updateText();
  }
  
  updateText() {
    this.#samp.innerText = this.counter;
    this.#button.innerText = this.seconds ? formatTime(this.seconds) : 'Collect';
  }
}
customElements.define('counter-instance', CounterElement);

添加(计时器)功能

现在的最后一步是添加计时器和 onclick-listener。

由于我们想在点击#button时开始计时,并在seconds达到0后停止计时,我们可以使用setInterval()clearInterval()分别。

前者函数returns区间的ID,后者用区间ID清除。要按预期使用这些函数,我们需要保留对间隔 ID 的引用。

单击 #button 时,应该:

  • 重置seconds并增加counter
  • 启动我们的计时器
  • 在我们的计时器持续时间内被禁用
  • 更新关于现在重置值的文本

这是我们实现它的(缩短的)代码:

// function formatTime(seconds) () { ... }

class CounterElement extends HTMLElement {
  counter = 0;
  seconds = 0;
  #shadow;
  #samp;
  #button;

  constructor() {
    super();

    // Shadow Root
    // ...
    
    let intervalId;
    let intervalStep = () => { // Will be called every second
      this.updateText();
      if (--this.seconds <= 0) {
        clearInterval(this.#intervalId);
        this.#button.disabled = false;
      }
    };
    
    this.#button.addEventListener('click', () => {
      this.seconds = 60;
      this.counter += 25;
      this.#intervalId = setInterval(intervalStep, 1000);
      this.#button.disabled = true;
      this.updateText();
    });
    
    this.updateText();
  }
  
  // Member-functions ...
}
customElements.define('counter-instance', CounterElement);

结论

如前所述,仍然可以使用开发人员工具访问影子根的元素。完全禁用更改按钮的 disabled-属性 的能力可以使用 MutationObserver 来实现,保持 属性 不被更改,具体取决于 seconds 当前拥有的数字。

这里是 Stack-Snippet 的完整代码,您可以自己尝试一下:

function formatTime(seconds) {
  var min = new String(Math.floor(seconds / 60));
  var sec = new String(seconds % 60);

  while (min.length < 2) min = '0' + min;
  while (sec.length < 2) sec = '0' + sec;

  return min + ':' + sec;
};

class CounterElement extends HTMLElement {
  counter = 0;
  seconds = 0;
  #shadow;
  #samp;
  #button;
  
  constructor() {
    super();
    
    // Shadow Root
    this.#shadow = this.attachShadow({mode: 'closed'});
    
    let div = document.createElement('div');
    let style = document.createElement('style');
    style.innerHTML = 'div{padding:0.2rem;border:1px solid black}'
        + 'samp{display:block}button{font-family:monospace}';
    
    this.#samp = document.createElement('samp');
    this.#button = document.createElement('button');
    
    div.append(this.#samp, this.#button);
    this.#shadow.append(style, div);
    
    let intervalId;
    let intervalStep = () => { // Will be called every second
      if (--this.seconds <= 0) {
        clearInterval(intervalId);
        this.#button.disabled = false;
      }
      this.updateText();
    };
    
    this.#button.addEventListener('click', () => {
      this.seconds = 60;
      this.counter += 25;
      intervalId = setInterval(intervalStep, 1000);
      this.#button.disabled = true;
      this.updateText();
    });

    this.updateText();
  }
  
  updateText() {
    this.#samp.innerText = this.counter;
    this.#button.innerText = this.seconds ? formatTime(this.seconds) : 'Collect';
  }
}
customElements.define('counter-instance', CounterElement);
/* Ignore; only for styling purposes */
body {
  display: flex;
  gap: 0.6rem;
}
<!-- Works with multiple elements -->
<counter-instance></counter-instance>
<counter-instance></counter-instance>