20
2024
09

js窗口组件

项目中可能会遇到需要弹出一个窗口。类似于windows系统的窗口,能够拖动,能够调整尺寸,能够关闭。

老版本的组件库有这个组件,新的组件库,没找到。

比如easyui中的window组件。


也可以自己写一个。自己写的好处是可以根据业务需求任意调整。

先看一下效果


代码如下(windows.js):

依赖另外一个自己写的拖拽库(dragUtil.js

function Windows() {

  this.ele = document.getElementById("windows");

  this.templete = document.getElementById("winPop");

  this.children = [];

}

Windows.prototype.add = function(title, x, y, w, h) {

  var win = new HWindow(this, title, x, y, w, h, this.children.length);

  this.children.push(win);

  this.ele.appendChild(win.ele);

  return win;

}


Windows.prototype.closeAll = function() {

  const arr = this.children.concat();

  for(var i = 0; i < arr.length; i++) {

    arr[i].remove();

  }

}


function HWindow(manager, title, x, y, w, h, z) {

  var ele = manager.templete.content.children[0].cloneNode(true);

  this.manager = manager;

  this.ele = ele;

  ele.style.zIndex = z;

  this.x = x;

  this.y = y;

  this.w = w;

  this.h = h;

  this.isMin = true;

  this.curDir = 0;

  this.DIR = {

    LEFT: 1,

    TOP: 2,

    RIGHT: 4,

    BOTOOM: 8

  };

  this.mh = 30;

  this.mw = 30;

  this.onResize = function(){};

  this.onMove = function(){};

  this.onClose = function(){};

  this.close = this.remove;


  this.eleHead = this.ele.querySelector(".win-pop-head");

  this.eleTitle = this.ele.querySelector(".win-pop-title");

  this.eleMin = this.ele.querySelector(".win-pop-min");

  this.eleMax = this.ele.querySelector(".win-pop-max");

  this.eleClose = this.ele.querySelector(".win-pop-close");

  this.eleBody = this.ele.querySelector(".win-pop-body");

  this.eleResize = this.ele.querySelector(".win-resize-con");


  this.eleTitle.innerHTML = title;

  this.ele.onclick = this.top.bind(this);

  this.eleClose.onclick = this.remove.bind(this);

  this.eleMin.onclick = this.eleMax.onclick = this.toggleMin.bind(this);

  this.toggleMin();


  this.dragUtil = new DragUtil(this.eleHead, this.onMouseDown.bind(this), this.onMouseMove.bind(this), this.onMouseUp.bind(this), false, true, false);

  this.resizeUtil = new DragUtil(this.eleResize, this.onResizeDown.bind(this), this.onResizeMove.bind(this), this.onResizeUp.bind(this), false, true, false);

}

HWindow.prototype.onMouseDown = function(id, x, y, e) {


}

HWindow.prototype.onMouseMove = function(id, x, y, dx, dy, e) {

  this.x += dx;

  this.y += dy;

  this.update();

  this.onMove();

}

HWindow.prototype.onMouseUp = function(id, x, y, e) {


}

HWindow.prototype.onResizeDown = function(id, x, y, e) {

  this.curDir = 0;

  var dir = e.target.getAttribute('dir');

  var dirs = dir.split("|");

  for(var i = 0; i < dirs.length; i++) {

    this.curDir = this.curDir | this.DIR[dirs[i]]

  }

}

HWindow.prototype.onResizeMove = function(id, x, y, dx, dy, e) {

  this.isMin = false;

  var dir = this.curDir;

  var DIR = this.DIR;

  if (dir & DIR.TOP) {

    if(dy > 0 && this.h - dy < this.mh) {

      dy = this.h - this.mh;

    }

    this.y += dy;

    this.h -= dy;

  } else if (dir & DIR.BOTOOM) {

    this.h += dy;

  }

  if (dir & DIR.LEFT) {

    if(dx > 0 && this.w - dx < this.mw) {

      dx = this.w - this.mw;

    }

    this.x += dx;

    this.w -= dx;

  } else if (dir & DIR.RIGHT) {

    this.w += dx;

  }

  this.update();

  this.onResize();

}

HWindow.prototype.onResizeUp = function(id, x, y, e) {


}

HWindow.prototype.remove = function() {

  this.onClose();

  this.ele.onclick = null;

  this.eleClose.onclick = null;

  this.eleMin.onclick = null;

  this.ele.parentElement.removeChild(this.ele);

  var ind = this.manager.children.indexOf(this);

  this.manager.children.splice(ind, 1);

  for(var i = 0;i < this.manager.children.length; i++){

    this.manager.children[i].ele.style.zIndex = i;

  }

  this.manager = null;

  this.dragUtil.destroy();

  this.dragUtil = null;

  this.resizeUtil.destroy();

  this.resizeUtil = null;

  this.onResize = null;

  this.onMove = null;

  this.onClose = null;

}

HWindow.prototype.top = function() {

  var ind = this.manager.children.indexOf(this);

  this.manager.children.splice(ind, 1);

  this.manager.children.push(this);

  for(var i = 0;i < this.manager.children.length; i++){

    this.manager.children[i].ele.style.zIndex = i;

  }

}

HWindow.prototype.setTitle = function(title) {

  this.eleTitle.innerHTML = title;

}

HWindow.prototype.getTitle = function() {

  return this.eleTitle.innerHTML;

}

HWindow.prototype.setSize = function(w, h) {

  this.w = Math.max(w, this.mw);

  this.h = Math.max(h, this.mh);

  this.update();

  this.onResize();

}

HWindow.prototype.setPos = function(x, y) {

  this.x = x;

  this.y = y;

  this.update();

  this.onMove();

}

HWindow.prototype.center = function() {

  this.setPos((window.innerWidth - this.w) / 2, (window.innerHeight - this.h) / 2);

}

HWindow.prototype.setMin = function(min) {

  this.isMin = !min;

  this.toggleMin();

}

HWindow.prototype.getSize = function() {

  return {w: this.w, h: this.h};

}

HWindow.prototype.getPos = function() {

  return {x: this.x, y: this.y};

}

HWindow.prototype.getRect = function() {

  return {x: this.x, y: this.y, w: this.w, h: this.h};

}

HWindow.prototype.update = function() {

  this.ele.style.left = this.x + "px";

  this.ele.style.top = this.y + "px";

  if(this.isMin) {

    this.eleBody.style.width = this.mw + "px";

    this.eleBody.style.height = this.mh + "px";

  } else {

    this.eleBody.style.width = this.w + "px";

    this.eleBody.style.height = this.h + "px";

  }

}


HWindow.prototype.toggleMin = function() {

  this.isMin = !this.isMin;

  if(this.isMin) {

    this.eleMin.style.display = "none";

    this.eleMax.style.display = "inline-block";

  } else {

    this.eleMin.style.display = "inline-block";

    this.eleMax.style.display = "none";

  }

  this.update();

}

测试代码如下

<html>

    <head>

    <meta charset="utf-8"/>

    <title>js窗口组件</title>

    <style type="text/css">

    :root {

      --color-gray-1: #BBBBBB;

      --color-gray-2: #5F5F5F;

      --color-gray-3: #4F4F4F;

      --color-gray-4: #3C3C3C;

      --color-gray-5: #313131;

      --color-gray-6: #2B2B2B;

      --color-blue-1: #3592C4;

      --color-blue-2: #598ABA;

      --color-blue-3: #4B6EAF;

      --color-blue-4: #0D293E;

      --color-red-1: #8B3C3C;

      --color-green-1: #629755;

      --color-mask-1: rgba(0, 0, 0, 0.3);

      --color-mask-2: rgba(0, 0, 0, 0.5);

      --color-mask-3: rgba(0, 0, 0, 0.8);

      --font-size: 16px;

    }

    #windows {

      position: fixed;

      left: 0;

      top: 0;

      right: 0;

      bottom: 0;

      z-index: 0;

      overflow: hidden;

      pointer-events: none;

    }


    .win-pop {

      position: absolute;

      z-index: 0;

      left: 0;

      top: 0;

      pointer-events: auto;

      background-color: var(--color-gray-3);

      color: var(--color-gray-1);

      border: solid 1px var(--color-gray-2);

    }


    .win-pop-head {

      position: relative;

      height: 2.0em;

      background-color: var(--color-gray-3);

      cursor: move;

      width: 100%;

      overflow: hidden;

      flex-shrink: 0;

      display: flex;

      flex-direction: row;

      align-items: center;

      border-bottom: solid 1px var(--color-gray-2);

    }

    .win-pop-head-con {

      flex-grow: 1;

      overflow: hidden;

    }

    .win-pop-title {

      padding-left: 1em;

    }

    .win-pop-body {

      position: relative;

      left: 0;

      top: 0;

      overflow: hidden;

    }

    .win-pop-button-con {

      flex-shrink: 0;

      display: flex;

      flex-direction: row;

      align-items: center;

    }


    .win-pop-min {


    }

    .win-pop-max {


    }

    .win-pop-close {


    }

    .win-pop-button {

      display: inline-block;

      height: 2.0em;

      line-height: 2.0em;

      padding: 0 1em;

      cursor: pointer;

    }

    .win-pop-button:hover {

      background-color: var(--color-blue-3);

    }


    /**resize**/

    .win-resize-con {

      position: absolute;

      left: -1em;

      top: -1em;

      right: -1em;

      bottom: -1em;

      background-color: transparent;

      pointer-events: none;

      font-size: 10px;

      user-select: none;

    }


    .win-resize-item {

      position: absolute;

      pointer-events: auto;

      /*border: solid 1px red;*/

    }

    /**4个边**/

    .win-resize-eg {

      /*background-color: rebeccapurple;*/

      background-color: rgba(0, 0, 0, 0);

    }

    .win-resize-ns {

      left: 0;

      right: 0;

      height: 1em;

      cursor: ns-resize;

    }

    .win-resize-top {

      top: 0;

    }

    .win-resize-bottom {

      bottom: 0;

    }

    .win-resize-ew {

      top: 0;

      bottom: 0;

      width: 1em;

      cursor: ew-resize;

    }

    .win-resize-left {

      left: 0;

    }

    .win-resize-right {

      right: 0;

    }

    /**4个角**/

    .app-mobile .win-resize-cn {

      width: 2em;

      height: 2em;

    }

    .win-resize-cn {

      width: 1em;

      height: 1em;

    }

    .win-resize-nwse {

      cursor: nwse-resize;

    }

    .win-resize-top-left {

      left: 0;

      top: 0;

    }

    .win-resize-bottom-right {

      bottom: 0;

      right: 0;

    }

    .win-resize-nesw {

      cursor: nesw-resize;

    }

    .win-resize-top-right {

      top: 0;

      right: 0;

    }

    .win-resize-bottom-left {

      bottom: 0;

      left: 0;

    }


    </style>

    <script type="text/javascript" src="./dragUtil.js"></script>

    <script type="text/javascript" src="./windows.js"></script>

    <script type="text/javascript">

    var windows;

    var n = 0;

    function onLoad() {

    windows = new Windows();

    addWindow();

    }


    function addWindow() {

    n++;

    windows.add("窗口"+n, 100 + Math.random() * 300, 100 + Math.random() * 300, 300, 300);

    }

    </script>

    </head>

    <body onload="onLoad()">

    <button onclick="addWindow()">添加窗口</button>

    <!--windows-->

      <dv id="windows">

        <template id="winPop">

          <div class="win-pop">

            <div class="win-pop-head">

              <div class="win-pop-head-con">

                <span class="win-pop-title"></span>

              </div>

              <div class="win-pop-button-con">

                <div class="win-pop-button win-pop-min">▁</div>

                <div class="win-pop-button win-pop-max">□</div>

                <div class="win-pop-button win-pop-close">✖</div>

              </div>

            </div>

            <div class="win-pop-body"></div>

            <div class="win-resize-con">

              <div class="win-resize-item win-resize-eg win-resize-ns win-resize-top" dir="TOP" ></div>

              <div class="win-resize-item win-resize-eg win-resize-ns win-resize-bottom" dir="BOTOOM"></div>

              <div class="win-resize-item win-resize-eg win-resize-ew win-resize-left" dir="LEFT"></div>

              <div class="win-resize-item win-resize-eg win-resize-ew win-resize-right" dir="RIGHT"></div>

              <div class="win-resize-item win-resize-cn win-resize-nwse win-resize-top-left" dir="TOP|LEFT"></div>

              <div class="win-resize-item win-resize-cn win-resize-nwse win-resize-bottom-right" dir="BOTOOM|RIGHT"></div>

              <div class="win-resize-item win-resize-cn win-resize-nesw win-resize-top-right" dir="TOP|RIGHT"></div>

              <div class="win-resize-item win-resize-cn win-resize-nesw win-resize-bottom-left" dir="BOTOOM|LEFT"></div>

            </div>

          </div>

        </template>

      </dv>

    </body>

</html>

dom元素,css,js都直接复制就可以用。

也可以改造成其它版本,比如vue,这个就是从vue里边提取出来的。

拖拽功能之前介绍过。

窗口的内容,用户自己定义。

这个唯一多出来的是调整尺寸的功能。

定义了4个边,4个脚,然后定义样式,定义拖转,拖拽边角的时候,调整尺寸。


源码打包下载

« 上一篇下一篇 »

相关文章:

js拖拽工具库  (2024-9-20 9:34:48)

js中学物理仿真  (2022-9-27 9:16:49)

canvas窗口自适应  (2021-6-24 9:0:7)

显示fps  (2020-1-19 9:16:17)

js保留有效数字  (2019-7-30 15:32:12)

js的parseInt方法  (2019-2-15 9:12:44)

闪电效果  (2017-11-28 15:4:19)

js中判断一个对象的类型  (2017-3-30 14:27:35)

解九连环  (2016-12-1 20:58:11)

DataURL与File,Blob,canvas对象之间的互相转换的Javascript  (2016-11-25 14:58:41)

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。