限制tabindex聚焦到页面的一部分 [英] Restrict tabindex focusing to a section of the page

查看:434
本文介绍了限制tabindex聚焦到页面的一部分的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个打开模式窗口(灯箱)的网页,其中包含用户可以输入数据的窗体。 用户通常使用键盘导航,从一个栏位跳到下一个栏位。



问题:

打开模式窗口时,只有窗口处于活动状态,页面的其余部分无法通过鼠标访问,但可通过从模式窗口中退出来访问元素。



问题:
$ b

如何通过使用tab按钮仅限表单窗口中的元素来限制移动?



我唯一能想到的就是使用Javascript在所有表单元素上设置 tabindex = -1 当模态窗口打开时,然后在模态窗口关闭时将 tabindex 值设置回它们以前的值。
是否有更简单/更好的方法?

解决方案

不,这是唯一的方法。
$ b


  1. 查找所有具有 tabIndex 大于 -1 并且不属于您的模式。 创建数组每个元素及其原始 tabIndex

  2. 将每个元素的 tabIndex 设置为 -1 因此它不能再从键盘获得焦点。

  3. 当模式对话框关闭时,迭代您的数组并恢复原始 tabIndex

下面是一个快速演示:



 函数isDescendant(ancestor,descendant){do {if(descendant === ancestor)return true; } while(descendant = descendant.parentNode);返回false;} var tabIndexRestoreFunctions; var lastFocused; document.getElementById(btn-show-modal)。addEventListener(click,function(e){lastFocused = document.activeElement; var modal = document.querySelector(。modal ); tabIndexRestoreFunctions = Array.prototype //获得不是我们模态子项的tabable项目(document.all,o => o.tabIndex> -1&&!isDescendant(modal, o))//遍历这些项目,设置tabIndex为-1,//返回一个函数来恢复tabIndex .map(o => {var oldTabIndex = o.tabIndex; o.tabIndex = -1; return )=> o.tabIndex = oldTabIndex;}); // show modal modal.classList.add(shown); // focus modal autofocus modal.querySelector([autofocus])。focus();}) ; document.getElementById(btn-close-modal)。addEventListener(click,function(e){// restore tabs tabIndexRestoreFunctions&&&&& tabIndexRestoreFunctions.forEach(f => f()); tabIndexRestoreFunctions = null ; //隐藏模式文档nt.querySelector( 模态 )classList.remove( 示出); //恢复焦点lastFocused&&  

.modal {显示:无;位置:固定; top:0;正确:0;底部:0;左:0; background-color:rgba(128,128,128,.75);} .modal.shown {display:flex;} .modal-content {margin:auto;宽度:500px;填充:30px; border:1px solid#333; < label>
test< input autofocus />< / label><按钮>虚拟按钮< /按钮>< hr /><按钮id =btn-show-modal>打开模式< /按钮><< ; div class =modal> < div class =modal-content> < label>测试<输入自动对焦/> < /标签> < button id =btn-close-modal>关闭模式< / button> < / div>< / div>

我们寻找 tabIndex> -1 ,这样我们就可以专注于tabable元素。您可以进一步限制该过滤器忽略隐藏的元素,但我会将其留给您。在这两种情况下,列表都不应该很大。另外,如在演示中,您可以使用一系列函数填充数组,其唯一目的是重置 tabIndex 。您也可以完全放弃数组,并简单地向受影响的元素添加 data-original-tab-index 属性...使用 document.querySelectorAll [data-original-tab-index])以在事实之后检索它们。 数据属性来存储原始的 tabIndex ,所以你不必维护自己的数组:

 函数isDescendant(ancestor,descendant){do {if(descendant === ancestor)return true; } while(descendant = descendant.parentNode);返回false;} var lastFocused; document.getElementById(btn-show-modal)。addEventListener(click,function(e){lastFocused = document.activeElement; var modal = document.querySelector(。modal); Array.prototype.forEach.call(document.all,o => {if(o.tabIndex> -1&&!isDescendant(modal,o)){o.dataset.originalTabIndex = o.tabIndex; o .tabIndex = -1;}}); // show modal modal.classList.add(shown); // focus modal autofocus modal.querySelector([autofocus])。focus();}); document。 getElementById(btn-close-modal)。addEventListener(click,function(e){// restore tabs Array.prototype.forEach.call(document.querySelectorAll([data-original-tab-index]) ,o => {o.tabIndex = o.dataset.originalTabIndex; delete o.dataset.originalTabIndex;}); // hide modal document.querySelector(。modal)。classList.remove(shown); / restore focus lastFocused&& lastFocused.focus();});  

  .modal {display:none;位置:固定; top:0;正确:0;底部:0;左:0; background-color:rgba(128,128,128,.75);} .modal.shown {display:flex;} .modal-content {margin:auto;宽度:500px;填充:30px; border:1px solid#333; < label>        test< input autofocus />< / label><按钮>虚拟按钮< /按钮>< hr /><按钮id =btn-show-modal>打开模式< /按钮><< ; div class =modal> < div class =modal-content> < label>测试<输入自动对焦/> < /标签> < button id =btn-close-modal>关闭模式< / button> < / div>< / div>  

请参阅 HTMLElement。数据集


Situation:

I have a webpage which opens modal windows (light boxes) which contain forms where the user can input data. Users generally navigate using the keyboard, tabbing from one field to the next.

Problem:

When a modal window opens, only the window is active, the rest of the page is not accessible using the mouse, but elements can be reached by tabbing out of the modal window.

Question:

How can I restrict movement by using the tab button to only the elements within the form window?

The only thing I can think of is using Javascript to set tabindex=-1 on all form elements (and other focusable elements) when the modal window is opened and then set the tabindex values back to their previous values when the modal window is closed. Is there a simpler/better way?

解决方案

No, it's the only way.

  1. Find all elements which have a tabIndex greater than -1 and don't belong to your modal.
  2. Create an array and fill it with references to each element along with its original tabIndex.
  3. Set each element's tabIndex to -1 so it can no longer receive focus from the keyboard.
  4. When the modal dialog is closed, iterate over your array and restore the original tabIndex.

Here's a quick demo:

function isDescendant(ancestor, descendant) {
  do {
    if (descendant === ancestor) return true;
  } while (descendant = descendant.parentNode);
  return false;
}

var tabIndexRestoreFunctions;
var lastFocused;

document.getElementById("btn-show-modal").addEventListener("click", function(e) {
  lastFocused = document.activeElement;
  var modal = document.querySelector(".modal");
  tabIndexRestoreFunctions = Array.prototype
  // get tabable items which aren't children of our modal
  .filter.call(document.all, o => o.tabIndex > -1 && !isDescendant(modal, o))
  // iterate over those items, set the tabIndex to -1, and 
  // return a function to restore tabIndex
  .map(o => {
    var oldTabIndex = o.tabIndex;
    o.tabIndex = -1;
    return () => o.tabIndex = oldTabIndex;
  });
  // show modal
  modal.classList.add("shown");
  // focus modal autofocus
  modal.querySelector("[autofocus]").focus();
});

document.getElementById("btn-close-modal").addEventListener("click", function(e) {
  // restore tabs
  tabIndexRestoreFunctions && tabIndexRestoreFunctions.forEach(f => f());
  tabIndexRestoreFunctions = null;
  // hide modal
  document.querySelector(".modal").classList.remove("shown");
  // restore focus
  lastFocused && lastFocused.focus();
});

.modal {
  display: none;
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background-color: rgba(128, 128, 128, .75);
}
.modal.shown {
  display: flex;
}
.modal-content {
  margin: auto;
  width: 500px;
  padding: 30px;
  border: 1px solid #333;
  background-color: #fdfdfd;
}

<label>test
  <input autofocus />
</label>
<button>dummy button</button>
<hr/>
<button id="btn-show-modal">open modal</button>
<div class="modal">
  <div class="modal-content">
    <label>test
      <input autofocus />
    </label>
    <button id="btn-close-modal">close modal</button>
  </div>
</div>

We look for tabIndex > -1 so that we can focus specifically on tabable elements. You could further restrict that filter to ignore hidden elements, but I'll leave that to you. In either case, the list shouldn't be very big.
Alternatively, as in the demo, you could fill the array with a series of functions whose sole purpose is to reset tabIndex. You could also forego the array entirely and simply add a data-original-tab-index attribute to the affected elements... using document.querySelectorAll("[data-original-tab-index]") to retrieve them after the fact.

Here's a demo which uses data attributes to store the original tabIndex so you don't have to maintain your own array:

function isDescendant(ancestor, descendant) {
  do {
    if (descendant === ancestor) return true;
  } while (descendant = descendant.parentNode);
  return false;
}

var lastFocused;

document.getElementById("btn-show-modal").addEventListener("click", function(e) {
  lastFocused = document.activeElement;
  var modal = document.querySelector(".modal");
  Array.prototype.forEach.call(document.all, o => {
    if (o.tabIndex > -1 && !isDescendant(modal, o)) {
      o.dataset.originalTabIndex = o.tabIndex;
      o.tabIndex = -1;
    }
  });
  // show modal
  modal.classList.add("shown");
  // focus modal autofocus
  modal.querySelector("[autofocus]").focus();
});

document.getElementById("btn-close-modal").addEventListener("click", function(e) {
  // restore tabs
  Array.prototype.forEach.call(document.querySelectorAll("[data-original-tab-index]"), o => {
    o.tabIndex = o.dataset.originalTabIndex;
    delete o.dataset.originalTabIndex;
  });
  // hide modal
  document.querySelector(".modal").classList.remove("shown");
  // restore focus
  lastFocused && lastFocused.focus();
});

.modal {
  display: none;
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background-color: rgba(128, 128, 128, .75);
}
.modal.shown {
  display: flex;
}
.modal-content {
  margin: auto;
  width: 500px;
  padding: 30px;
  border: 1px solid #333;
  background-color: #fdfdfd;
}

<label>test
  <input autofocus />
</label>
<button>dummy button</button>
<hr/>
<button id="btn-show-modal">open modal</button>
<div class="modal">
  <div class="modal-content">
    <label>test
      <input autofocus />
    </label>
    <button id="btn-close-modal">close modal</button>
  </div>
</div>

See HTMLElement.dataset

这篇关于限制tabindex聚焦到页面的一部分的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆