关键词

JS实现可拖曳、可关闭的弹窗效果

实现可拖拽、可关闭的弹窗效果需要借助JavaScript和CSS的帮助。主要的实现步骤如下:

步骤一:HTML结构

先定义一个弹窗的HTML结构,包括一个模态框、一个标题、一个内容和两个关闭按钮:

<div class="modal">
  <div class="modal-header">
    <h3 class="modal-title">弹窗标题</h3>
    <button class="btn-close">&times;</button>
  </div>
  <div class="modal-body">
    <p>弹窗内容</p>
  </div>
  <button class="btn-close btn-close-modal">&times;</button>
</div>

其中,.modal是弹窗的容器,.modal-header是弹窗标题的容器,.modal-title是弹窗标题,.btn-close是用于关闭弹窗的按钮,.modal-body是弹窗内容的容器,.btn-close-modal是关闭弹窗按钮的一部分,点击弹窗内容部分也可以关闭弹窗。

步骤二:CSS样式

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;
  }
}

其中,.modalposition设置为绝对定位,topleft设置为50%,以便将弹窗居中显示。transform属性用于偏移弹窗,使其相对于中心点水平和垂直居中。

.modal-header中,padding设置为10像素,background-color设置为灰色,cursor设置为move,以便实现拖动弹窗的效果。

.btn-close中,position设置为绝对定位,topright设置为5像素和10像素,使关闭按钮出现在右上角;font-size设置为24像素,使关闭按钮更加显眼;cursor设置为pointer,使鼠标光标变成小手形状。

.fade-in.fade-out是用于实现弹窗的动画效果,fade-in代表淡入,fade-out代表淡出。在动画过程中,会逐渐改变弹窗的透明度(opacity)。

步骤三:JS实现

创建弹窗

先定义一个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 = "&times;";

    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的方法,用于实现弹窗的拖动。在该方法内,需要操控mousedownmouseupmousemove等事件,从而实现拖动弹窗。

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会计算出鼠标和标题栏的距离差值,并将其添加到弹窗的topleft样式属性上,从而实现弹窗的拖动效果。

示例一:自定义消息弹窗

// HTML结构
<div id="alert-modal" class="modal" style="display: none;">
  <div class="modal-header">
    <h4 class="modal-title">提示</h4>
    <button class="btn-close">&times;</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

展开阅读全文