在开发过程中有时候会碰到需要拖拽修改页面元素宽度的需求,实际场景是页面上有并排两个或多个元素,需要拖拽修改其中一个元素的宽度,则只引入下方组件代替页面中需要被拖拽的元素及右侧相邻的元素。需要将需要拖拽的元素放进下面组件的左边的插槽中,右侧相邻的元素放入下方组件右侧的插槽中即可。
<template><!-- 左侧元素 --><el-asideref="leftAsideRef"class="container__left border-right"width="260px"@mousemove="handleMousemove"@mousedown="handleMousedown"@mouseup="handleMouseup"><slot name="left"></slot></el-aside><!-- 右侧元素 --><el-asideref="rightAsideRef"class="container__middle border-right"width="260px"@mousemove="handleMousemove"@mousedown="handleMousedown"@mouseup="handleMouseup"><slot name="right"></slot></el-aside>
</template><script lang="ts">
import { defineComponent, reactive, toRefs, ref, watch } from 'vue';export default defineComponent({name: 'DragChangeLeftWidth',props: {// 是否隐藏左边的元素hiddenLeft: {type: Boolean,default: false,},// 左侧元素可拖拽的最小宽度minWidth: {type: Number || String,default: 200,},// 左侧元素可拖拽的最大宽度maxWidth: {type: Number || String,default: 900,},},setup(props, { emit }) {const state = reactive({// 第一把锁控制鼠标形状改变resizableLock1: false,// 第二把锁控制是否可以拖拽resizableLock2: false,// 拖拽之前起始x坐标initialX: 0,// 拖拽之前起始宽度initialWidth: 0,});// 左侧domRefconst leftAsideRef = ref();// 右侧aside domRefconst rightAsideRef = ref();/*** @description: 左侧指标模块鼠标进入事件* @return {*}*/const handleMousemove = (e: any) => {// 现获取左侧dom 的左侧x轴坐标const rightXAxis = leftAsideRef.value?.$el.getBoundingClientRect()?.right;const leftXAxis = leftAsideRef.value?.$el.getBoundingClientRect()?.left;// 获取当前鼠标所在x轴的坐标const mouseXAxis = e.clientX;// 当鼠标从dom右侧进入5px距离之间时,修改鼠标样式if ((rightXAxis >= mouseXAxis && rightXAxis - mouseXAxis <= 10)|| (rightXAxis < mouseXAxis && mouseXAxis - rightXAxis <= 10)) {if (!state.resizableLock2) {// 只能先开启第一把锁state.resizableLock1 = true;}} else if (!state.resizableLock2) {// 将鼠标形状复原// 第二把锁不关第一把锁不能关state.resizableLock1 = false;}// 第一把锁控制鼠标变形if (state.resizableLock1) {leftAsideRef.value.$el.style.cursor = 'w-resize';rightAsideRef.value.$el.style.cursor = 'w-resize';// 打开第一把锁之后,要将fixed-container子元素设置pointer-event:noneconst leftChildList = leftAsideRef.value.$el.children;leftChildList.forEach((item: any) => {// eslint-disable-next-line no-param-reassignitem.style.pointerEvents = 'none';});const rightChildList = rightAsideRef.value.$el.children;rightChildList.forEach((item: any) => {// eslint-disable-next-line no-param-reassignitem.style.pointerEvents = 'none';});} else {leftAsideRef.value.$el.style.cursor = 'default';rightAsideRef.value.$el.style.cursor = 'default';// 第一把锁关闭之后,要将fixed-container子元素设置pointer-event:autoconst leftChildList = leftAsideRef.value.$el.children;leftChildList.forEach((item: any) => {// eslint-disable-next-line no-param-reassignitem.style.pointerEvents = 'auto';});const rightChildList = rightAsideRef.value.$el.children;rightChildList.forEach((item: any) => {// eslint-disable-next-line no-param-reassignitem.style.pointerEvents = 'auto';});}if (state.resizableLock2) {// 只有当可以进行拖拽的时候,才去清除鼠标默认事件e.preventDefault();// 第二把锁控制移动const updateWidth = e.clientX - state.initialX;// 超出最小值范围则不进行修改宽度操作,但是要更新初始宽度和初始x坐标if (rightXAxis - leftXAxis <= props.minWidth && updateWidth < 0) {state.initialX = e.clientX;state.initialWidth = leftAsideRef.value.$el.offsetWidth;return;}if (rightXAxis - leftXAxis >= props.maxWidth && updateWidth > 0) {state.initialX = e.clientX;state.initialWidth = leftAsideRef.value.$el.offsetWidth;return;}const newWidth = state.initialWidth + updateWidth;leftAsideRef.value.$el.style.width = `${newWidth}px`;}};/*** @description: 监听鼠标按下事件* @return {*}*/const handleMousedown = (e: any) => {if (state.resizableLock1) {// 只有当可以进行拖拽的时候,才去清除鼠标默认事件e.preventDefault();// 只有当第一把锁打开的时候,才能打开第二把锁state.resizableLock2 = true;}state.initialX = e.clientX;state.initialWidth = leftAsideRef.value.$el.offsetWidth;};/*** @description: 鼠标回弹触发事件* @return {*}*/const handleMouseup = () => {state.resizableLock2 = false;state.resizableLock1 = false;};return {...toRefs(state),leftAsideRef,rightAsideRef,handleTransitionend,handleMousemove,handleMousedown,handleMouseup,};},
});
</script>