效果示例
DragResizeContainer组件
<!--可拖拽移动、可通过拖拽调整容器大小的组件-->
<template>
<div ref="dragBox" class="main" :style="{ zIndex: zIndex }" v-change-z-index>
<div :ref="DARG_LINE.T_LINE" class="resize-y border-t"></div>
<div class="g-flex">
<div :ref="DARG_LINE.L_LINE" class="resize-x border-l"></div>
<div ref="dragBoxContent" :style="{ width: width + 'px', height: height + 'px' }">
<slot name="content"></slot>
</div>
<div :ref="DARG_LINE.R_LINE" class="resize-x border-r"></div>
</div>
<div :ref="DARG_LINE.B_LINE" class="resize-y border-b"></div>
<div ref="resizeXYRef" class="resize-xy"></div>
</div>
</template>
<script>
const DARG_LINE = {
T_LINE: 'topLine',
B_LINE: 'bottomLine',
R_LINE: 'rightLine',
L_LINE: 'leftLine',
}
export default {
name: 'DragResizeContainer',
props: {
parentDom: {
type: HTMLElement,
default: null,
},
positionConfig: {
type: Object,
default: () => {
return {}
},
},
zIndex: {
type: String,
default: '100',
},
height: {
type: [String, Number],
default: '0',
},
width: {
type: [String, Number],
default: '0',
},
safeDistance: {
type: Object,
default: () => {
return {
top: 0,
left: 0,
right: 0,
bottom: 0,
}
},
},
minHeight: {
type: [String, Number],
default: 10,
},
maxHeight: {
type: [String, Number],
default: 800,
},
minWidth: {
type: [String, Number],
default: 10,
},
maxWidth: {
type: [String, Number],
default: 1200,
},
canDrag: {
type: Boolean,
default: false,
},
horizontalMove: {
type: Boolean,
default: true,
},
verticalMove: {
type: Boolean,
default: true,
},
leftLine: {
type: Boolean,
default: true,
},
rightLine: {
type: Boolean,
default: true,
},
topLine: {
type: Boolean,
default: true,
},
bottomLine: {
type: Boolean,
default: true,
},
rightBottomLine: {
type: Boolean,
default: true,
},
disableUserSelect: {
type: Boolean,
default: true,
},
},
data() {
return {
DARG_LINE,
startResize: false,
RESIZE_LINE_ARR: [
DARG_LINE.B_LINE,
DARG_LINE.L_LINE,
DARG_LINE.R_LINE,
DARG_LINE.T_LINE,
],
tempUserSelect: '',
}
},
mounted() {
this.$nextTick(() => {
Object.keys(this.positionConfig).forEach(key => {
const dragBox = this.$refs.dragBox
dragBox.style[key] = this.positionConfig[key]
})
this.resizeLineInit()
this.resizeXYInit()
this.dragInit()
this.setZIndexTopFn(this.$refs.dragBox)
})
},
methods: {
setZIndexTopFn(dom) {
if (dom) {
this.$utils.setZIndexTop(dom)
}
},
dragInit() {
const parentDom = this.parentDom
const dragBoxContent = this.$refs.dragBoxContent
const dragBox = this.$refs.dragBox
let startX, startY, initialLeft, initialTop
dragBoxContent.addEventListener('mousedown', (event) => {
if (!this.canDrag) return
if (this.disableUserSelect) {
this.tempUserSelect = document.body.style.userSelect
document.body.style.userSelect = 'none'
}
startX = event.clientX
startY = event.clientY
const {left, top} = dragBoxContent.getBoundingClientRect()
initialLeft = left
initialTop = top
document.addEventListener('mousemove', onMouseMove)
document.addEventListener('mouseup', onMouseUp, {once: true})
})
const onMouseMove = (event) => {
const offsetX = event.clientX - startX
const offsetY = event.clientY - startY
const newLeft = initialLeft + offsetX
const newTop = initialTop + offsetY
const newRight = newLeft + dragBox.getBoundingClientRect().width
const newBottom = newTop + dragBox.getBoundingClientRect().height
if (
newLeft >=
parentDom.getBoundingClientRect().left + (this.safeDistance.left || 0) &&
newRight <=
parentDom.getBoundingClientRect().right - (this.safeDistance.right || 0) &&
this.horizontalMove
) {
dragBox.style.left = `${newLeft - parentDom.getBoundingClientRect().left}px`
}
if (
newTop >=
parentDom.getBoundingClientRect().top + (this.safeDistance.top || 0) &&
newBottom <=
parentDom.getBoundingClientRect().bottom -
(this.safeDistance.bottom || 0) &&
this.verticalMove
) {
dragBox.style.top = `${newTop - parentDom.getBoundingClientRect().top}px`
}
}
const onMouseUp = (_event) => {
if (this.disableUserSelect) document.body.style.userSelect = this.tempUserSelect
document.removeEventListener('mousemove', onMouseMove)
}
},
resizeXYInit() {
const dragXYRef = this.$refs.resizeXYRef
const dragBox = this.$refs.dragBox
let isResizing = false;
let prevX = 0;
let prevY = 0;
let prevWidth = 0;
let prevHeight = 0;
dragXYRef.addEventListener('mousedown', (event) => {
if (!this.rightBottomLine) return
if (this.disableUserSelect) {
this.tempUserSelect = document.body.style.userSelect
document.body.style.userSelect = 'none'
}
isResizing = true
prevX = event.clientX
prevY = event.clientY
prevWidth = dragBox.getBoundingClientRect().width
prevHeight = dragBox.getBoundingClientRect().height
document.addEventListener('mousemove', onMouseMoveXY)
document.addEventListener('mouseup', onMouseUpXY, {once: true})
})
const onMouseMoveXY = (event) => {
if (isResizing) {
const newWidth = prevWidth + (event.clientX - prevX)
const newHeight = prevHeight + (event.clientY - prevY)
const width = Math.max(this.minWidth, Math.min(this.maxWidth, newWidth))
const height = Math.max(this.minHeight, Math.min(this.maxHeight, newHeight))
requestAnimationFrame(() => {
this.$emit('update:width', width - 10)
this.$emit('update:height', height - 10)
})
}
}
const onMouseUpXY = (event) => {
isResizing = false
if (this.disableUserSelect) document.body.style.userSelect = this.tempUserSelect
document.removeEventListener('mousemove', onMouseMoveXY)
}
},
resizeLineInit() {
const dragBox = this.$refs.dragBox
this.RESIZE_LINE_ARR.forEach((item) => {
this.lineInit(this.$refs[item], dragBox, item)
})
},
lineInit(line, dragBox, lineKey) {
let width, height, left, top
let startCoord = 0
let isResizing = false
const parentDom = this.parentDom
const isVertical = [DARG_LINE.T_LINE, DARG_LINE.B_LINE].includes(lineKey)
line.addEventListener('mousedown', (event) => {
if (!this[lineKey]) return
if (this.disableUserSelect) {
this.tempUserSelect = document.body.style.userSelect
document.body.style.userSelect = 'none'
}
isResizing = true
width = dragBox.getBoundingClientRect().width
height = dragBox.getBoundingClientRect().height
if (lineKey === DARG_LINE.T_LINE) startCoord = event.clientY + height
if (lineKey === DARG_LINE.B_LINE) startCoord = event.clientY - height
if (lineKey === DARG_LINE.L_LINE) startCoord = event.clientX + width
if (lineKey === DARG_LINE.R_LINE) startCoord = event.clientX - width
left =
width +
dragBox.getBoundingClientRect().left -
parentDom.getBoundingClientRect().left
top =
height +
dragBox.getBoundingClientRect().top -
parentDom.getBoundingClientRect().top
document.addEventListener('mousemove', onMouseMove)
document.addEventListener('mouseup', onMouseUp, {once: true})
})
const onMouseMove = (event) => {
if (isResizing) {
let curSize
const sizeLimit = isVertical
? [this.minHeight, this.maxHeight]
: [this.minWidth, this.maxWidth]
if (lineKey === DARG_LINE.T_LINE) curSize = startCoord - event.clientY
if (lineKey === DARG_LINE.B_LINE) curSize = event.clientY - startCoord
if (lineKey === DARG_LINE.L_LINE) curSize = startCoord - event.clientX
if (lineKey === DARG_LINE.R_LINE) curSize = event.clientX - startCoord
if (
this.lineEdgeCheck({
curSize,
sizeLimit,
lineKey,
parentDom,
clientY: event.clientY,
clientX: event.clientX,
})
) {
requestAnimationFrame(() => {
if (lineKey === DARG_LINE.R_LINE)
this.$emit('update:width', curSize - 10)
if (lineKey === DARG_LINE.B_LINE)
this.$emit('update:height', curSize - 10)
if (lineKey === DARG_LINE.T_LINE) {
dragBox.style.top = top - curSize + 'px'
this.$emit('update:height', curSize - 10)
}
if (lineKey === DARG_LINE.L_LINE) {
dragBox.style.left = left - curSize + 'px'
this.$emit('update:width', curSize - 10)
}
})
}
}
}
const onMouseUp = () => {
isResizing = false
if (this.disableUserSelect) document.body.style.userSelect = this.tempUserSelect
document.removeEventListener('mousemove', onMouseMove)
}
},
lineEdgeCheck(obj) {
let isEdge = false
const parentDomPosition = obj.parentDom.getBoundingClientRect()
if (obj.lineKey === DARG_LINE.T_LINE)
isEdge = obj.clientY >= parentDomPosition.top + (this.safeDistance.top || 0)
if (obj.lineKey === DARG_LINE.B_LINE)
isEdge = obj.clientY <= parentDomPosition.bottom - (this.safeDistance.bottom || 0)
if (obj.lineKey === DARG_LINE.L_LINE)
isEdge = obj.clientX >= parentDomPosition.left + (this.safeDistance.left || 0)
if (obj.lineKey === DARG_LINE.R_LINE)
isEdge = obj.clientX <= parentDomPosition.right - (this.safeDistance.right || 0)
const isInRange =
(obj.sizeLimit[0] ? obj.curSize > obj.sizeLimit[0] : true) &&
(obj.sizeLimit[1] ? obj.curSize < obj.sizeLimit[1] : true)
return isInRange && isEdge
},
},
}
</script>
<style scoped lang="scss">
$hoverColor: #1d7dfa;
@mixin hoverBorder($property, $direction) {
&.border#{$direction} {
&:hover {
border-#{$property}: 1px dashed $hoverColor;
}
}
}
.main {
position: absolute;
width: fit-content;
height: fit-content;
.g-flex {
display: flex;
}
.resize-xy {
position: absolute;
right: 0;
bottom: 0;
z-index: 9;
width: 5px;
height: 5px;
cursor: se-resize;
}
}
.border-t {
@include hoverBorder(top, -t);
}
.border-b {
@include hoverBorder(bottom, -b);
}
.border-l {
@include hoverBorder(left, -l);
}
.border-r {
@include hoverBorder(right, -r);
}
.resize-x {
width: 5px;
cursor: e-resize;
}
.resize-y {
height: 5px;
cursor: s-resize;
}
</style>
使用示例
<!-- 竖表相关-->
<drag-resize-container
v-if="pillarDialogConfig.visible"
:parent-dom="dragParentDom"
:position-config="{left:'410px',top:0}"
style="background-color: rgba(232, 235, 244, 0.7);"
:max-width="900"
:min-height="300"
:width.sync="pillarDialogConfig.width"
:height.sync="pillarDialogConfig.height">
<template #content>
<PillarTable
:pillarRebarData="pillarRebarData"
:pillarRebarLoading="pillarRebarLoading"
:pillarTableTips="pillarTableTips"
:pillarTitle="pillarTitle"
@editPillarTableValue="editPillarTableValue"
@closePillarTable="pillarDialogConfig.visible = false"
></PillarTable>
</template>
</drag-resize-container>