实现效果
解决方案
方案中使用的是 vue
的 指令
来实现的,如果是 js
的话,可以更换成 js dom 事件绑定来实现。
directive.js
文件,要在 main.js
引入该文件
import Vue from 'vue'
Vue.directive('dialogDragWidth', {
inserted(el, binding) {
// 由于使用 binding 获取不到 dom 元素,所以我就改用了 固定布局的方式来获取窗体元素。
const dragDom = el.parentNode.parentNode // 窗体中间嵌套了一层:dialog -> div -> dragDom
// 由于使用的是一个指令绑定到了三个 dragdom 上面,所以做了参数判断。
// corner: 右下角;right: 右侧;bottom:底部;
// 参数可根据自身编码习惯修改
const value = binding.value || 'corner'
if (!dragDom) return // 错误处理
el.onmousedown = (e) => {
// 鼠标按下,在原来页面上增加透明遮罩,防止部分元素例如iframe监听不到鼠标事件
const mask = document.createElement('div')
mask.setAttribute('style', 'position:fixed;top:0px;bottom:0px;left:0px;right:0px;background:rgba(0,0,0,0)')
document.body.appendChild(mask)
// 计算当前元素距离可视区的距离
const disX = e.clientX - el.offsetLeft
const disY = e.clientY - el.offsetTop
document.body.onmousemove = function (e) {
e.preventDefault() // 移动时禁用默认事件
// 通过事件委托,计算移动的距离
const l = e.clientX - disX
const h = e.clientY - disY
// 一个方法实现三种方式,所以根据参数来判断 size 方向
if (value === 'right' || value === 'corner') {
dragDom.style.width = `${l}px`
}
// 判断弹窗高度,防止用于拖动的点移出可视区
if (value === 'bottom' || value === 'corner') {
dragDom.style.height = `${h > document.body.offsetHeight ? document.body.offsetHeight : h}px`
}
}
document.body.onmouseup = function (e) {
document.body.removeChild(mask) // 移除mask遮罩
document.body.onmousemove = null
document.body.onmouseup = null
}
}
}
})
dragSize.vue
<template>
<div class="sd-drag-size-box">
<!-- 指令的参数是字符串,一定不要少了 外面的 单引号 '' -->
<div v-dialogDragWidth="'right'" class="sd-drag-item sd-drag-item-right"></div>
<div v-dialogDragWidth="'corner'" class="sd-drag-item sd-drag-item-corner"></div>
<div v-dialogDragWidth="'bottom'" class="sd-drag-item sd-drag-item-bottom"></div>
</div>
</template>
<style lang="scss" scoped>
.sd-drag-size-box {
.sd-drag-item {
position: absolute;
z-index: 2;
&-right {
height: 98%;
width: 2px;
right: -1px;
top: 0;
cursor: col-resize;
background: red;
}
&-corner {
width: 5px;
height: 5px;
position: absolute;
right: -2px;
bottom: -2px;
cursor: se-resize;
background: black;
}
&-bottom {
height: 2px;
width: 98%;
left: 0;
bottom: -1px;
cursor: row-resize;
background: #096;
}
}
}
</style>
使用方式
index.vue
<template>
<div class="box">
<!-- 放在窗体子级 -->
<DragSize />
</div>
</template>
<style>
import DragSize from './dragSize.vue'
export default {
name: 'Demo',
components: { DragSize }
}
</style>
<style lang="scss" scoped>
.box {
position: absolute;
left: 20px;
top: 50px;
// 我是拖动的右侧,和底部,所以 根据处理逻辑,不能向这两个方向设置 定位
right: unset;
bottom: unset;
border-radius: 8px;
width: 452px;
height: 650px;
}
</style>