如何防止点击复选框的标签来窃取焦点

时间:2015-10-05 21:20:41

标签: javascript html

Mac OS X上的默认行为是单击复选框和按钮不会从具有焦点的其他控件(例如,文本框)中窃取焦点。我想在网上实现这一点。

我可以使用按钮和复选框本身,但不能用于复选框标签。

以此jsbin为例:
http://jsbin.com/kopateluze/1/edit?html,console,output

以下是表单的截图:

Screenshot of http://jsbin.com/kopateluze/1/edit?html,console,output

如果您首先关注文本框然后点击该按钮,则可以使用event.preventDefault()上的mousedown来防止文本框失去焦点。这很好用。如果你首先关注文本框,然后单击复选框,同样的事情就可以了。

但是,如果您首先关注文本框,然后点击复选框的label文字,它就无法运作;文本框失去了焦点。

有没有办法阻止点击复选框label从其他控件中窃取焦点?

纯JavaScript,请随时链接到库中实现的解决方案的源代码。

1 个答案:

答案 0 :(得分:2)

好的,这是我能够弄清楚的事情,比事发后两年多一点。

防止按钮窃取焦点

首先,让我们谈谈推动这个问题的例子。当文本字段具有焦点时,我希望防止单击按钮来窃取焦点。我仍然希望调用任何按钮点击处理程序,我只是不想让焦点移动。

要做到这一点,我们只需要知道按钮会在mousedown上得到关注,因此阻止它就像使用event.preventDefault()一样简单:



<input placeholder="First focus me" type="text" />

<br/>

<button
  onmousedown="event.preventDefault()"
  onclick="console.log('button:click')">
    Then click me
</button>
&#13;
&#13;
&#13;

请注意,单击该按钮会触发单击处理程序,但永远不会使该按钮获得焦点。另请注意,通过按Tab按钮仍然可以获得焦点,因此这不会损害键盘访问。

防止复选框被盗“

事实证明,只要您使用没有标签的裸体复选框,这种技术就可以完美运行。

&#13;
&#13;
<input placeholder="First focus me" type="text" />

<br/>

<input
  type="checkbox"
  onmousedown="event.preventDefault()"
  onclick="console.log('checkbox:click')"
/>
⇐ Then click the checkbox
&#13;
&#13;
&#13;

但是这确实存在可访问性问题,因为描述复选框的文本没有与之关联,复选框单击目标只是复选框本身,而不是随之而来的文本。这里的解决方案是添加label元素,但这就是问题的起源。

复选框具有标签

时的问题

&#13;
&#13;
<input placeholder="First focus me" type="text">

<br/>

<label>
  <input type="checkbox"
    onmousedown="event.preventDefault()"
    onclick="console.log('checkbox:click')"
  />
  Then click me
</label>
&#13;
&#13;
&#13;

如果单击复选框,则会成功阻止复选框窃取焦点。但是,如果单击复选框旁边的文本,则会从文本框中删除焦点。

复选框具有标签

时的修复

关键在于了解label元素如何与其关联的input元素进行交互。 label元素的click处理程序实际上会被调用两次:event.targetlabel元素,而复选框就是{。}}。

因此,一般的解决方法是:

  1. 在标签和复选框的event.preventDefault()上致电mousedown
  2. 在标签点击处理程序中,执行两次,在关联控件(复选框元素)上调用.click(),但仅当event.target等于label元素时。
  3. &#13;
    &#13;
    <input placeholder="First focus me" type="text" />
    
    <br/>
    
    <label for="checkbox"
      onmousedown="event.preventDefault()"
      onclick="
        console.log('label:click');
        if (this === event.target) {
          console.log('label === event.target');
          console.log('label:click preventDefault()');
          // prevent focus and click
          event.preventDefault();
          // call click on the labeled control
          this.control && this.control.click();
        }
      ">
      <input id="checkbox" type="checkbox"
        onmousedown="event.preventDefault()"
        onclick="
          console.log('checkbox:click', `checked = ${this.checked}`);
        "
      />
      Then click me
    </label>
    &#13;
    &#13;
    &#13;