vue3 可拖动的左右面板分割组件实现

yizhihongxing

针对“vue3 可拖动的左右面板分割组件实现”的话题,我将为你提供详细的攻略,包含以下内容:

  1. 确定组件需求和功能
  2. 搭建基本的组件结构和布局
  3. 实现拖动效果
  4. 处理拖动边缘限制和动态宽度变化
  5. 实现完整功能

下面我们就来一步一步地讲解每个步骤,供你参考。

1. 确定组件需求和功能

我们的目标是创建一个可拖动的左右面板分割组件,使得用户可以自由拖动左右两个面板的宽度,以实现多种效果。具体功能如下:

  • 左右两个面板的宽度可以自由拖动调整,满足不同的排布需求;
  • 拖动过程中,两个面板的宽度比例可以自适应调整,并始终保持在一个合理的范围内;
  • 当拖动到最左边或最右边时,左或右面板不能再继续往左或右移动。

2. 搭建基本的组件结构和布局

在Vue3中,通常我们会使用单文件组件(SFC)来开发,因此我们需要创建一个名为SplitPane.vue的组件文件,并在里面添加模板,脚本和样式三个部分。

现在我们来定义组件模板,实现基本的布局效果:

<template>
  <div class="split-pane">
    <div class="split-pane__left" :style="{ width: leftWidth + '%'}"></div>
    <div class="split-pane__dragbar"></div>
    <div class="split-pane__right" :style="{ width: rightWidth + '%'}"></div>
  </div>
</template>

其中,我们定义了三个容器元素:split-pane、split-pane__left和split-pane__right,分别对应整个组件,左面板和右面板。我们还定义了一个分割条元素split-pane__dragbar,用于拖动调整面板宽度。

3. 实现拖动效果

现在我们开始实现拖动效果。我们可以在分割条上绑定一个mousedown事件,并在拖动条上添加一个“可拖动”类(dragging),以供后面调整样式用。同时,我们还需要绑定整个文档的mousemove和mouseup事件,以处理当鼠标移动或者松开时的拖动效果。

下面是代码示例:

<template>
  <div class="split-pane">
    <div class="split-pane__left" :style="{ width: leftWidth + '%'}"></div>
    <div class="split-pane__dragbar" @mousedown="handleMouseDown"></div>
    <div class="split-pane__right" :style="{ width: rightWidth + '%'}"></div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      dragging: false, // 是否在拖动中
      leftWidth: 50, // 左面板的宽度
      rightWidth: 50 // 右面板的宽度
    };
  },
  methods: {
    handleMouseDown() {
      // 绑定mousemove、mouseup事件
      document.addEventListener('mousemove', this.handleMouseMove);
      document.addEventListener('mouseup', this.handleMouseUp);
      // 添加拖动样式
      this.dragging = true;
      document.body.classList.add('dragging');
    },
    handleMouseMove(event) {
      if (this.dragging) {
        // 计算拖动的距离
        const dx = event.pageX - this.$refs.dragbar.offsetLeft;
        const totalWidth = this.$el.clientWidth;
        // 计算左右两个面板的宽度
        const leftWidth = ((this.leftWidth / totalWidth) * totalWidth + dx) / totalWidth * 100;
        const rightWidth = ((this.rightWidth / totalWidth) * totalWidth - dx) / totalWidth * 100;
        // 更新状态
        this.leftWidth = leftWidth > 0 ? leftWidth : 0;
        this.rightWidth = rightWidth > 0 ? rightWidth : 0;
      }
    },
    handleMouseUp() {
      // 解除事件绑定和拖动样式
      document.removeEventListener('mousemove', this.handleMouseMove);
      document.removeEventListener('mouseup', this.handleMouseUp);
      this.dragging = false;
      document.body.classList.remove('dragging');
    }
  }
};
</script>

<style scoped>
.split-pane {
  display: flex;
  height: 500px;
  overflow: hidden;
  position: relative;
}

.split-pane__left,
.split-pane__right {
  height: 100%;
  position: absolute;
  top: 0;
}

.split-pane__left {
  left: 0;
  background-color: #f0f0f0;
}

.split-pane__right {
  right: 0;
  background-color: #fff;
}

.split-pane__dragbar {
  height: 100%;
  width: 10px;
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  cursor: ew-resize;
}

.dragging {
  user-select: none;
  -moz-user-select: none;
  -webkit-user-select: none;
}
</style>

4. 处理拖动边缘限制和动态宽度变化

在第三步中,我们已经成功地实现了基本的拖动效果。但是,在实际操作中我们会发现,在拖动到左边沿或右边沿时,左侧或右侧的面板不会再继续移动,这是我们需要进行进一步处理的地方。

我们可以在handleMouseMove方法中添加如下代码,来限制拖动的最小和最大宽度:

const minLeftWidth = 0;
const maxRightWidth = 100;
const percentWidth = totalWidth / 100; // 计算总宽度的百分比

// 计算限制后的宽度
const left = leftWidth > minLeftWidth ? leftWidth : minLeftWidth;
const right = rightWidth > 0 ? (rightWidth < maxRightWidth ? rightWidth : maxRightWidth) : 0;

// 计算拖动后左、右面板的宽度,并进行相应的百分比转换
this.leftWidth = left / percentWidth;
this.rightWidth = right / percentWidth;

另外,我们可能还会发现一个问题:当拖动后,两个面板的宽度比例可能不会保持不变,这可能会导致排版效果不佳。解决这个问题的办法是在组件初始化的时候,根据初始比例计算出左右面板的宽度,随着拖动变化也可以根据新的比例计算出左右面板的宽度来进行动态更新。

5. 实现完整功能

现在我们已经实现了拖动效果并限制了左右面板的拖动边界,但我们的组件是静态的,无法响应外部的变化。因此,我们需要在SplitPane组件中添加一个props来允许外部传入初始的左右面板宽度比例,从而能够动态更新组件的状态。

同时,我们可以添加事件回调并在拖动状态发生改变时进行触发:

export default {
  props: {
    initLeftWidth: {
      type: Number,
      default: 50
    },
    initRightWidth: {
      type: Number,
      default: 50
    }
  },
  data() {
    return {
      dragging: false,
      leftWidth: this.initLeftWidth,
      rightWidth: this.initRightWidth
    };
  },
  mounted() {
    const totalWidth = this.$el.clientWidth;
    const percentWidth = totalWidth / 100;
    this.leftWidth = this.initLeftWidth / percentWidth;
    this.rightWidth = this.initRightWidth / percentWidth;
  },
  methods: {
    handleMouseMove(event) {
      // ...
      if (this.dragging) {
        // 计算拖动的距离
        const dx = event.pageX - this.$refs.dragbar.offsetLeft;
        const totalWidth = this.$el.clientWidth;
        // 计算左右两个面板的宽度
        const leftWidth = ((this.leftWidth / percentWidth) * totalWidth + dx) / totalWidth * 100;
        const rightWidth = ((this.rightWidth / percentWidth) * totalWidth - dx) / totalWidth * 100;
        // 计算限制后的宽度
        const minLeftWidth = 0;
        const maxRightWidth = 100;
        const left = leftWidth > minLeftWidth ? leftWidth : minLeftWidth;
        const right = rightWidth > 0 ? (rightWidth < maxRightWidth ? rightWidth : maxRightWidth) : 0;
        // 计算拖动后左、右面板的宽度,并进行相应的百分比转换
        this.leftWidth = left / percentWidth;
        this.rightWidth = right / percentWidth;
        // 触发事件回调
        this.$emit('dragging', this.leftWidth, this.rightWidth);
      }
    },
    handleMouseUp() {
      // ...
      this.$emit('draggend', this.leftWidth, this.rightWidth);
    }
  }
};

这样,我们就成功地实现了一个可拖动的左右面板分割组件,并且可以响应外部状态变化。接下来,我们可以在父组件中使用这个组件,并进行相应的事件调用。

下面提供一个示例代码供你参考:

<template>
  <div>
    <SplitPane ref="splitPane" :init-left-width="30" :init-right-width="70" @dragging="handleDragging" @dragend="handleDragEnd" />
  </div>
</template>

<script>
import SplitPane from './SplitPane.vue';

export default {
  components: {
    SplitPane
  },
  methods: {
    handleDragging(leftWidth, rightWidth) {
      console.log('正在拖动,当前状态:', leftWidth, rightWidth);
    },
    handleDragEnd(leftWidth, rightWidth) {
      console.log('拖动结束,最终状态:', leftWidth, rightWidth);
    }
  }
};
</script>

这里我们可以看到,我们实例化了一个SplitPane组件,并对其进行了一些props传递和事件监听。当我们拖动时,就可以看到SplitPane组件会动态地更新状态,并打印出事件回调的内容。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:vue3 可拖动的左右面板分割组件实现 - Python技术站

(0)
上一篇 2023年6月10日
下一篇 2023年6月10日

相关文章

  • 纯DIV+CSS实现圆角代码

    关于“纯DIV+CSS实现圆角代码”的攻略,我总结了以下几个步骤: 1. 用border-radius属性实现圆角 border-radius属性可以用于设置元素的圆角。这个属性接受一个或四个参数,分别代表四个角的圆角半径。 例如,以下CSS代码块设置了一个4个角都是5px的圆角效果: div { border-radius: 5px; } 示例:你可以在自…

    css 2023年6月10日
    00
  • 设置margin和padding为0可去掉DIV与DIV的空白

    在网页设计中,我们经常需要去掉 div 元素之间的空白,以使页面布局更加紧凑。下面是一个完整攻略,包含了如何使用 CSS 设置 margin 和 padding 为 0 可去掉 div 元素之间的空白的过程和两个示例说明。 CSS 如何设置 margin 和 padding 为 0 可去掉 div 元素之间的空白 我们可以使用 CSS 的 margin 和 …

    css 2023年5月18日
    00
  • 使用纯 CSS 创作一个渐变色动画边框

    使用纯 CSS 创作一个渐变色动画边框,通常需要遵循以下步骤: Step 1:创建 HTML 元素 首先,在 HTML 中创建一个元素,该元素将作为动画边框的容器,如下所示: <div class="border-container"></div> Step 2:添加样式 接下来,在 CSS 中添加一些样式,为动画…

    css 2023年6月10日
    00
  • 固定在网页右侧的浮动层实现代码

    实现在网页右侧浮动的层,使用的是position属性。 在HTML中创建浮动层 首先在HTML文件的<body>标签结束前添加如下代码 <div class="float-layer">Hello world</div> 其中,我们的浮动层被指定为float-layer。我们将在CSS部分设置其样式。 …

    css 2023年6月10日
    00
  • CSS特殊性、继承与层叠

    CSS特殊性、继承与层叠是CSS样式表的基础知识,理解这些概念对赋予网页以不同的样式非常重要。下面是本题要求的完整攻略: CSS特殊性 特殊性指的是选择器某个部分对样式表条目优先级的影响力。CSS规定了4个级别来计算特殊性,从左到右优先级依次降低: 内联样式(inline style) ID选择器 类选择器、属性选择器、伪类 标签选择器、伪元素 特殊性越高,…

    css 2023年6月9日
    00
  • CSS3 对过渡(transition)进行调速以及延时

    CSS3 提供了对过渡(transition)进行调速以及延时的功能,使元素的动画效果更加流畅和自然。在进行过渡调速以及延时时,需要借助两个 CSS 属性:transition-timing-function 和 transition-delay。 transition-timing-function transition-timing-function 用…

    css 2023年6月10日
    00
  • JQuery操作元素的css样式

    JQuery是一种流行的JavaScript库,它为开发人员提供了一个方便的方式来操作HTML和CSS。在此,我们将详细讲解JQuery如何操作元素的CSS样式。 1. 选取元素 要操作一个元素的CSS样式,必须先选取该元素。在JQuery中,选取元素的方式有很多。最基本的是使用元素的ID或类名。例如,$(‘#example’)将选取ID为“example”…

    css 2023年6月10日
    00
  • JS 仿腾讯发表微博的效果代码

    首先讲解一下JS仿腾讯发表微博的效果代码需要的知识点: 获取DOM元素及其属性值。使用document.getElementById()或document.querySelector()获取DOM元素,通过元素对象的value属性获取输入框的值,通过元素对象的innerHTML属性改变提示信息的内容。 利用按钮添加点击事件。通过给按钮元素对象绑定onclic…

    css 2023年6月10日
    00
合作推广
合作推广
分享本页
返回顶部