项目中可能会遇到需要弹出一个窗口。类似于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个脚,然后定义样式,定义拖转,拖拽边角的时候,调整尺寸。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。