情况:
我有一个网页打开模态窗口(灯箱),其中包含用户可以输入数据的表单。用户通常使用键盘进行导航,从一个字段切换到下一个字段。
问题:
当模态窗口打开时,只有窗口处于活动状态,使用鼠标无法访问页面的其余部分,但可以通过从模式窗口中跳出来访问元素。
问题:
如何使用标签按钮仅限表单窗口中的元素来限制移动?
我唯一能想到的是在打开模态窗口时使用Javascript在所有表单元素(以及其他可聚焦元素)上设置tabindex=-1
,然后将tabindex
值设置回以前的值模态窗口关闭时的值。
有更简单/更好的方法吗?
答案 0 :(得分:6)
不,这是唯一的方法。
tabIndex
大于-1
†并且不属于您的模态的所有元素。tabIndex
的引用填充它。tabIndex
设置为-1
,使其无法再从键盘获得焦点。tabIndex
。这是一个快速演示:
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>
†我们寻找tabIndex > -1
,以便我们可以专注于可选元素。您可以进一步限制该过滤器忽略隐藏的元素,但我会留给您。在任何一种情况下,清单都不应该很大
‡或者,如在演示中,您可以使用一系列函数填充数组,其唯一目的是重置tabIndex
。您也可以完全放弃数组,只需向受影响的元素添加data-original-tab-index
属性...使用document.querySelectorAll("[data-original-tab-index]")
在事后检索它们。
这是一个使用数据属性存储原始tabIndex
的演示,因此您不必维护自己的数组:
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>
参见HTMLElement.dataset
答案 1 :(得分:3)
如何抓住tab-key
?在最后一个元素上然后将焦点放在第一个元素上,反之亦然shift-tab
这是我在多模态 - diaolog环境中使用,在对话框中保持焦点,在鼠标或其他键的对话框之间切换
inputs=".editing, input, textarea, button, a, select"
no_tab="[type='hidden'], :disabled"
$focusable=dlg.$form.find(inputs).not(no_tab)
$fa_first=$focusable.first()
$fa_last=$focusable.last()
$fa_last.on("keydown", (evt) =>
if evt.keyCode==9 && ! evt.shiftKey
$fa_first.focus()
evt.preventDefault()
false
)
$fa_first.on("keydown", (evt) =>
if evt.keyCode==9 && evt.shiftKey
$fa_last.focus()
evt.preventDefault()
false
)
小编辑:替换了我的on&#34; unibind()&#34; (= .off(x).on(x))函数通过jQuery&#34; on()&#34;
答案 2 :(得分:1)
查看jQuery BlockUI Plugin。它们有an example using a modal box with two buttons,它也限制了标签。
它可能会或者可能不会与您的模态窗口一起开箱即用,但值得一看,而不必实施自己的解决方案。
答案 3 :(得分:0)
即使这是一篇旧帖子,我也在寻找解决这个问题的方法,并做了以下工作来解决它。
使用JQuery我会在模态窗口打开时禁用不同形式和div的所有输入字段(模态窗体本身除外)。
$('#formId :input').prop('disabled',true);
关闭模态窗体时,可以再次启用输入元素。
在页面周围“标记”时,不会考虑禁用字段。
答案 4 :(得分:0)
如果您想将焦点限制在“父母” dom内部
parent.addEventListener('focusout', function(event) {
event.stopPropagation();
if (node.contains(event.relatedTarget)) { // if focus moved to another
parent descend
return;
}
parent.focus(); // otherwise focus on parent or change to another dom
})
所有现代浏览器都支持