带你一键生成一个可拖拽可改变大小的弹窗

2,762 阅读4分钟

「这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战

前言

前两天有一个需求,就是需要实现一个可以随便拖拽的页面弹窗,网上关于这方面的插件不少,但是大部分都要依赖于jQuery,并不想使用jQuery,想找一个没有依赖的组件库,但是并没有找到,所以自己手撸了一个,之后做出了优化,把生成的过程全部交给js来实现,只需要引入一段代码,就可以一键生成一个窗口。

简单使用示例

我是用一个类来自动生成了这个弹窗,在js中引入这个类,并且实例化它,传入我设定好的必要参数和可选参数,就可以生成一个弹窗,现在可选的设置暂时不多,只是简单实现了这个想法:

import { Drag } from "./Drag.js";
const drag = new Drag({
  id: "drag", //填充的元素的id
  title: "我是一个窗口",  //窗口的标题
  content: `
  ① 窗口可以拖动;<br>
  ② 窗口可以通过八个方向改变大小;<br>
  ④ 限制窗口最小宽度/高度。`,  //窗口的内容
});

这样就可以在页面实例化出来一个弹窗:

image.png 接下来来讲讲要怎么实现这样一键生成一个弹窗

定义类来动态生成元素

首先我们可以用一个类来描述我们的这个弹窗,他可以接收一个用户的自定义参数,是个对象,里面可以包含很多我们设定的可供用户自定义的参数,比如说上面的title和content就是设定出来的可以供给用户设定的参数。

export class Drag {
  constructor(data) {
    this.data = data;
  }

然后,在这个类实例化的时候,应该要去调用一个方法,这个方法需要把我们需要用到的页面元素都生成出来,方便我们后面绑定点击或者拖拽事件

export class Drag {
  constructor(data) {
    this.data = data;
    this._newDrag(this.data);
  }
  _newDrag(data) {
    this._creatElm(data); //根据配置创建窗口);
  }
}

在_creatElm()这个函数中,我们能拿到用户的自定义设置,这时候你在创建元素的时候,就可以看是否要允许自定义,比方说一个盒子正常是可以上下左右和四个角拖动缩小放大,那就可以你喜欢的设定添加限制,比如限制只能通过四个角落缩小放大,那么我们就不用去添加四个边框和他们对应的事件。

然后正常创建的弹窗,需要包含标题,内容,四边和四角的拖拽响应元素:

image.png

然后在css中对对应的类名添加样式,我们就能够动态的生成一个窗口,只是还没有添加事件。

四边和四角拖拽事件

首先,我们要用到js的onmousedown事件,将它绑在一个元素上面,就能够监听鼠标在这个元素上点下去之后执行的逻辑,并且,在这个事件中,还会有着另外两个事件,分别是document.onmousemovedocument.onmouseup 它们两分别是监听鼠标点击之后移动和鼠标松开的事件。

再者,就是这三个方法浏览器都会传给我们一个参数event:

image.png 它里面包含了当前元素相对于浏览器的边距,然后根据这些方法和参数,我们就可以通过在移动事件触发的时候,不断地去获取当前相对改变的位置然后去动态的改变窗口的大小:

var event = event || window.event;
var iL = event.clientX - disX;
var iT = event.clientY - disY;
var maxW =
  document.documentElement.clientWidth - oParent.offsetLeft - 2;
var maxH =
  document.documentElement.clientHeight - oParent.offsetTop - 2;
var iW = isLeft ? iParentWidth - iL : handle.offsetWidth + iL;
var iH = isTop ? iParentHeight - iT : handle.offsetHeight + iT;
isLeft && (oParent.style.left = iParentLeft + iL + "px");
isTop && (oParent.style.top = iParentTop + iT + "px");
iW < this.dragMinWidth && (iW = this.dragMinWidth);
iW > maxW && (iW = maxW);
lockX || (oParent.style.width = iW + "px");
iH < this.dragMinHeight && (iH = this.dragMinHeight);
iH > maxH && (iH = maxH);
lockY || (oParent.style.height = iH + "px");

组合点击事件到类当中

还有一个拖动标题实现移动的拖动函数,这里和上面的类似就不在做太多的讲述,在实现玩所有的函数之后,我们就应该在类当中去实现它们:

 _newDrag(data) {
    try {
      this._creatElm(data); //根据配置创建窗口
      this._changeSize(data); //绑定四角和四边
      this._dragElm(data); //绑定拖拽方法
    } catch (error) {
      console.log(error);
    }
  }

通过在实例化过程中会调用的_newDrag这个方法,然后运行我们的所有的绑定函数。

总结

这次实现了一个能够通过绑定一个元素就能够自动在其中实例化出来一个弹窗的类,虽然它其中的方法还没有特别的完善,但是要开放更多的配置可以提供给用户去配置,这样才能实现一个比较理想的弹窗组件,