用vue3 setup语法糖写一个拖拽弹窗组件
时间: 2023-09-24 20:11:35 浏览: 106
好的,下面是用 Vue3 的 setup 语法糖写一个拖拽弹窗组件的示例代码:
```vue
<template>
<div class="draggable-dialog" :style="{ left: dialogLeft + 'px', top: dialogTop + 'px' }">
<div class="dialog-header" @mousedown="onHeaderMouseDown">
<slot name="title">拖拽弹窗</slot>
<button class="close-btn" @click="$emit('close')">关闭</button>
</div>
<div class="dialog-body">
<slot></slot>
</div>
</div>
</template>
<script>
import { ref, reactive } from 'vue'
export default {
props: {
visible: {
type: Boolean,
default: false
},
x: {
type: Number,
default: 0
},
y: {
type: Number,
default: 0
}
},
emits: ['close'],
setup(props, { emit }) {
const dialogLeft = ref(props.x)
const dialogTop = ref(props.y)
const dragging = reactive({ value: false })
const mousePos = reactive({ x: 0, y: 0 })
const onHeaderMouseDown = (event) => {
event.preventDefault()
dragging.value = true
mousePos.x = event.clientX
mousePos.y = event.clientY
}
const onDocumentMouseMove = (event) => {
if (dragging.value) {
const offsetX = event.clientX - mousePos.x
const offsetY = event.clientY - mousePos.y
dialogLeft.value += offsetX
dialogTop.value += offsetY
mousePos.x = event.clientX
mousePos.y = event.clientY
}
}
const onDocumentMouseUp = () => {
dragging.value = false
}
// 监听 visible 属性的变化,隐藏或显示弹窗
watch(() => props.visible, (val) => {
if (val) {
document.addEventListener('mousemove', onDocumentMouseMove)
document.addEventListener('mouseup', onDocumentMouseUp)
} else {
document.removeEventListener('mousemove', onDocumentMouseMove)
document.removeEventListener('mouseup', onDocumentMouseUp)
}
})
// 初始化时直接绑定监听器
if (props.visible) {
document.addEventListener('mousemove', onDocumentMouseMove)
document.addEventListener('mouseup', onDocumentMouseUp)
}
return {
dialogLeft,
dialogTop,
onHeaderMouseDown
}
}
}
</script>
<style scoped>
.draggable-dialog {
position: absolute;
background-color: #fff;
border: 1px solid #ccc;
z-index: 1000;
}
.dialog-header {
padding: 8px;
background-color: #f2f2f2;
cursor: move;
}
.dialog-body {
padding: 16px;
}
.close-btn {
float: right;
border: none;
background-color: transparent;
cursor: pointer;
}
</style>
```
这个组件的 props 包括 visible、x 和 y,分别表示弹窗是否可见、弹窗的左上角 x 坐标和 y 坐标。当 visible 变为 true 时,弹窗会显示出来并且可以拖拽。当 visible 变为 false 时,弹窗会隐藏并且停止拖拽。
组件内部使用 ref 和 reactive 两个响应式 API 来声明变量。dragging 和 mousePos 都是 reactive 变量,前者表示是否正在拖拽,后者表示鼠标的位置。dialogLeft 和 dialogTop 都是 ref 变量,表示弹窗的左上角位置。
onHeaderMouseDown 函数是鼠标按下事件的处理函数,它会将 dragging 设置为 true,表示开始拖拽,并且记录下鼠标的位置。onDocumentMouseMove 和 onDocumentMouseUp 分别是鼠标移动和鼠标抬起事件的处理函数,它们会根据鼠标的位置更新弹窗的位置,并且在拖拽结束时将 dragging 设置为 false。
最后,使用 watch 监听 visible 属性的变化,如果 visible 变为 true,就会绑定 document 的 mousemove 和 mouseup 事件;如果 visible 变为 false,就会移除这两个事件。如果组件初始化时 visible 就是 true,也需要直接绑定监听器。
阅读全文