mirror of
https://github.com/zclzone/vue-naive-admin.git
synced 2025-05-01 06:39:01 +08:00
feat: 增加MeModal拖拽功能
This commit is contained in:
parent
2c9604a829
commit
a6773cbfec
@ -1,7 +1,7 @@
|
|||||||
<!--------------------------------
|
<!--------------------------------
|
||||||
- @Author: Ronnie Zhang
|
- @Author: Ronnie Zhang
|
||||||
- @LastEditor: Ronnie Zhang
|
- @LastEditor: Ronnie Zhang
|
||||||
- @LastEditTime: 2023/12/16 18:50:02
|
- @LastEditTime: 2024/01/13 17:41:38
|
||||||
- @Email: zclzone@outlook.com
|
- @Email: zclzone@outlook.com
|
||||||
- Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top
|
- Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top
|
||||||
--------------------------------->
|
--------------------------------->
|
||||||
@ -9,17 +9,17 @@
|
|||||||
<template>
|
<template>
|
||||||
<n-modal
|
<n-modal
|
||||||
v-model:show="show"
|
v-model:show="show"
|
||||||
|
class="modal-box"
|
||||||
:style="{ width: modalOptions.width, ...modalOptions.modalStyle }"
|
:style="{ width: modalOptions.width, ...modalOptions.modalStyle }"
|
||||||
:preset="undefined"
|
:preset="undefined"
|
||||||
size="huge"
|
size="huge"
|
||||||
:bordered="false"
|
:bordered="false"
|
||||||
|
@after-leave="onAfterLeave"
|
||||||
>
|
>
|
||||||
<n-card
|
<n-card :style="modalOptions.contentStyle" :closable="modalOptions.closable" @close="close()">
|
||||||
:title="modalOptions.title"
|
<template #header>
|
||||||
:style="modalOptions.contentStyle"
|
<header class="modal-header">{{ modalOptions.title }}</header>
|
||||||
:closable="modalOptions.closable"
|
</template>
|
||||||
@close="close()"
|
|
||||||
>
|
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
|
|
||||||
<!-- 底部按钮 -->
|
<!-- 底部按钮 -->
|
||||||
@ -45,6 +45,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import { initDrag } from './utils'
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
width: {
|
width: {
|
||||||
type: String,
|
type: String,
|
||||||
@ -101,12 +102,17 @@ const show = ref(false)
|
|||||||
const modalOptions = ref({})
|
const modalOptions = ref({})
|
||||||
|
|
||||||
// 打开模态框
|
// 打开模态框
|
||||||
function open(options = {}) {
|
async function open(options = {}) {
|
||||||
// 将props和options合并赋值给modalOptions
|
// 将props和options合并赋值给modalOptions
|
||||||
modalOptions.value = { ...props, ...options }
|
modalOptions.value = { ...props, ...options }
|
||||||
|
|
||||||
// 将show的值设置为true
|
// 将show的值设置为true
|
||||||
show.value = true
|
show.value = true
|
||||||
|
await nextTick()
|
||||||
|
initDrag(
|
||||||
|
Array.prototype.at.call(document.querySelectorAll('.modal-header'), -1),
|
||||||
|
Array.prototype.at.call(document.querySelectorAll('.modal-box'), -1)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 定义一个close函数,用于关闭模态框
|
// 定义一个close函数,用于关闭模态框
|
||||||
@ -149,6 +155,14 @@ async function handleCancel(data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function onAfterLeave() {
|
||||||
|
await nextTick()
|
||||||
|
initDrag(
|
||||||
|
Array.prototype.at.call(document.querySelectorAll('.modal-header'), -1),
|
||||||
|
Array.prototype.at.call(document.querySelectorAll('.modal-box'), -1)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const okLoading = computed({
|
const okLoading = computed({
|
||||||
get() {
|
get() {
|
||||||
return !!modalOptions.value?.okLoading
|
return !!modalOptions.value?.okLoading
|
||||||
|
94
src/components/me/modal/utils.js
Normal file
94
src/components/me/modal/utils.js
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
/**********************************
|
||||||
|
* @Author: Ronnie Zhang
|
||||||
|
* @LastEditor: Ronnie Zhang
|
||||||
|
* @LastEditTime: 2024/01/13 17:41:26
|
||||||
|
* @Email: zclzone@outlook.com
|
||||||
|
* Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top
|
||||||
|
**********************************/
|
||||||
|
|
||||||
|
// 获取元素的CSS样式
|
||||||
|
function getCss(element, key) {
|
||||||
|
return element.currentStyle
|
||||||
|
? element.currentStyle[key]
|
||||||
|
: window.getComputedStyle(element, null)[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
const params = {
|
||||||
|
left: 0,
|
||||||
|
top: 0,
|
||||||
|
currentX: 0,
|
||||||
|
currentY: 0,
|
||||||
|
flag: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化拖拽
|
||||||
|
export function initDrag(bar, box) {
|
||||||
|
if (!bar || !box) return
|
||||||
|
const screenWidth = document.body.clientWidth // 页面宽度
|
||||||
|
const screenHeight = document.documentElement.clientHeight // 页面可见区域高度
|
||||||
|
|
||||||
|
const dragDomWidth = box.offsetWidth // 盒子宽度
|
||||||
|
const dragDomHeight = box.offsetHeight // 盒子高度
|
||||||
|
|
||||||
|
const minDomLeft = box.offsetLeft // 盒子相对于父元素的左偏移量
|
||||||
|
const minDomTop = box.offsetTop // 盒子相对于父元素的上偏移量
|
||||||
|
|
||||||
|
const maxDragDomLeft = screenWidth - minDomLeft - dragDomWidth // 盒子在水平方向上可拖拽的最大距离
|
||||||
|
const maxDragDomTop = screenHeight - minDomTop - dragDomHeight // 盒子在垂直方向上可拖拽的最大距离
|
||||||
|
|
||||||
|
if (getCss(box, 'left') !== 'auto') {
|
||||||
|
params.left = getCss(box, 'left')
|
||||||
|
}
|
||||||
|
if (getCss(box, 'top') !== 'auto') {
|
||||||
|
params.top = getCss(box, 'top')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置触发拖动元素的鼠标样式为移动图标
|
||||||
|
bar.style.cursor = 'move'
|
||||||
|
|
||||||
|
// 鼠标按下事件处理函数
|
||||||
|
bar.onmousedown = function (e) {
|
||||||
|
params.flag = true // 设置拖拽标志为true
|
||||||
|
e.preventDefault() // 阻止默认事件
|
||||||
|
params.currentX = e.clientX // 鼠标当前位置的X坐标
|
||||||
|
params.currentY = e.clientY // 鼠标当前位置的Y坐标
|
||||||
|
}
|
||||||
|
document.onmouseup = function () {
|
||||||
|
params.flag = false // 设置拖拽标志为false
|
||||||
|
if (getCss(box, 'left') !== 'auto') {
|
||||||
|
params.left = getCss(box, 'left')
|
||||||
|
}
|
||||||
|
if (getCss(box, 'top') !== 'auto') {
|
||||||
|
params.top = getCss(box, 'top')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
document.onmousemove = function (e) {
|
||||||
|
e.preventDefault() // 阻止默认事件
|
||||||
|
// 如果拖拽标志为true
|
||||||
|
if (params.flag) {
|
||||||
|
const nowX = e.clientX // 鼠标当前位置的X坐标
|
||||||
|
const nowY = e.clientY // 鼠标当前位置的Y坐标
|
||||||
|
const disX = nowX - params.currentX // 鼠标移动的X距离
|
||||||
|
const disY = nowY - params.currentY // 鼠标移动的Y距离
|
||||||
|
|
||||||
|
let left = parseInt(params.left) + disX // 盒子元素的新left值
|
||||||
|
let top = parseInt(params.top) + disY // 盒子元素的新top值
|
||||||
|
|
||||||
|
// 拖出屏幕边缘
|
||||||
|
if (-left > minDomLeft) {
|
||||||
|
left = -minDomLeft
|
||||||
|
} else if (left > maxDragDomLeft) {
|
||||||
|
left = maxDragDomLeft
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-top > minDomTop) {
|
||||||
|
top = -minDomTop
|
||||||
|
} else if (top > maxDragDomTop) {
|
||||||
|
top = maxDragDomTop
|
||||||
|
}
|
||||||
|
|
||||||
|
box.style.left = left + 'px'
|
||||||
|
box.style.top = top + 'px'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
<!--------------------------------
|
<!--------------------------------
|
||||||
- @Author: Ronnie Zhang
|
- @Author: Ronnie Zhang
|
||||||
- @LastEditor: Ronnie Zhang
|
- @LastEditor: Ronnie Zhang
|
||||||
- @LastEditTime: 2023/12/16 18:51:56
|
- @LastEditTime: 2024/01/13 17:41:47
|
||||||
- @Email: zclzone@outlook.com
|
- @Email: zclzone@outlook.com
|
||||||
- Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top
|
- Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top
|
||||||
--------------------------------->
|
--------------------------------->
|
||||||
@ -55,7 +55,7 @@ function openModal2() {
|
|||||||
$modal2.value?.open({
|
$modal2.value?.open({
|
||||||
cancelText: '关闭当前',
|
cancelText: '关闭当前',
|
||||||
okText: '关闭所有弹窗',
|
okText: '关闭所有弹窗',
|
||||||
modalStyle: { width: '320px', padding: '12px', top: '100px' },
|
width: '400px',
|
||||||
async onOk() {
|
async onOk() {
|
||||||
okLoading2.value = true
|
okLoading2.value = true
|
||||||
$message.loading('正在关闭...', { key: 'modal2' })
|
$message.loading('正在关闭...', { key: 'modal2' })
|
||||||
|
Loading…
x
Reference in New Issue
Block a user