Vue3拖拽修改左侧元素宽度组件开发

       在开发过程中有时候会碰到需要拖拽修改页面元素宽度的需求,实际场景是页面上有并排两个或多个元素,需要拖拽修改其中一个元素的宽度,则只引入下方组件代替页面中需要被拖拽的元素及右侧相邻的元素。需要将需要拖拽的元素放进下面组件的左边的插槽中,右侧相邻的元素放入下方组件右侧的插槽中即可。

<template>
  <!-- 左侧元素 -->
  <el-aside
    ref="leftAsideRef"
    class="container__left border-right"
    width="260px"
    @mousemove="handleMousemove"
    @mousedown="handleMousedown"
    @mouseup="handleMouseup"
  >
    <slot name="left"></slot>
  </el-aside>

  <!-- 右侧元素 -->
  <el-aside
    ref="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,
    });

    // 左侧domRef
    const leftAsideRef = ref();
    // 右侧aside domRef
    const 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:none
        const leftChildList = leftAsideRef.value.$el.children;
        leftChildList.forEach((item: any) => {
          // eslint-disable-next-line no-param-reassign
          item.style.pointerEvents = 'none';
        });
        const rightChildList = rightAsideRef.value.$el.children;
        rightChildList.forEach((item: any) => {
          // eslint-disable-next-line no-param-reassign
          item.style.pointerEvents = 'none';
        });
      } else {
        leftAsideRef.value.$el.style.cursor = 'default';
        rightAsideRef.value.$el.style.cursor = 'default';
        // 第一把锁关闭之后,要将fixed-container子元素设置pointer-event:auto
        const leftChildList = leftAsideRef.value.$el.children;
        leftChildList.forEach((item: any) => {
          // eslint-disable-next-line no-param-reassign
          item.style.pointerEvents = 'auto';
        });
        const rightChildList = rightAsideRef.value.$el.children;
        rightChildList.forEach((item: any) => {
          // eslint-disable-next-line no-param-reassign
          item.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>

Vue中实现拖拽功能以调整三列元素宽度,通常可以使用第三方库如Vuedraggable或者vue-drag-resize。以下是一个简化的步骤: 1. 安装依赖:首先安装`vuedraggable`库,通过npm或yarn: ```bash npm install vuedraggable # 或者 yarn add vuedraggable ``` 2. 引入并配置draggable组件: ```html <template> <div id="app"> <draggable :items="columns" @start="dragStart" @end="dragEnd"> <div v-for="(column, index) in columns" :key="index" :style="{ width: column.width + &#39;%&#39; }"> {{ column.title }} <button @click="handleWidthChange(index)" class="drag-buttons">[{{ buttonLabel(index) }}]</button> </div> </draggable> </div> </template> <script> import draggable from &#39;vuedraggable&#39;; export default { components: { draggable, }, data() { return { columns: [ { title: &#39;Column 1&#39;, width: 33 }, { title: &#39;Column 2&#39;, width: 34 }, { title: &#39;Column 3&#39;, width: 33 }, ], currentDragIndex: null, }; }, methods: { dragStart(e, index) { this.currentDragIndex = index; }, dragEnd() { this.currentDragIndex = null; }, handleWidthChange(index) { const newWidth = // 根据当前操作计算新宽度; this.columns[index].width = newWidth; }, buttonLabel(index) { // 返回左右按钮的文字,比如 "Left" 或 "Right" return index === 0 ? &#39;左&#39; : (index === 2 ? &#39;右&#39; : &#39;&#39;); }, }, }; </script> ``` 在这个例子中,`vuedraggable`用于处理拖动操作,`handleWidthChange`方法负责根据点击的按钮调整相应列的宽度。你需要实现根据按钮位置(`buttonLabel`)确定是改变左边还是右边的列。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值