发布时间:2024-11-28 16:01
<template>
<div class=\"container\">
<div class=\"resizable-container\" v-panel-resize:vertical=\"handleResize\">
<div class=\"item item-1 wrapper\" weight=\"0.3\">1div>
<div class=\"item item-2 wrapper\" weight=\"0.35\">2div>
<div class=\"item item-3 wrapper\" weight=\"0.35\">3div>
div>
div>
template>
<script>
import PanelResize from \'@/directive/resizer\'
export default {
directives: {
PanelResize
},
data: () => ({
}),
mounted() {
},
methods: {
handleResize(weights) {
console.log(weights)
}
}
};
</script>
<style lang=\"scss\">
.resizable-container {
display: flex;
flex: 1;
flex-direction: column;
align-items: stretch;
min-width: 0;
min-height: 0;
height: 100%;
&.horizontal {
flex-direction: row;
}
.wrapper {
display: flex;
flex: 1;
flex-direction: column;
align-items: stretch;
overflow: hidden;
min-width: 20px;
min-height: 20px;
&.horizontal {
flex-direction: row;
}
}
}
.ide-divider {
position: absolute;
z-index: 97;
&:after {
position: absolute;
background-color: #505050;
content: \"\";
}
&.horizontal {
right: 0;
top: 0;
width: 7px;
height: 100%;
margin: 0 -3px;
cursor: ew-resize;
&:after {
top: 0;
bottom: 0;
left: 3px;
width: 1px;
}
}
&.vertical {
left: 0;
bottom: 0;
width: 100%;
height: 7px;
margin: -3px 0;
cursor: ns-resize;
&:after {
left: 0;
right: 0;
top: 3px;
height: 1px;
}
}
}
.container {
width: 400px;
height: 450px;
margin: 50px auto;
border: 2px solid rgb(18, 78, 243);
}
.item {
}
.item-1 {
background-color: pink;
}
.item-2 {
background-color: palegoldenrod;
}
.item-3 {
background-color: peachpuff;
}
style>
import { hasClass } from \"../../utils\";
const resizer = {
bind(el, binding) {
binding.arg = binding.arg || \'vertical\'
const handleResizer = typeof binding.value === \'function\' ? binding.value : () => {}
const getChildren = (el) => {
let childs = el.childNodes || []
let children = []
childs.forEach(child => {
if (child.nodeType === 1 && !hasClass(child, \'ide-divider\') && child.hasAttribute(\'weight\')) {
children.push(child)
}
})
return children
}
const createDivider = (el, binding) => {
el.style.position = \'relative\'
let divider = document.createElement(\'div\')
divider.setAttribute(\'class\', \'ide-divider \' + binding.arg)
el.appendChild(divider)
return divider
}
const handleResize = (targetElement, clientX, clientY, index, nextIndex, weights) => {
const horizontal = binding.arg === \'horizontal\' ? true : false;
const { left, top } = targetElement.getBoundingClientRect();
const { offsetWidth, offsetHeight } = targetElement;
const position = horizontal ? clientX - left : clientY - top;
const containerSize = horizontal ? offsetWidth : offsetHeight;
/**
* 1.计算总共的比重
* 2.计算resize前,当前容器它之前的容器比重之和
*/
let totalWeight = 0;
let subtotalWeight = 0;
weights.forEach((weight, i) => {
totalWeight += weight;
if (i < nextIndex) subtotalWeight += weight;
});
// console.log(\'totalWeight\', totalWeight, subtotalWeight, index)
/**
* 计算resize后的新比重
*
* newWeight position
* ———————————— = ————————————————
* totalWeight containerSize
*/
const newWeight = (position / containerSize) * totalWeight;
let deltaWeight = newWeight - subtotalWeight;
/**
* 能调整的最大最小的比重
*/
deltaWeight = Math.max(deltaWeight, -weights[index]);
deltaWeight = Math.min(deltaWeight, weights[nextIndex]);
/**
* 前一个容器 +=
* 当前容器 -=
*/
weights[index] += deltaWeight;
weights[nextIndex] -= deltaWeight;
return weights
}
let target
const handleMouseDown = (e) => {
target = e.target
e.preventDefault()
document.addEventListener(\'mousemove\', handleMouseMove, false)
document.addEventListener(\'mouseup\', handleMouseUp, false)
}
const handleMouseMove = (e) => {
let dx = e.clientX
let dy = e.clientY
let children = getChildren(el)
let weights = []
let index = 0, nextIndex
children.forEach((child, i) => {
let weight = +(child.getAttribute(\'weight\') || (1 / children.length))
weights.push(weight)
if (target && target.parentElement === child) {
index = i
nextIndex = i + 1
}
})
let newWeights = handleResize(el, dx, dy, index, nextIndex, weights)
children.forEach((child, i) => {
let weight = newWeights[i]
child.style.flexGrow = weight
child.setAttribute(\'weight\', weight)
})
handleResizer(weights)
}
const handleMouseUp = () => {
target = null
document.removeEventListener(\'mousemove\', handleMouseMove)
document.removeEventListener(\'mouseup\', handleMouseUp)
}
const init = () => {
if (!el) {
return
}
const children = getChildren(el)
// console.log(\'children\', children)
children.forEach((child, index) => {
let weight = +(child.getAttribute(\'weight\') || (1 / children.length))
child.style.flexGrow = weight
if (index < children.length - 1) {
let divider = createDivider(child, binding)
divider.addEventListener(\'mousedown\', handleMouseDown, false)
}
})
}
init()
}
}
resizer.install = Vue => Vue.directive(\'panel-resize\', resizer)
export default resizer