我创建了一个简单的模式,当您在内容区域之外单击时,可以将其关闭。这是设计使然,但具有意外的副作用。如果我单击内容区域中的任何位置(例如,在文本字段中)并将鼠标拖动到内容区域之外,然后释放单击,它将关闭模式。我经常有这样做的习惯,并且可以看到普通用户将其视为错误的原因,因此我试图在发布前先加以解决。
var modal = document.getElementById("modal-container");
function openModal() { modal.classList.add("active"); }
function closeModal() { modal.classList.remove("active"); }
window.onclick = function (event) {
if (event.target == modal)
closeModal();
}
html, body {
margin: 0;
height: 100%;
}
.modal-container.active { top: 0; }
.modal-container {
position: absolute;
top: -500vh;
left: 0;
width: 100%;
height: 100%;
display: grid;
background-color: rgba(0, 0, 0, 0.75);
}
.modal-content {
height: 50%;
width: 50%;
margin: auto;
background-color: #fff;
display: flex;
align-items: center;
justify-content: center;
}
<button onclick="openModal();">Open the Modal</button>
<div id="modal-container" class="modal-container">
<div class="modal-content">
<input type="text" />
</div>
</div>
要正确测试:
现在应该关闭模式。
有没有一种方法可以在不跟踪鼠标坐标的情况下防止这种情况发生?
onmousedown
而不是点击?
答案 0 :(得分:1)
在以有效原因回答自己之前(如问题编辑中所述)- 考虑:
onmousedown
可能并不总是所需的UX。 (有时,有经验的用户可以撤消未注册为click
的mousedown,他们故意将鼠标移到mouseup事件的另一个元素上,只是保留当前状态。)Element.addEventListener()
将侦听器分配给具有data-modal
属性的任何按钮data-modal="#some_modal_id"
if (evt.target !== this) return;
const el_dataModal = document.querySelectorAll('[data-modal]');
function toggleModal(evt) {
if (evt.target !== this) return; // Do nothing if the element that propagated the event is not the `this` button which has the event attached.
const id = evt.currentTarget.getAttribute('data-modal');
document.querySelector(id).classList.toggle('active');
}
el_dataModal.forEach(el => el.addEventListener('click', toggleModal));
html, body {
margin: 0;
height: 100%;
}
.modal-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: grid;
background-color: rgba(0, 0, 0, 0.75);
opacity: 0; /* ADDED */
transition: 0.26s; /* ADDED */
visibility: hidden; /* ADDED */
}
.modal-container.active {
opacity: 1; /* ADDED */
visibility: visible; /* ADDED */
}
.modal-content {
height: 50%;
width: 50%;
margin: auto;
background-color: #fff;
display: flex;
align-items: center;
justify-content: center;
}
<button data-modal="#modal-container">Open the Modal</button>
<div id="modal-container" class="modal-container" data-modal="#modal-container">
<div class="modal-content">
<input type="text">
<br><br>
<button data-modal="#modal-container">CLOSE MODAL TEST</button>
</div>
</div>
答案 1 :(得分:1)
这是工作示例。想一想,它符合您的需求))
var clickTarget = null;
var modal = document.getElementById("modal-container");
function openModal() {
modal.classList.add("active");
document.body.addEventListener('mousedown', onModalMouseDown, false);
document.body.addEventListener('mouseup', onModalMouseUp, false);
}
function closeModal() {
modal.classList.remove("active");
document.body.removeEventListener('mousedown', onModalMouseDown);
document.body.removeEventListener('mouseup', onModalMouseUp);
}
function onModalMouseDown(event) {
clickTarget = event.target;
}
function onModalMouseUp() {
if (clickTarget === modal) {
closeModal();
}
}
html, body {
margin: 0;
height: 100%;
}
.modal-container.active { top: 0; }
.modal-container {
position: absolute;
top: -500vh;
left: 0;
width: 100%;
height: 100%;
display: grid;
background-color: rgba(0, 0, 0, 0.75);
}
.modal-content {
height: 50%;
width: 50%;
margin: auto;
background-color: #fff;
display: flex;
align-items: center;
justify-content: center;
}
.modal-trigger-btn {
margin: 20px;
font-size: 16px;
}
<button onmousedown="openModal();" class="modal-trigger-btn">Open the Modal</button>
<div id="modal-container" class="modal-container">
<div class="modal-content">
<input type="text" placeholder="Start to drag outside..."/>
</div>
</div>
答案 2 :(得分:1)
要亲自回答这个问题,我考虑了onclick
事件的工作方式。单击的定义是按下并释放鼠标按钮。必须同时发生这两个点才能引发onclick
事件(尽管在之前或之后的某个时刻没有其他事件发生,您实际上无法拥有一个事件。)
我没有在下面的执行路径上找到任何真实的文档,因此它是基于逻辑推论的。 如果您对此有任何文档,请在评论中链接它,以便我进行审阅并为以后的读者调整答案。
用户按下鼠标按钮。
引发
onmousedown
事件。用户释放鼠标按钮。
引发
onmouseup
事件。引发
onmouseclick
事件。
我确实编写了一个测试来验证这些结果:
var ePath = document.getElementById("executionPath");
document.body.onmousedown = function (event) { ePath.innerHTML += "On Mouse Down<br>"; }
document.body.onmouseup = function (event) { ePath.innerHTML += "On Mouse Up<br>"; }
document.body.onclick = function (event) { ePath.innerHTML += "On Click<br>"; }
html, body { height: 100%; }
<p id="executionPath">Click the Window<br></p>
我认为,意外行为是由于为target
事件设置了onclick
而引起的。我认为设置此设置时存在三种可能性(从最大到最小),我无法确认或否认:
target
。target
在按下鼠标按钮时设置,然后在释放鼠标按钮时再次设置。target
是连续设置的。经过分析,我确定对于我的情况onmousedown
可能是最佳解决方案。这将确保仅当用户在内容区域之外启动单击时,模式才会关闭。下面展示了一种与onmouseup
结合使用以确保仍然实现完整点击的好方法。尽管就我而言,我可以简单地使用onmousedown
:
var initialTarget = null;
var modal = document.getElementById("modal-container");
function openModal() { modal.classList.add("active"); }
function closeModal() { modal.classList.remove("active"); }
window.onmousedown = function (event) { initialTarget = event.target; }
window.onmouseup = function (event) {
if (event.target == initialTarget)
closeModal();
}
html, body { height: 100%; }
.modal-container.active { top: 0; }
.modal-container {
position: absolute;
top: -500vh;
left: 0;
width: 100%;
height: 100%;
display: grid;
background-color: rgba(0, 0, 0, 0.75);
}
.modal-content {
height: 50%;
width: 50%;
margin: auto;
background-color: #fff;
display: flex;
align-items: center;
justify-content: center;
}
<button onclick="openModal();">Open the Modal</button>
<div id="modal-container" class="modal-container">
<div class="modal-content">
<input type="text" />
</div>
</div>
上面的代码段可确保在关闭模式之前先在模式容器上单击并结束。如果用户不小心在内容区域之外发起了单击并将鼠标拖到内容区域以完成单击,则这可以防止模式关闭。反之亦然,只有在模式容器上启动并完成点击后,模式才会关闭。
我唯一不知道的是设置了target
的{{1}}时,这可能在正确解释此问题的根本原因上更为重要,请随时让我知道!