打造新Web体验:如何在Vue 2项目中实现可拖动定位的悬浮按钮(代码版)


实现屏幕右侧可拖动的悬浮按钮

在现代的前端开发中,悬浮按钮广泛应用于各种场景。本文将介绍如何在 Vue 2 项目中实现一个固定在屏幕右侧、可垂直拖动的悬浮按钮。按钮拖动后会自动固定在屏幕的右侧,避免按钮超出屏幕范围,并配合抽屉组件实现快捷菜单功能。

功能需求

  1. 固定在屏幕右侧:按钮始终固定在屏幕的右侧,用户无法水平拖动按钮。
  2. 垂直拖动:用户可以自由拖动按钮在垂直方向上移动,并限制在屏幕上下边界内。
  3. 贴边显示:拖动结束后,按钮始终保持贴边显示。
  4. 抽屉菜单:点击按钮可打开抽屉,展示快捷菜单功能。

实现步骤

1. 创建悬浮按钮组件

首先,创建一个 Vue 组件用于实现悬浮按钮和抽屉功能。我们使用 element-ui 组件库来实现按钮和抽屉,并添加拖动和贴边逻辑。

<template>
  <div v-if="shouldShowButton">
    <!-- 小箭头按钮,控制悬浮按钮的显示和隐藏 -->
    <div
      v-if="!floatingButtonVisible"
      class="arrow-button"
      @click="toggleFloatingButton"
    >
      →
    </div>

    <!-- 悬浮按钮 -->
    <transition name="slide-fade">
      <el-button
        v-if="floatingButtonVisible"
        class="floating-button"
        type="primary"
        circle
        @mousedown="startDrag"
        @click="toggleDrawer"
        :style="{ top: `${buttonPosition.y}px`, right: `20px`, transition: isDragging ? 'none' : 'top 0.3s ease, right 0.3s ease' }"
      >
        {{ todoCount }}
      </el-button>
    </transition>

    <!-- 抽屉 -->
    <el-drawer
      v-model="drawerVisible"
      direction="rtl"
      size="50%"
      title="快捷菜单"
      @close="toggleDrawer"
    >
      <!-- 抽屉内容 -->
      <el-tabs type="border-card" style="min-height: 500px">
        <el-tab-pane label="我的待办" style="height:500px;overflow: auto;">
          <!-- 演示表格 -->
          <el-table
            :cell-style="{'text-align':'center'}"
            :data="demoData"
            :header-cell-style="{'text-align':'center'}"
            border
            table-layout="auto"
            class="table-style"
            highlight-current-row
          >
            <el-table-column label="示例列1" prop="column1"></el-table-column>
            <el-table-column label="示例列2" prop="column2"></el-table-column>
          </el-table>
        </el-tab-pane>
        <el-tab-pane label="已办" style="height:700px;overflow: auto;">
          <!-- 演示表格 -->
          <el-table
            :cell-style="{'text-align':'center'}"
            :data="demoData"
            :header-cell-style="{'text-align':'center'}"
            border
            table-layout="auto"
            highlight-current-row
            class="table-style"
          >
            <el-table-column label="示例列1" prop="column1"></el-table-column>
            <el-table-column label="示例列2" prop="column2"></el-table-column>
          </el-table>
        </el-tab-pane>
      </el-tabs>
    </el-drawer>
  </div>
</template>

<script>
export default {
  data() {
    return {
      drawerVisible: false,
      floatingButtonVisible: true,
      todoCount: 5, // 代办事项数量
      isDragging: false,
      buttonPosition: { y: window.innerHeight - 70 }, // 初始位置:右下角
      startY: 0,
      demoData: [
        { column1: "示例数据1", column2: "示例数据2" },
        { column1: "示例数据3", column2: "示例数据4" },
      ], // 演示数据
    };
  },
  computed: {
    shouldShowButton() {
      return !this.$route.path.includes("/login");
    },
  },
  mounted() {
    // 监听窗口大小变化
    window.addEventListener("resize", this.updateButtonPosition);
  },
  beforeDestroy() {
    // 在组件销毁时移除监听器
    window.removeEventListener("resize", this.updateButtonPosition);
  },
  methods: {
    toggleDrawer() {
      this.drawerVisible = !this.drawerVisible;
    },
    toggleFloatingButton() {
      this.floatingButtonVisible = !this.floatingButtonVisible;
    },
    startDrag(event) {
      this.isDragging = true;
      this.startY = event.clientY - this.buttonPosition.y;
      document.addEventListener("mousemove", this.onDrag);
      document.addEventListener("mouseup", this.stopDrag);
    },
    onDrag(event) {
      if (this.isDragging) {
        // 只允许垂直移动,限制范围在屏幕内
        let newY = event.clientY - this.startY;
        newY = Math.max(0, Math.min(newY, window.innerHeight - 50));
        this.buttonPosition.y = newY;
      }
    },
    stopDrag() {
      this.isDragging = false;
      document.removeEventListener("mousemove", this.onDrag);
      document.removeEventListener("mouseup", this.stopDrag);
    },
    updateButtonPosition() {
      // 当窗口调整大小时更新按钮位置,确保按钮不超出屏幕
      this.buttonPosition.y = Math.min(this.buttonPosition.y, window.innerHeight - 50);
    },
  },
};
</script>

<style scoped>
.floating-button {
  position: fixed;
  z-index: 1000;
  display: flex;
  justify-content: center;
  align-items: center;
  width: 50px;
  height: 50px;
  border-radius: 50%;
  transition: top 0.3s ease, right 0.3s ease;
  cursor: pointer;
  right: 20px; /* 固定在右侧 */
}

.arrow-button {
  position: fixed;
  right: 0;
  bottom: 20px;
  z-index: 1000;
  width: 20px;
  height: 50px;
  background-color: #409eff;
  color: white;
  display: flex;
  justify-content: center;
  align-items: center;
  border-radius: 0 10px 10px 0;
  cursor: pointer;
}

.slide-fade-enter-active,
.slide-fade-leave-active {
  transition: all 0.3s ease;
}

.slide-fade-enter,
.slide-fade-leave-to {
  transform: translateX(100%);
  opacity: 0;
}
</style>

2. 实现逻辑说明

  1. 固定右侧贴边: 悬浮按钮始终固定在屏幕右侧(通过 right: 20px;),用户无法水平拖动按钮,仅能在垂直方向上移动。

  2. 垂直移动: 在 onDrag 方法中,仅允许按钮在 y 轴上移动。通过限制 y 值,确保按钮不会超出屏幕上下边界。

  3. 贴边显示: 由于按钮始终固定在右侧,因此在用户停止拖动时按钮自动贴边。

  4. 抽屉菜单: 按钮的点击事件触发抽屉菜单的显示或隐藏,并展示了一些演示数据。

  5. 窗口大小调整: 在窗口大小发生变化时,通过 updateButtonPosition 方法动态调整按钮位置,确保按钮不会超出屏幕。

3. 总结

通过上述代码和实现逻辑,我们成功创建了一个固定在屏幕右侧且可垂直拖动的悬浮按钮。这个按钮在移动后始终贴边,并且结合抽屉组件实现了快捷菜单功能。在实际应用中,你可以根据项目需求进一步定制和扩展此功能。


希望这篇博客内容能够帮助你理解和实现类似的悬浮按钮功能。如有任何疑问或建议,欢迎在评论区留言讨论!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

饼干饿死了

三连和打赏总要留一个吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值