fix: 防止拖选内容误关闭弹窗 (#56)
This commit is contained in:
@@ -112,3 +112,24 @@ func TestMainPagesReturnOK(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 公共弹窗不能只看 click.target 关闭:从密码框拖选到遮罩松开时,
|
||||||
|
// 浏览器会把 click 目标合成为遮罩。这个静态守卫确保 #56 的手势起点判断不被删掉;
|
||||||
|
// 真实指针行为另用 Chrome 回归验证。
|
||||||
|
func TestModalBackdropRequiresPointerStart(t *testing.T) {
|
||||||
|
js, err := staticFS.ReadFile("static/js/app.js")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("读取公共 JavaScript 失败: %v", err)
|
||||||
|
}
|
||||||
|
source := string(js)
|
||||||
|
for _, required := range []string{
|
||||||
|
`addEventListener("pointerdown"`,
|
||||||
|
`pointerStartedOnBackdrop = e.target === modal`,
|
||||||
|
`e.target === modal && pointerStartedOnBackdrop`,
|
||||||
|
`addEventListener("pointercancel"`,
|
||||||
|
} {
|
||||||
|
if !strings.Contains(source, required) {
|
||||||
|
t.Errorf("公共弹窗缺少拖选防误关闭守卫 %q", required)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+15
-2
@@ -164,9 +164,22 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
document.querySelectorAll(".modal-backdrop").forEach(function (modal) {
|
document.querySelectorAll(".modal-backdrop").forEach(function (modal) {
|
||||||
/* 关闭:叉、取消按钮,以及点弹窗外面的灰底 */
|
/* 关闭:叉、取消按钮,以及真正点弹窗外面的灰底。
|
||||||
|
|
||||||
|
不能只看 click 的 target:从输入框按下拖选到灰底松开时,浏览器会把
|
||||||
|
合成的 click 目标设成灰底。只有手势也从灰底开始,才算有意关闭。 */
|
||||||
|
var pointerStartedOnBackdrop = false;
|
||||||
|
modal.addEventListener("pointerdown", function (e) {
|
||||||
|
pointerStartedOnBackdrop = e.target === modal;
|
||||||
|
});
|
||||||
|
modal.addEventListener("pointercancel", function () {
|
||||||
|
pointerStartedOnBackdrop = false;
|
||||||
|
});
|
||||||
modal.addEventListener("click", function (e) {
|
modal.addEventListener("click", function (e) {
|
||||||
if (e.target === modal || e.target.closest("[data-modal-close]")) {
|
var clickedCloseButton = e.target.closest("[data-modal-close]");
|
||||||
|
var clickedBackdrop = e.target === modal && pointerStartedOnBackdrop;
|
||||||
|
pointerStartedOnBackdrop = false;
|
||||||
|
if (clickedBackdrop || clickedCloseButton) {
|
||||||
closeModal(modal);
|
closeModal(modal);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -37,6 +37,10 @@
|
|||||||
|
|
||||||
`[必须]` 页面在 1366×768 上可用。列多了让表格**横向滚动**,不要压缩列宽把字挤成两行。
|
`[必须]` 页面在 1366×768 上可用。列多了让表格**横向滚动**,不要压缩列宽把字挤成两行。
|
||||||
|
|
||||||
|
`[必须]` 公共弹窗可以通过关闭按钮、取消按钮、Esc 或直接点击灰色遮罩关闭;
|
||||||
|
但从输入框或弹窗内容开始拖选、在遮罩上松开时不得关闭。遮罩关闭逻辑必须同时确认
|
||||||
|
指针按下和最终点击都发生在遮罩本身,避免误丢用户尚未提交的输入。
|
||||||
|
|
||||||
## 3. 表格通用规则
|
## 3. 表格通用规则
|
||||||
|
|
||||||
- `[必须]` 第一列是勾选框,表头有全选。
|
- `[必须]` 第一列是勾选框,表头有全选。
|
||||||
|
|||||||
Reference in New Issue
Block a user