如何故意冻结浏览器窗口(如警报,确认和提示)?



有没有办法像alertconfirmprompt(简而言之:"acp")那样故意冻结浏览器窗口?

我想显示一个带有自定义 css 的模式对话框,而不是"acp"的本机弹出窗口,但也希望能够冻结浏览器,直到我像"acp"一样获得用户反馈。

但是,伙计,为什么呢?这是不好的做法(呃,我必须投反对票)!
那么当它是不好的做法时 - 那么为什么"acp"实际上提供这种同步行为?因为在某些特定情况下,它正是适合适当用户体验的正确工具。那些原生模态看起来确实很丑,同时也非常有限。

这只是一个快速而肮脏的例子,在用户提供反馈之前冻结浏览器是完全可以的。假设我们有一个带有input[type="reset"]元素的form。因此,在我们真正让form重置之前,我们会问用户:"您确定要重置(数据将丢失)吗?

如果我对原生模态外观没问题(我不是),我可以做:

document.querySelector('form').addEventListener(
'reset', e => confirm('Are you sure you want to reset (data will be lost)?') || e.preventDefault()
);
<form>
<input placeholder="type something, reset and cancel to keep input value" style="width:100%">
<input type="reset">
</form>

所以"每个人"都应该同意(编辑:或者至少有人可以)这不是坏做法,对吧?
但是我们如何通过自定义样式的模态/对话框/弹出窗口来实现相同的效果?
我当然不是要求HTML/CSS部分,而是要求通过JavaScript冻结浏览器窗口的能力!

老实说,我实际上预计会对此投一些反对票,但也许有一个杀手 JavaScript 忍者,他们有一个特殊的黑客来使其成为可能......

您不能像本机对话框那样冻结浏览器应用程序。这些不是用JavaScript构建的,它们是用本机代码构建的,可以以任何方式影响浏览器应用程序。禁止 JavaScript 以这种方式影响客户端应用程序。

但是,您可以在浏览器窗口中冻结与页面内容的交互。

只需在页面上方放置一个大小为div的窗口,并固定定位即可。这将阻止用户与主页(其后面)上的任何内容进行交互。然后,在此之上显示您的模式对话框。当用户清除模态时,隐藏它和窗口大小的div,从而使主页再次交互。

let modal = document.querySelector(".modal");
let pageCover = document.querySelector(".pageCover");
let main = document.querySelector("main");        
document.getElementById("open").addEventListener("click", function(){
modal.classList.remove("hidden");
pageCover.classList.remove("hidden"); 
main.addEventListener("focus", preventFocus);
});
document.getElementById("close").addEventListener("click", function(){
modal.classList.add("hidden");
pageCover.classList.add("hidden"); 
main.removeEventListener("focus", preventFocus);
});
function preventFocus (evt){
evt.preventDefault();
}
.hidden { display:none; }
.pageCover { 
position:fixed; 
z-index:10; 
background-color:rgba(0,0,0,.25); 
width:100vw; 
height:100vh; 
top:0; 
left:0;
}
.modal { 
position:absolute; 
z-index:100; 
background-color:aliceblue;
border:2px double grey;
width:200px; 
height:200px; 
top:30%; 
left:30%; 
text-align:center;
}
.modalTitle {
margin:0;
background-color:#00a;
color:#ff0;
padding:5px;
font-weight:bold;
font-size:1.1em;
}
#close { 
background-color:#800080;
color:#ff0;
border:1px solid #e0e0e0;
padding:5px 10px;
}
#close:hover { background-color:#c000c0; }
<main>
<h1>This is some page content</h1>
<p>And more content</p>
<button id="open">Click Me To Show Modal</button>
<div>More content</div>
</main>
<div class="hidden pageCover"></div>
<div class="hidden modal">
<div class="modalTitle">Modal Title Here</div>
<p>
Now, you can only interact with the contents of this "modal".
</p>
<button id="close" >Close</button>
</div>

您可以将除弹出窗口之外的所有内容都放在div 中。然后,您可以通过 css 打开/关闭指针事件。

div 中的所有内容将不再可交互。这将呈现冻结浏览器窗口的外观。

.freeze { pointer-events: none; }

注意:向元素添加pointer-events时,这也会影响所有子元素,因此将其放在正文上也会锁定弹出窗口。

关闭弹出窗口后,我们可以从div 中删除freeze类,一切将重新开始工作。

const content = document.getElementById('content')
const overlay = document.querySelector('.overlay')
const a = document.querySelector('.open-overlay')
const close = document.querySelector('.overlay .close')
// Open a popup and freeze the browser content
a.addEventListener('click', e => {
e.preventDefault()
content.classList.add('freeze')
overlay.classList.remove('hidden')
})
// Close the popup window and unfreeze the browser content
close.addEventListener('click', e => {
e.preventDefault()
content.classList.remove('freeze')
overlay.classList.add('hidden')
})
.freeze { pointer-events: none; }
.hidden { display: none; }
.overlay {
position: fixed;
z-index: 100;
padding: 20px;
background: white;
border: solid 1px #ccc;
width: 300px;
top: 20px;
left: 0;
right: 0;
margin: auto;
}
<div class="overlay hidden">
<h1>Overlay</h1>
<a href="" class="close">Close</a>
</div>
<div id="content">
<a href="" class="open-overlay">Open Overlay</a>
<p>Hello World</p>
<p>Hello World</p>
<p>Hello World</p>
<p>Hello World</p>
<p>Hello World</p>
<form>
<input type="text">
</form>
</div>

最新更新