Vue全局最大化、最小化、还原、关闭、拖拽
大约 3 分钟
Vue全局最大化、最小化、还原、关闭、拖拽
在基于Vue全局指令实现拖拽的基础上,丰富了最大化、最小化、还原、关闭功能。
封装全局指令
在项目的 src 目录下创建 src/utils/windowControl.js 文件,代码如下:
export default {
install(Vue) {
Vue.directive('window-control', {
inserted(el, binding) {
console.log('window-control', binding);
// 默认配置(可通过指令参数覆盖)
const config = {
draggable: false, // 是否可拖拽
minimizable: false, // 是否可最小化
maximizable: false, // 是否可最大化
boundary: null, // 默认无限制,可传入选择器或DOM对象
closable: false, // 是否显示关闭按钮
onClose: null, // 关闭时的回调函数
onMined: null, // 最小化时的回调函数
onMaxed: null, // 最大化时的回调函数
...binding.value // 自定义配置
};
// 初始状态
let isMaximized = false;
let originalStyle = {};
// ========== 拖拽逻辑 ==========
if (config.draggable) {
el.style.position = 'absolute'; // 必须设置为绝对定位
el.onmousedown = function (ev) {
if (isMaximized) return; // 最大化时禁止拖拽
const disX = ev.clientX - el.offsetLeft;
const disY = ev.clientY - el.offsetTop;
document.onmousemove = function (ev) {
const left = ev.clientX - disX;
const top = ev.clientY - disY;
// 边界检查(防止拖出屏幕)
const maxLeft = window.innerWidth - el.offsetWidth;
const maxTop = window.innerHeight - el.offsetHeight;
el.style.left = Math.max(0, Math.min(left, maxLeft)) + 'px';
el.style.top = Math.max(0, Math.min(top, maxTop)) + 'px';
};
document.onmouseup = function () {
document.onmousemove = null;
document.onmouseup = null;
};
};
}
// ========== 窗口控制按钮 ==========
if (config.minimizable || config.maximizable) {
const btnContainer = document.createElement('div');
btnContainer.className = 'window-control-btns';
// 最小化按钮
if (config.minimizable) {
const minBtn = document.createElement('button');
minBtn.innerHTML = '−';
minBtn.onclick = () => {
// 隐藏窗口
el.style.display = 'none';
// 可在这里触发自定义事件
if (typeof config.onMined === 'function') {
config.onMined(el);
}
};
btnContainer.appendChild(minBtn);
}
// 最大化/还原按钮
if (config.maximizable) {
const maxBtn = document.createElement('button');
maxBtn.innerHTML = '□';
maxBtn.onclick = () => {
if (isMaximized) {
// 还原窗口
Object.assign(el.style, originalStyle);
maxBtn.innerHTML = '□';
} else {
// 最大化窗口
if (config.boundary) {
console.log(11111111, config.boundary);
const boundaryEl = typeof config.boundary === 'string'
? document.querySelector(config.boundary)
: config.boundary;
console.log(22222222, boundaryEl);
if (boundaryEl) {
originalStyle = {
width: el.style.width,
height: el.style.height,
left: el.style.left,
top: el.style.top
};
// 限制在boundary区域内
el.style.width = `${boundaryEl.offsetWidth}px`;
el.style.height = `${boundaryEl.offsetHeight}px`;
el.style.left = `${boundaryEl.offsetLeft}px`;
el.style.top = `${boundaryEl.offsetTop}px`;
}
} else {
// 默认全屏
el.style.width = '100vw';
el.style.height = '100vh';
el.style.left = '0';
el.style.top = '0';
}
maxBtn.innerHTML = '↗';
}
isMaximized = !isMaximized;
if (typeof config.onMaxed === 'function') {
config.onMaxed(el, isMaximized);
}
};
btnContainer.appendChild(maxBtn);
}
// 关闭按钮(×)
if (config.closable) {
const closeBtn = document.createElement('button');
closeBtn.innerHTML = '×';
closeBtn.onclick = () => {
// 触发回调或自定义事件
if (typeof config.onClose === 'function') {
config.onClose(el);
} else {
// 移除窗口
el.remove();
}
};
btnContainer.appendChild(closeBtn);
}
// 将按钮容器添加到元素右上角
btnContainer.style.position = 'absolute';
btnContainer.style.right = '10px';
btnContainer.style.top = '10px';
el.appendChild(btnContainer);
}
}
});
}
};
使用插件
在 src/main.js 入口文件引入包含全局拖拽指令的插件,代码如下:
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import windowControl from '@/utils/windowControl.js' // 引入插件
// 使用插件
Vue.use(windowControl)
new Vue({
router,
render: h => h(App)
}).$mount('#app')
在组件中使用拖拽指令
在任意的组件文件中可以通过 v-candrag 指令赋予元素可拖拽的能力,代码如下:
<template>
<div class="drag-container">
<div class="drag-div" v-window-control="{
draggable: true,
maximizable: true,
minimizable: true,
closable: true,
boundary: '.main',
onClose: handleClose,
onMaxed: handleMaximize,
onMined: handleMinimize,
}"></div>
</div>
</template>
<script>
// javascript脚本代码...
export default {
methods: {
handleClose(el) {
console.log("窗口已关闭", el);
el.remove(); // 直接移除DOM元素(或隐藏 el.style.display = 'none')
},
handleMinimize(el) {
console.log("窗口已最小化", el);
},
handleMaximize(el, isMaximized) {
console.log(el, `窗口状态:${isMaximized ? "最大化" : "还原"}`);
},
}
};
</script>
<style scoped>
.drag-container {
width: 100%;
height: 100%;
position: relative; /* 把拖拽元素父元素设置为相对定位,非常重要!!! */
background-color: bisque;
}
.drag-div {
position: absolute; /* 把拖拽元素设置为绝对定位,非常重要!!! */
width: 300px;
height: 300px;
background-color: pink;
}
</style>
