This commit is contained in:
oneao committed 2026-04-17 17:25:15 +08:00
1 parent e893ef2e48
commit b6415c0d65
25 files changed
+1495 -112

No files matched your search

+384
View File
@@ -0,0 +1,384 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<title>Dialog Final</title>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js"></script>
<style>
.mask {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.35);
z-index: 999;
display: none;
}
.win-dialog {
position: fixed;
background: #fff;
box-shadow: 0 12px 40px rgba(0, 0, 0, .25);
display: none;
overflow: hidden;
z-index: 1000;
}
.win-header {
height: 40px;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #eee;
cursor: move;
background: #fafafa;
}
.win-title {
padding-left: 10px;
}
.win-btn {
display: flex;
height: 100%;
}
.btn-item {
padding: 0 10px;
display: flex;
align-items: center;
cursor: pointer;
}
.btn-item:hover {
background: #ddd;
}
.win-body {
height: calc(100% - 40px);
padding: 10px;
}
.resizer {
position: absolute;
}
.br {
right: 0;
bottom: 0;
width: 12px;
height: 12px;
cursor: nwse-resize;
}
.r {
right: 0;
top: 0;
width: 5px;
height: 100%;
cursor: ew-resize;
}
.b {
bottom: 0;
left: 0;
width: 100%;
height: 5px;
cursor: ns-resize;
}
.l {
left: 0;
top: 0;
width: 5px;
height: 100%;
cursor: ew-resize;
}
.t {
top: 0;
left: 0;
width: 100%;
height: 5px;
cursor: ns-resize;
}
</style>
</head>
<body>
<template id="file-template">
<div class="layout">
<div class="left">分类树</div>
<div class="middle">列表</div>
<div class="right">预览</div>
</div>
</template>
<button onclick="handleShowDialog()">
打开窗口
</button>
<script>
function handleShowDialog() {
Dialog.open({
title: 'Test Window',
template: '#file-template',
width: '80%',
height: '80%'
})
}
// Dialog
const Dialog = (() => {
let $mask = $('<div class="mask"></div>').appendTo('body');
let $el = null;
let isMax = false;
let old = {};
let opt = null;
// ====== 工具函数 ======
function parseSize(val, max) {
if (typeof val === 'number') return val;
if (typeof val === 'string') {
if (val.includes('%')) return max * parseFloat(val) / 100;
if (val.includes('vw')) return window.innerWidth * parseFloat(val) / 100;
if (val.includes('vh')) return window.innerHeight * parseFloat(val) / 100;
return parseFloat(val);
}
return max;
}
// ====== 核心方法 ======
function applySize() {
const maxW = window.innerWidth;
const maxH = window.innerHeight;
let w = parseSize(opt.width || 600, maxW);
let h = parseSize(opt.height || 400, maxH);
w = Math.min(w, maxW);
h = Math.min(h, maxH);
$el.css({
width: w,
height: h,
left: (maxW - w) / 2,
top: (maxH - h) / 2
});
}
function bindResize() {
$(window).on('resize.dialog', () => {
if (isMax) {
$el.css({
width: window.innerWidth,
height: window.innerHeight
});
return;
}
const w = opt.width;
const h = opt.height;
if (
(typeof w === 'string' && (w.includes('%') || w.includes('vw'))) ||
(typeof h === 'string' && (h.includes('%') || h.includes('vh')))
) {
applySize();
}
});
}
function bindEvents() {
const self = {
get el() { return $el; }
};
$el.find('.close').on('click', close);
// drag
let move = false, ox = 0, oy = 0;
$el.find('.win-header').on('mousedown', function (e) {
if (isMax) return;
move = true;
const pos = $el.position();
ox = e.clientX - pos.left;
oy = e.clientY - pos.top;
$(document).on('mousemove.drag', function (e) {
if (!move) return;
$el.css({
left: e.clientX - ox,
top: e.clientY - oy
});
});
$(document).on('mouseup.drag', function () {
move = false;
$(document).off('.drag');
});
});
// resize
const MIN_W = 300;
const MIN_H = 200;
$el.find('.resizer').on('mousedown', function (e) {
if (isMax) return;
let type = $(this).attr('class').split(' ')[1];
const startX = e.clientX;
const startY = e.clientY;
const startW = $el.width();
const startH = $el.height();
const startL = parseFloat($el.css('left'));
const startT = parseFloat($el.css('top'));
const MAX_W = window.innerWidth;
const MAX_H = window.innerHeight;
function onMove(e) {
if (e.buttons !== 1) return;
let dx = e.clientX - startX;
let dy = e.clientY - startY;
let newW = startW;
let newH = startH;
let newL = startL;
let newT = startT;
if (type === 'br') { newW += dx; newH += dy; }
if (type === 'r') newW += dx;
if (type === 'b') newH += dy;
if (type === 'l') { newW -= dx; newL += dx; }
if (type === 't') { newH -= dy; newT += dy; }
if (newW < MIN_W) newW = MIN_W;
if (newH < MIN_H) newH = MIN_H;
if (newW > MAX_W) newW = MAX_W;
if (newH > MAX_H) newH = MAX_H;
$el.css({
width: newW,
height: newH,
left: newL,
top: newT
});
}
function onUp() {
$(document).off('.resize');
}
$(document)
.on('mousemove.resize', onMove)
.on('mouseup.resize', onUp);
});
// max
$el.find('.max').on('click', function () {
if (!isMax) {
old = {
width: $el.width(),
height: $el.height(),
left: $el.position().left,
top: $el.position().top
};
$el.css({
left: 0,
top: 0,
width: window.innerWidth,
height: window.innerHeight
});
isMax = true;
} else {
$el.css(old);
isMax = false;
}
});
}
function destroy() {
if ($el) {
$el.remove();
$el = null;
}
isMax = false;
$mask.off().hide();
$(window).off('resize.dialog');
}
// ====== API ======
function open(o) {
destroy();
opt = o;
$el = $(`
<div class="win-dialog">
<div class="win-header">
<div class="win-title"></div>
<div class="win-btn">
<div class="btn-item max">MAX</div>
<div class="btn-item close">X</div>
</div>
</div>
<div class="win-body"></div>
</div>
`).appendTo('body');
$el.find('.win-title').text(opt.title || 'Dialog');
const $body = $el.find('.win-body');
if (opt.template) {
const tpl = document.querySelector(opt.template);
const node = tpl.content.cloneNode(true);
$body.empty().append(node);
}
else if (opt.content instanceof HTMLElement) {
$body.empty().append(opt.content);
}
else {
$body.html(opt.content || '');
}
applySize();
$mask.fadeIn(120);
$el.fadeIn(180);
bindEvents();
bindResize();
}
function close() {
$el?.fadeOut(120);
$mask.fadeOut(120);
setTimeout(() => destroy(), 120);
}
// ====== 单例导出 ======
return {
open,
close
};
})();
</script>
</body>
</html>