实现可拖拽、可关闭的弹窗效果需要借助JavaScript和CSS的帮助。主要的实现步骤如下:
先定义一个弹窗的HTML结构,包括一个模态框、一个标题、一个内容和两个关闭按钮:
<div class="modal">
<div class="modal-header">
<h3 class="modal-title">弹窗标题</h3>
<button class="btn-close">×</button>
</div>
<div class="modal-body">
<p>弹窗内容</p>
</div>
<button class="btn-close btn-close-modal">×</button>
</div>
其中,.modal
是弹窗的容器,.modal-header
是弹窗标题的容器,.modal-title
是弹窗标题,.btn-close
是用于关闭弹窗的按钮,.modal-body
是弹窗内容的容器,.btn-close-modal
是关闭弹窗按钮的一部分,点击弹窗内容部分也可以关闭弹窗。
CSS样式主要是用于定义弹窗的基本样式、位置和动画效果。
.modal {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border: 1px solid #ccc;
background-color: #fff;
box-shadow: 0 0 10px #aaa;
z-index: 100;
display: none;
}
.modal-header {
padding: 10px;
background-color: #eee;
cursor: move;
}
.modal-body {
padding: 10px;
}
.btn-close {
position: absolute;
top: 5px;
right: 10px;
font-size: 24px;
cursor: pointer;
}
.btn-close:hover {
color: #f00;
}
.btn-close-modal {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
cursor: default;
}
.fade-in {
animation: fade-in 0.3s;
}
.fade-out {
animation: fade-out 0.3s;
}
@keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
其中,.modal
的position
设置为绝对定位,top
和left
设置为50%,以便将弹窗居中显示。transform
属性用于偏移弹窗,使其相对于中心点水平和垂直居中。
.modal-header
中,padding
设置为10像素,background-color
设置为灰色,cursor
设置为move
,以便实现拖动弹窗的效果。
.btn-close
中,position
设置为绝对定位,top
和right
设置为5像素和10像素,使关闭按钮出现在右上角;font-size
设置为24像素,使关闭按钮更加显眼;cursor
设置为pointer
,使鼠标光标变成小手形状。
.fade-in
和.fade-out
是用于实现弹窗的动画效果,fade-in
代表淡入,fade-out
代表淡出。在动画过程中,会逐渐改变弹窗的透明度(opacity
)。
先定义一个Modal
类,用于创建一个新的弹窗。该类的构造函数接受一个表示弹窗标题的字符串和一个表示弹窗内容的字符串。
class Modal {
constructor(title, content) {
this.title = title;
this.content = content;
this.modal = null;
this.init();
}
init() {
this.createModal();
this.addEventListeners();
}
createModal() {
this.modal = document.createElement("div");
this.modal.classList.add("modal");
const header = document.createElement("div");
header.classList.add("modal-header");
const title = document.createElement("h3");
title.classList.add("modal-title");
title.textContent = this.title;
const btnClose = document.createElement("button");
btnClose.classList.add("btn-close");
btnClose.innerHTML = "×";
header.appendChild(title);
header.appendChild(btnClose);
const body = document.createElement("div");
body.classList.add("modal-body");
body.innerHTML = this.content;
this.modal.appendChild(header);
this.modal.appendChild(body);
document.body.appendChild(this.modal);
}
...
}
其中,createModal()
方法用于动态创建弹窗。通过document.createElement()
方法创建了若干个DOM元素,再通过appendChild()
方法组装起来,最终添加到document.body
中。
若要弹窗显示需要先调用一个show()
方法,弹窗会通过JS的类名添加类名,从而达到一个动态的效果
show() {
this.modal.classList.add("fade-in");
this.modal.style.display = "block";
document.body.style.overflow = "hidden";
}
当弹窗的关闭按钮或者内容区域被点击时,可以通过调用hide()
方法关闭弹窗。这个方法跟show()
方法加入的类名相似,只是添加的是类名为fade-out
,表示关闭的过程
hide() {
this.modal.classList.add("fade-out");
setTimeout(() => {
this.modal.style.display = "none";
this.modal.classList.remove("fade-in", "fade-out");
document.body.style.overflow = "auto";
}, 300);
}
在Modal
类中添加一个名为dragElement
的方法,用于实现弹窗的拖动。在该方法内,需要操控mousedown
、mouseup
、mousemove
等事件,从而实现拖动弹窗。
dragElement() {
const header = this.modal.querySelector(".modal-header");
let x = 0;
let y = 0;
header.addEventListener("mousedown", startDrag);
function startDrag(e) {
e.preventDefault();
x = e.clientX;
y = e.clientY;
document.addEventListener("mousemove", onDrag);
document.addEventListener("mouseup", stopDrag);
}
function onDrag(e) {
e.preventDefault();
const deltaX = e.clientX - x;
const deltaY = e.clientY - y;
const modalRect = this.modal.getBoundingClientRect();
this.modal.style.top = `${modalRect.top + deltaY}px`;
this.modal.style.left = `${modalRect.left + deltaX}px`;
x = e.clientX;
y = e.clientY;
}
function stopDrag() {
document.removeEventListener("mousemove", onDrag);
document.removeEventListener("mouseup", stopDrag);
}
}
其中,mousedown
事件监听在标题栏上,当事件触发时,事件回调函数startDrag
会记录鼠标按下时的坐标。mousemove
事件监听在整个文档上,它的回调函数onDrag
会计算出鼠标和标题栏的距离差值,并将其添加到弹窗的top
和left
样式属性上,从而实现弹窗的拖动效果。
示例一:自定义消息弹窗
// HTML结构
<div id="alert-modal" class="modal" style="display: none;">
<div class="modal-header">
<h4 class="modal-title">提示</h4>
<button class="btn-close">×</button>
</div>
<div class="modal-body">
<p id="alert-message"></p>
</div>
</div>
// CSS样式
.modal {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border-radius: 8px;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.5);
background-color: #fff;
width: 400px;
z-index: 100;
display: none;
}
.modal .modal-header {
padding: 15px;
border-bottom: 1px solid #eee;
text-align: center;
font-size: 20px;
font-weight: bold;
position: relative;
}
.modal .modal-header .btn-close {
position: absolute;
top: 5px;
right: 5px;
font-size: 20px;
cursor: pointer;
outline: none;
border: none;
background-color: transparent;
}
.modal .modal-body {
padding: 15px;
}
// JS代码
class AlertModal {
constructor(message) {
this.message = message;
this.init();
}
init() {
this.alertModal = document.getElementById("alert-modal");
this.alertMessage = document.getElementById("alert-message");
this.alertMessage.textContent = this.message;
this.btnClose = this.alertModal.querySelector(".btn-close");
this.addEventListeners();
}
addEventListeners() {
this.btnClose.addEventListener("click", this.hide.bind(this));
this.alertModal.addEventListener("click", this.handleModalClick.bind(this));
window.addEventListener("keyup", this.handleKeyUp.bind(this));
}
show() {
this.alertModal.classList.add("fade-in");
this.alertModal.style.display = "block";
document.body.style.overflow = "hidden";
}
hide() {
this.alertModal.classList.add("fade-out");
setTimeout(() => {
this.alertModal.style.display = "none";
this.alertModal.classList.remove("fade-in", "fade-out");
document.body.style.overflow = "auto";
}, 300);
}
handleModalClick(e) {
if (e.target === this.alertModal) {
this.hide();
}
}
handleKeyUp(e) {
if (e.key === "Escape") {
this.hide();
}
}
}
const btnAlert = document.getElementById("btn-alert");
btnAlert.addEventListener("click", handleAlertClick);
function handleAlertClick() {
const message = "您好,欢迎访问该网站!";
const alertModal = new AlertModal(message);
alertModal.show();
}
示例二:加载中的遮罩弹窗
// HTML结构
<div id="loading-modal" class="modal" style="display: none;">
<div class="modal-body">
<div class="loader"></div>
</div>
</div>
// CSS样式
.modal .modal-body {
padding: 0;
background-color: transparent;
}
.modal .modal-body .loader {
border: 16px solid #f3f3f3; /* Light grey */
border-top: 16px solid #3498db; /* Blue */
border-radius: 50%;
width: 120px;
height: 120px;
animation: spin 2s linear infinite;
margin: auto;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
// JS代码
class LoadingModal {
constructor() {
this.init();
}
init() {
this.loadingModal = document.getElementById("loading-modal");
}
show() {
this.loadingModal.style.display = "block";
}
hide() {
this.loadingModal.style.display = "none";
}
}
const btnLoading = document.getElementById("btn-loading");
btnLoading.addEventListener("click", handleLoadingClick);
function handleLoadingClick() {
const loadingModal = new LoadingModal();
loadingModal.show();
setTimeout(function () {
loadingModal.hide();
}, 2000);
}
本文链接:http://task.lmcjl.com/news/8563.html