按住 keydown 问题时单击时的 Firefox 事件传播
Firefox Event propagation on click while holding keydown problem
我正在实施 table 行多 selection,它应该像这样工作:
单击第一行,然后按住 Shift 键并单击底行应该 select 之间的所有行。
我还使用自定义复选框,基本上是复选框 + 标签的组合。我也仅在 table 上利用事件传播和绑定事件处理程序。
问题是在 Firefox 上按住 Shift 键时事件不会从标签冒泡到输入。
var lastCheckedRow = null;
$("table").click(function handleRowCheckboxClick(e) {
var $t = $(e.target);
// check if target is checkbox, otherwise ignore event ( on label )
if ($t.is(":checkbox")) {
var $cb = $t.is(":checkbox") ? $t : $t.siblings("input.mof-cell-checkbox");
// if not disabled
if (!$cb.prop("disabled")) {
if ($cb.hasClass("mof-cell-checkbox")) {
if (window.getSelection().empty) {
// Chrome
window.getSelection().empty();
}
checkBoxClickHandler($cb, e.shiftKey);
}
}
}
});
function checkBoxClickHandler($checkBoxInput, wasShiftPressed) {
var isChecked = $checkBoxInput.prop("checked");
$checkBoxInput
.closest("table > tbody > tr")
.toggleClass("row-selected", isChecked);
if (
lastCheckedRow &&
lastCheckedRow.index() ==
$checkBoxInput.closest("table > tbody > tr").index()
) {
lastCheckedRow = null;
return;
}
if (!lastCheckedRow) {
lastCheckedRow = $checkBoxInput.closest("table > tbody > tr");
return;
}
if (wasShiftPressed) {
var start = $checkBoxInput.closest("table > tbody > tr").index();
var end = lastCheckedRow.index();
var $trs = $checkBoxInput
.closest("table")
.find("tbody > tr")
.slice(Math.min(start, end), Math.max(start, end) + 1);
if (
lastCheckedRow.find(".mof-cell-checkbox").prop("checked") == isChecked
) {
$trs.each(function () {
$(this).toggleClass("row-selected", isChecked);
$(this).find(".mof-cell-checkbox").prop("checked", isChecked);
});
} else {
$trs.each(function () {
$(this).toggleClass("row-selected", !isChecked);
$(this).find(".mof-cell-checkbox").prop("checked", !isChecked);
});
}
}
lastCheckedRow = $checkBoxInput.closest("table > tbody > tr");
}
.custom-checkbox {
padding-left: 0;
margin-top: -0.075rem;
margin-bottom: -0.075rem;
position: relative;
display: block;
min-height: 1.45rem;
}
.custom-control-input {
position: absolute;
z-index: -1;
opacity: 0;
}
.custom-checkbox .custom-control-label::before {
border-radius: 2px;
}
.custom-control-label::before {
position: absolute;
top: 0.1rem;
left: 0;
display: block;
width: 1.25rem;
height: 1.25rem;
pointer-events: none;
content: "";
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
background-color: #dee2e6;
}
.custom-checkbox .custom-control-input:checked ~ .custom-control-label::before {
background-color: #2196f3;
}
.custom-control-input:checked ~ .custom-control-label::before {
border: none;
}
.custom-control-input:checked ~ .custom-control-label::before {
color: #fff;
background-color: #2196f3;
}
.custom-checkbox .custom-control-input:checked ~ .custom-control-label::after {
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3E%3C/svg%3E");
}
.custom-control-label::after {
position: absolute;
top: 0.1rem;
left: 0;
display: block;
width: 1.25rem;
height: 1.25rem;
content: "";
background-repeat: no-repeat;
background-position: center center;
background-size: 50% 50%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<colgroup>
<col width="30px">
</colgroup>
<tbody>
<tr>
<td>
<div class="custom-checkbox custom-control">
<input class="custom-control-input mof-cell-checkbox mof-cell-checkbox-item form-control" id="0__checkBox" type="checkbox" value="true">
<label class="custom-control-label" for="0__checkBox"></label>
</div>
</td>
<td>1
</td>
</tr>
<tr>
<td>
<div class="custom-checkbox custom-control">
<input class="custom-control-input mof-cell-checkbox mof-cell-checkbox-item form-control" id="1__checkBox" type="checkbox" value="true">
<label class="custom-control-label" for="1__checkBox"></label>
</div>
</td>
<td>2
</td>
</tr>
<tr>
<td>
<div class="custom-checkbox custom-control">
<input class="custom-control-input mof-cell-checkbox mof-cell-checkbox-item form-control" id="2__checkBox" type="checkbox" value="true">
<label class="custom-control-label" for="2__checkBox"></label>
</div>
</td>
<td>3
</td>
</tr>
</tbody>
</table>
该演示适用于 Chrome,但不适用于 Firefox。
为什么会发生任何想法?谢谢!
shift+click 或 ctrl+click 标签在 Firefox 中不起作用。请参考他们重新打开的错误 If you shift+click or ctrl+click on a label for a checkbox, checkbox is not checked..
要使其正常工作,您需要在不使用 <label>
标记的情况下自定义您的复选框。
集成自定义复选框标签,效果很好。在最新的 Chrome 和 Firefox 中测试。
var lastCheckedRow = null;
$(document).on('click', '.mof-cell-checkbox', function handleRowCheckboxClick(e) {
var $t = $(e.target);
// check if target is checkbox, otherwise ignore event ( on label )
if ($t.is(":checkbox")) {
var $cb = $t.is(":checkbox") ? $t : $t.siblings("input.mof-cell-checkbox");
// if not disabled
if (!$cb.prop("disabled")) {
if ($cb.hasClass("mof-cell-checkbox")) {
if (window.getSelection().empty) {
// Chrome
window.getSelection().empty();
}
checkBoxClickHandler($cb, e.shiftKey);
}
}
}
});
function checkBoxClickHandler($checkBoxInput, wasShiftPressed) {
var isChecked = $checkBoxInput.prop("checked");
$checkBoxInput
.closest("table > tbody > tr")
.toggleClass("row-selected", isChecked);
if (
lastCheckedRow &&
lastCheckedRow.index() ==
$checkBoxInput.closest("table > tbody > tr").index()
) {
lastCheckedRow = null;
return;
}
if (!lastCheckedRow) {
lastCheckedRow = $checkBoxInput.closest("table > tbody > tr");
return;
}
if (wasShiftPressed) {
var start = $checkBoxInput.closest("table > tbody > tr").index();
var end = lastCheckedRow.index();
var $trs = $checkBoxInput
.closest("table")
.find("tbody > tr")
.slice(Math.min(start, end), Math.max(start, end) + 1);
if (
lastCheckedRow.find(".mof-cell-checkbox").prop("checked") == isChecked
) {
$trs.each(function () {
$(this).toggleClass("row-selected", isChecked);
$(this).find(".mof-cell-checkbox").prop("checked", isChecked);
});
} else {
$trs.each(function () {
$(this).toggleClass("row-selected", !isChecked);
$(this).find(".mof-cell-checkbox").prop("checked", !isChecked);
});
}
}
lastCheckedRow = $checkBoxInput.closest("table > tbody > tr");
}
.custom-checkbox {
width: 20px;
height: 20px;
position: relative;
}
.custom-checkbox > * {
position: absolute;
}
.custom-checkbox-visible {
width: 1.25rem;
height: 1.25rem;
margin: 2px;
background-color: #dee2e6;
}
.custom-checkbox > input {
z-index: 1;
opacity: 0;
left: 50%;
top: 50%;
transform: translatex(-50%) translatey(-50%);
display: block;
cursor: pointer;
width: 20px;
height: 20px;
background-color: #dee2e6;
}
.custom-checkbox > input:checked + .custom-checkbox-visible {
background: #2196f3;
background-color: #2196f3;
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: center center;
background-size: 50% 50%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<colgroup>
<col width="30px">
</colgroup>
<tbody>
<tr>
<td>
<div class="custom-checkbox custom-control">
<input class="custom-control-input mof-cell-checkbox mof-cell-checkbox-item form-control" id="0__checkBox" type="checkbox" value="true">
<div class="custom-checkbox-visible"></div>
</div>
</td>
<td>1
</td>
</tr>
<tr>
<td>
<div class="custom-checkbox custom-control">
<input class="custom-control-input mof-cell-checkbox mof-cell-checkbox-item form-control" id="1__checkBox" type="checkbox" value="true"/>
<div class="custom-checkbox-visible"></div>
</div>
</td>
<td>2
</td>
</tr>
<tr>
<td>
<div class="custom-checkbox custom-control">
<input class="custom-control-input mof-cell-checkbox mof-cell-checkbox-item form-control" id="2__checkBox" type="checkbox" value="true">
<div class="custom-checkbox-visible"></div>
</div>
</td>
<td>3
</td>
</tr>
</tbody>
</table>
我正在实施 table 行多 selection,它应该像这样工作: 单击第一行,然后按住 Shift 键并单击底行应该 select 之间的所有行。 我还使用自定义复选框,基本上是复选框 + 标签的组合。我也仅在 table 上利用事件传播和绑定事件处理程序。
问题是在 Firefox 上按住 Shift 键时事件不会从标签冒泡到输入。
var lastCheckedRow = null;
$("table").click(function handleRowCheckboxClick(e) {
var $t = $(e.target);
// check if target is checkbox, otherwise ignore event ( on label )
if ($t.is(":checkbox")) {
var $cb = $t.is(":checkbox") ? $t : $t.siblings("input.mof-cell-checkbox");
// if not disabled
if (!$cb.prop("disabled")) {
if ($cb.hasClass("mof-cell-checkbox")) {
if (window.getSelection().empty) {
// Chrome
window.getSelection().empty();
}
checkBoxClickHandler($cb, e.shiftKey);
}
}
}
});
function checkBoxClickHandler($checkBoxInput, wasShiftPressed) {
var isChecked = $checkBoxInput.prop("checked");
$checkBoxInput
.closest("table > tbody > tr")
.toggleClass("row-selected", isChecked);
if (
lastCheckedRow &&
lastCheckedRow.index() ==
$checkBoxInput.closest("table > tbody > tr").index()
) {
lastCheckedRow = null;
return;
}
if (!lastCheckedRow) {
lastCheckedRow = $checkBoxInput.closest("table > tbody > tr");
return;
}
if (wasShiftPressed) {
var start = $checkBoxInput.closest("table > tbody > tr").index();
var end = lastCheckedRow.index();
var $trs = $checkBoxInput
.closest("table")
.find("tbody > tr")
.slice(Math.min(start, end), Math.max(start, end) + 1);
if (
lastCheckedRow.find(".mof-cell-checkbox").prop("checked") == isChecked
) {
$trs.each(function () {
$(this).toggleClass("row-selected", isChecked);
$(this).find(".mof-cell-checkbox").prop("checked", isChecked);
});
} else {
$trs.each(function () {
$(this).toggleClass("row-selected", !isChecked);
$(this).find(".mof-cell-checkbox").prop("checked", !isChecked);
});
}
}
lastCheckedRow = $checkBoxInput.closest("table > tbody > tr");
}
.custom-checkbox {
padding-left: 0;
margin-top: -0.075rem;
margin-bottom: -0.075rem;
position: relative;
display: block;
min-height: 1.45rem;
}
.custom-control-input {
position: absolute;
z-index: -1;
opacity: 0;
}
.custom-checkbox .custom-control-label::before {
border-radius: 2px;
}
.custom-control-label::before {
position: absolute;
top: 0.1rem;
left: 0;
display: block;
width: 1.25rem;
height: 1.25rem;
pointer-events: none;
content: "";
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
background-color: #dee2e6;
}
.custom-checkbox .custom-control-input:checked ~ .custom-control-label::before {
background-color: #2196f3;
}
.custom-control-input:checked ~ .custom-control-label::before {
border: none;
}
.custom-control-input:checked ~ .custom-control-label::before {
color: #fff;
background-color: #2196f3;
}
.custom-checkbox .custom-control-input:checked ~ .custom-control-label::after {
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3E%3C/svg%3E");
}
.custom-control-label::after {
position: absolute;
top: 0.1rem;
left: 0;
display: block;
width: 1.25rem;
height: 1.25rem;
content: "";
background-repeat: no-repeat;
background-position: center center;
background-size: 50% 50%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<colgroup>
<col width="30px">
</colgroup>
<tbody>
<tr>
<td>
<div class="custom-checkbox custom-control">
<input class="custom-control-input mof-cell-checkbox mof-cell-checkbox-item form-control" id="0__checkBox" type="checkbox" value="true">
<label class="custom-control-label" for="0__checkBox"></label>
</div>
</td>
<td>1
</td>
</tr>
<tr>
<td>
<div class="custom-checkbox custom-control">
<input class="custom-control-input mof-cell-checkbox mof-cell-checkbox-item form-control" id="1__checkBox" type="checkbox" value="true">
<label class="custom-control-label" for="1__checkBox"></label>
</div>
</td>
<td>2
</td>
</tr>
<tr>
<td>
<div class="custom-checkbox custom-control">
<input class="custom-control-input mof-cell-checkbox mof-cell-checkbox-item form-control" id="2__checkBox" type="checkbox" value="true">
<label class="custom-control-label" for="2__checkBox"></label>
</div>
</td>
<td>3
</td>
</tr>
</tbody>
</table>
该演示适用于 Chrome,但不适用于 Firefox。 为什么会发生任何想法?谢谢!
shift+click 或 ctrl+click 标签在 Firefox 中不起作用。请参考他们重新打开的错误 If you shift+click or ctrl+click on a label for a checkbox, checkbox is not checked..
要使其正常工作,您需要在不使用 <label>
标记的情况下自定义您的复选框。
集成自定义复选框标签,效果很好。在最新的 Chrome 和 Firefox 中测试。
var lastCheckedRow = null;
$(document).on('click', '.mof-cell-checkbox', function handleRowCheckboxClick(e) {
var $t = $(e.target);
// check if target is checkbox, otherwise ignore event ( on label )
if ($t.is(":checkbox")) {
var $cb = $t.is(":checkbox") ? $t : $t.siblings("input.mof-cell-checkbox");
// if not disabled
if (!$cb.prop("disabled")) {
if ($cb.hasClass("mof-cell-checkbox")) {
if (window.getSelection().empty) {
// Chrome
window.getSelection().empty();
}
checkBoxClickHandler($cb, e.shiftKey);
}
}
}
});
function checkBoxClickHandler($checkBoxInput, wasShiftPressed) {
var isChecked = $checkBoxInput.prop("checked");
$checkBoxInput
.closest("table > tbody > tr")
.toggleClass("row-selected", isChecked);
if (
lastCheckedRow &&
lastCheckedRow.index() ==
$checkBoxInput.closest("table > tbody > tr").index()
) {
lastCheckedRow = null;
return;
}
if (!lastCheckedRow) {
lastCheckedRow = $checkBoxInput.closest("table > tbody > tr");
return;
}
if (wasShiftPressed) {
var start = $checkBoxInput.closest("table > tbody > tr").index();
var end = lastCheckedRow.index();
var $trs = $checkBoxInput
.closest("table")
.find("tbody > tr")
.slice(Math.min(start, end), Math.max(start, end) + 1);
if (
lastCheckedRow.find(".mof-cell-checkbox").prop("checked") == isChecked
) {
$trs.each(function () {
$(this).toggleClass("row-selected", isChecked);
$(this).find(".mof-cell-checkbox").prop("checked", isChecked);
});
} else {
$trs.each(function () {
$(this).toggleClass("row-selected", !isChecked);
$(this).find(".mof-cell-checkbox").prop("checked", !isChecked);
});
}
}
lastCheckedRow = $checkBoxInput.closest("table > tbody > tr");
}
.custom-checkbox {
width: 20px;
height: 20px;
position: relative;
}
.custom-checkbox > * {
position: absolute;
}
.custom-checkbox-visible {
width: 1.25rem;
height: 1.25rem;
margin: 2px;
background-color: #dee2e6;
}
.custom-checkbox > input {
z-index: 1;
opacity: 0;
left: 50%;
top: 50%;
transform: translatex(-50%) translatey(-50%);
display: block;
cursor: pointer;
width: 20px;
height: 20px;
background-color: #dee2e6;
}
.custom-checkbox > input:checked + .custom-checkbox-visible {
background: #2196f3;
background-color: #2196f3;
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: center center;
background-size: 50% 50%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<colgroup>
<col width="30px">
</colgroup>
<tbody>
<tr>
<td>
<div class="custom-checkbox custom-control">
<input class="custom-control-input mof-cell-checkbox mof-cell-checkbox-item form-control" id="0__checkBox" type="checkbox" value="true">
<div class="custom-checkbox-visible"></div>
</div>
</td>
<td>1
</td>
</tr>
<tr>
<td>
<div class="custom-checkbox custom-control">
<input class="custom-control-input mof-cell-checkbox mof-cell-checkbox-item form-control" id="1__checkBox" type="checkbox" value="true"/>
<div class="custom-checkbox-visible"></div>
</div>
</td>
<td>2
</td>
</tr>
<tr>
<td>
<div class="custom-checkbox custom-control">
<input class="custom-control-input mof-cell-checkbox mof-cell-checkbox-item form-control" id="2__checkBox" type="checkbox" value="true">
<div class="custom-checkbox-visible"></div>
</div>
</td>
<td>3
</td>
</tr>
</tbody>
</table>