提示:目前很多写法都是用js实现左右拖拽,但当dom一多,还是会影响性能,所以我选择用css实现左右拖拽
1、效果图
左右俩个组件中的那条线可以实现左右拖拽,然后左侧有最小宽度
2、组件源码
<template>
<div
ref="collapseContainer"
class="collapse-container"
>
<!-- css实现拖拽时候,左侧高度必须为实际像素值 -->
<div
class="left"
:style="{
height: maxHeight + 'px'
}"
>
<div
ref="resizeBar"
class="resize-bar"
:style="{
'--min-width': minWidth + 'px',
width: width + 'px'
}"
/>
<div class="resize-line" />
<div
v-show="width > minExistWidth"
class="left-conatiner"
:style="{
width: (width === minWidth ? minWidth : width) - 3 + 'px'
}"
>
<slot name="left" />
</div>
</div>
<div
v-show="width < (maxWidth - minExistWidth)"
class="right right-container"
>
<slot name="right" />
</div>
</div>
</template>
<script>
export default {
name: 'Collapse',
props: {
/** 左侧最小宽度 */
minWidth: {
type: Number,
default: 300
}
},
data() {
return {
width: this.minWidth,
maxWidth: 0,
minExistWidth: 5,
maxHeight: 0
}
},
watch: {
minWidth: {
handler(val) {
setTimeout(() => {
this.maxWidth = this.$refs['collapseContainer'].offsetWidth;
this.maxHeight = this.$refs['collapseContainer'].offsetHeight;
this.width = val;
})
},
immediate: true
}
},
mounted() {
const observerOptions = {
childList: false, // 观察目标子节点的变化,是否有添加或者删除
attributes: true, // 观察属性变动
subtree: false // 观察后代节点,默认为 false
};
const mutationObserver = new MutationObserver((entries) => {
// 当DOM元素的宽高发生变化时执行回调函数
this.handleResize(entries[0].target);
});
mutationObserver.observe(this.$refs.resizeBar, observerOptions);
// 组件销毁时停止观察
this.$once('hook:beforeDestroy', () => {
mutationObserver.disconnect();
});
},
methods: {
/**
* 监听dom大小改变
* @param {*} dom
*/
handleResize(dom) {
this.width = dom.offsetWidth;
},
/**
* 主动折叠/收缩
* true => 展开左侧, false => 收缩左侧
* @param {*} direction
*/
collapse(direction) {
if (direction) {
this.width = this.maxWidth - this.minExistWidth;
} else {
this.width = this.minExistWidth;
}
}
}
}
</script>
<style lang="scss">
.collapse-container {
width: 100%;
height: 100%;
overflow: hidden;
.left {
background-color: #fff;
position: relative;
float: left;
.left-conatiner {
position: absolute;
top: 0;
right: 5px;
bottom: 0;
left: 0;
overflow-x: hidden;
}
.resize-bar {
height: inherit;
resize: horizontal;
opacity: 0;
cursor: ew-resize;
// cursor: col-resize;
overflow: scroll;
width: var(--min-width);
}
.resize-line {
position: absolute;
right: 0;
top: 0;
bottom: 0;
border-right: 2px solid #eee;
border-left: 1px solid #eee;
pointer-events: none;
}
.resize-bar:hover ~ .resize-line,
.resize-bar:active ~ .resize-line {
border-left: 1px dashed #fff;
}
.resize-bar::-webkit-scrollbar {
width: var(--min-width);
height: inherit;
}
}
.right {
height: 100%;
box-sizing: border-box;
overflow: hidden;
}
}
</style>
3、组件调用方式
<Collapse ref="collapse" :min-width="minWidth">
<div slot="left" style="height: 100%;">
xxxxx
</div>
<div slot="right" style="height: 100%;">
xxxxx
</div>
</Collapse>
// 主动实现折叠收缩方法
this.$refs['collapse'].collapse(true | false)
4、疑难解答
1、左右滚动的效果,是怎么出来的?
resize-bar 这个类 overflow设置为scroll,并且左侧内容区宽度和滚动条dom宽度一致,以此来实现拖动控制宽度
2、minExistWidth为啥要设置?
因为不设置的话,主动调用折叠收缩将直接将另一侧宽度设置为0,那将无法将被折叠的dom再次拖拽了,当然此值可以根据你想要的来设置
3、css实现拖拽时候,为什么左侧高度必须为实际像素值?
因为不设置实际像素值的话,那拖拽滚动条的位置 只能在dom偏上方,而不能实现在滚动条任意位置拖拽