159 lines
3.3 KiB
Vue
159 lines
3.3 KiB
Vue
|
|
<template>
|
|||
|
|
<div class="drag-resize-panel" :class="{ 'vertical': direction === 'vertical' }">
|
|||
|
|
<div class="panel-a" :style="panelAstyle">
|
|||
|
|
<slot name="panelA"></slot>
|
|||
|
|
</div>
|
|||
|
|
<div class="resizer" :class="{ 'vertical-resizer': direction === 'vertical' }" @mousedown="startResize"></div>
|
|||
|
|
<div class="panel-b" :style="panelBstyle">
|
|||
|
|
<slot name="panelB"></slot>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</template>
|
|||
|
|
|
|||
|
|
<script>
|
|||
|
|
export default {
|
|||
|
|
name: 'DragResizePanel',
|
|||
|
|
props: {
|
|||
|
|
direction: {
|
|||
|
|
type: String,
|
|||
|
|
default: 'horizontal',
|
|||
|
|
validator: function(value) {
|
|||
|
|
return ['horizontal', 'vertical'].includes(value);
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
// 设置panelA的初始大小,最大值和最小值,默认值为300px,10000px,100px
|
|||
|
|
// panelB占据剩余空间
|
|||
|
|
initialSize: {
|
|||
|
|
type: Number,
|
|||
|
|
default: 300
|
|||
|
|
},
|
|||
|
|
minSize: {
|
|||
|
|
type: Number,
|
|||
|
|
default: 100
|
|||
|
|
},
|
|||
|
|
maxSize: {
|
|||
|
|
type: Number,
|
|||
|
|
default: 10000
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
data() {
|
|||
|
|
return {
|
|||
|
|
currentSize: this.initialSize,
|
|||
|
|
isResizing: false,
|
|||
|
|
startPosition: 0
|
|||
|
|
};
|
|||
|
|
},
|
|||
|
|
computed: {
|
|||
|
|
panelAstyle() {
|
|||
|
|
if (this.direction === 'horizontal') {
|
|||
|
|
return { width: this.currentSize + 'px' };
|
|||
|
|
} else {
|
|||
|
|
return { height: this.currentSize + 'px' };
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
panelBstyle() {
|
|||
|
|
if (this.direction === 'horizontal') {
|
|||
|
|
return { flex: 1 };
|
|||
|
|
} else {
|
|||
|
|
return { flex: 1 };
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
methods: {
|
|||
|
|
startResize(e) {
|
|||
|
|
e.preventDefault();
|
|||
|
|
this.isResizing = true;
|
|||
|
|
this.startPosition = this.direction === 'horizontal' ? e.clientX : e.clientY;
|
|||
|
|
this.startSize = this.currentSize;
|
|||
|
|
|
|||
|
|
document.addEventListener('mousemove', this.handleResize);
|
|||
|
|
document.addEventListener('mouseup', this.stopResize);
|
|||
|
|
},
|
|||
|
|
handleResize(e) {
|
|||
|
|
if (!this.isResizing) return;
|
|||
|
|
|
|||
|
|
const delta = this.direction === 'horizontal' ? e.clientX - this.startPosition : e.clientY - this.startPosition;
|
|||
|
|
const newSize = this.startSize + delta;
|
|||
|
|
|
|||
|
|
if (newSize >= this.minSize && newSize <= this.maxSize) {
|
|||
|
|
this.currentSize = newSize;
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
stopResize() {
|
|||
|
|
this.isResizing = false;
|
|||
|
|
document.removeEventListener('mousemove', this.handleResize);
|
|||
|
|
document.removeEventListener('mouseup', this.stopResize);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
<style scoped>
|
|||
|
|
.drag-resize-panel {
|
|||
|
|
display: flex;
|
|||
|
|
height: 100%;
|
|||
|
|
overflow: hidden;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.drag-resize-panel.vertical {
|
|||
|
|
flex-direction: column;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.panel-a {
|
|||
|
|
position: relative;
|
|||
|
|
overflow: hidden;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.panel-b {
|
|||
|
|
position: relative;
|
|||
|
|
overflow: auto;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.resizer {
|
|||
|
|
width: 4px;
|
|||
|
|
cursor: col-resize;
|
|||
|
|
position: relative;
|
|||
|
|
transition: background-color 0.3s;
|
|||
|
|
height: 100%;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.resizer.vertical-resizer {
|
|||
|
|
width: 100%;
|
|||
|
|
height: 4px;
|
|||
|
|
cursor: row-resize;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.resizer:hover {
|
|||
|
|
background-color: #409eff;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.resizer::before {
|
|||
|
|
content: '';
|
|||
|
|
position: absolute;
|
|||
|
|
top: 50%;
|
|||
|
|
left: 50%;
|
|||
|
|
transform: translate(-50%, -50%);
|
|||
|
|
height: 40px;
|
|||
|
|
width: 2px;
|
|||
|
|
background-color: #c0c4cc;
|
|||
|
|
border-radius: 1px;
|
|||
|
|
transition: background-color 0.3s;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.resizer.vertical-resizer::before {
|
|||
|
|
width: 40px;
|
|||
|
|
height: 2px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.resizer:hover::before {
|
|||
|
|
background-color: #409eff;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.resizer:active {
|
|||
|
|
background-color: #409eff;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.resizer:active::before {
|
|||
|
|
background-color: #fff;
|
|||
|
|
}
|
|||
|
|
</style>
|