效果
实现逻辑
- 监听鼠标按下事件,设置滑条背景色,left距离,记录初始位置,捕获鼠标
- 监听鼠标拖动事件,获取移动的距离,设置左侧区域与右侧区域的宽度,滑条的left值
- 监听鼠标松开事件,取消事件监听,恢复滑条背景色,释放鼠标
代码
<template>
<div :class="prefixCls">
<div ref="wrapRef" :class="`${prefixCls}-content`">
<div ref="leftRef" :class="`${prefixCls}-aside`">
<slot name="aside" />
</div>
<span ref="resizeRef" class="resize" />
<div ref="rightRef" :class="[`${prefixCls}-main`, $slots.aside && 'ml']">
<slot name="header" />
<div :class="`${prefixCls}-main-content`">
<slot />
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'Demo',
inheritAttrs: false
}
</script>
<script setup>
import { computed, onMounted, ref, unref, shallowRef } from 'vue'
const prefixCls = computed(() => 'page-layout')
const wrapRef = shallowRef()
const leftRef = ref()
const resizeRef = ref()
const rightRef = ref()
onMounted(() => dragController())
function dragController() {
const leftEleMinWidth = 271
const rightEleMinWidth = 500
unref(resizeRef).onmousedown = function(e) {
// 设置颜色
resizeRef.value.style.background = '#3D8BF2'
const startX = e.clientX
resizeRef.value.left = unref(resizeRef).offsetLeft
// 鼠标拖动
document.onmousemove = function({ clientX }) {
const endX = clientX
// 移动距离
let movingDistance = unref(resizeRef).left + (endX - startX)
// 右边区域宽度
const rightEleWidth = unref(wrapRef).clientWidth - unref(resizeRef).offsetWidth
// 拉伸的宽度不能小于左侧区域的宽度
if (movingDistance < leftEleMinWidth) movingDistance = leftEleMinWidth
// 判断最大宽度
if (movingDistance > rightEleWidth - rightEleMinWidth) movingDistance = rightEleWidth - rightEleMinWidth
// 设置左侧区域宽度
resizeRef.value.style.left = movingDistance
leftRef.value.style.width = movingDistance + 'px'
// 设置右侧区域宽度
rightRef.value.style.width = (unref(wrapRef).clientWidth - movingDistance - 10) + 'px'
}
// 鼠标松开
document.onmouseup = function() {
resizeRef.value.style.background = '#fff'
document.onmousemove = null
document.onmouseup = null
unref(resizeRef)?.releaseCapture?.()
}
unref(resizeRef)?.setCapture?.() // 设置鼠标捕获
return false
}
}
</script>
<style lang="scss">
.page-layout {
overflow: hidden;
display: flex;
width: 100%;
height: 100%;
&-content {
position: relative;
overflow: hidden;
flex: 1;
display: flex;
margin: 16px;
}
&-aside {
overflow: hidden;
width: 271px;
padding: 16px 0 16px 16px;
}
&-main {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
margin: 16px 16px 0;
background-color: white;
&-content {
flex: auto;
overflow: hidden;
padding-top: 16px;
}
}
.resize {
width: 5px;
margin: 16px 16px 11px 0;
cursor: w-resize;
background-color: #fff;
}
}
}
</style>