uniapp 微信小程序Vue3项目使用内置组件movable-area封装悬浮可拖拽按钮(拖拽结束时自动吸附到最近的屏幕边缘)

发布于:2025-07-16 ⋅ 阅读:(17) ⋅ 点赞:(0)

一、最终效果

在这里插入图片描述

二、具体详情请看movable-areamovable-view官方文档说明

三、参数配置

1、代码示例

<TFab title="新建订单" @click="addOrder" />
// title:表按钮文案
// addOrder:点击按钮事件

四、组件源码

<template>
  <movable-area class="movable-area" @touchend="onTouchend">
    <movable-view class="movable-view" :x="x" :y="y" direction="all" @change="onChange">
      <view class="addBtn" :style="{ width: `${width}px` , height: `${height}px`}" @tap="handleClick">{{title}}</view>
      <slot />
    </movable-view>
  </movable-area>
</template>

<script lang="ts" setup>
import { debounce } from "@/utils";
defineProps({
  title: {
    type: String
  },
   width: {
    type: Number,
    default: 40
  },
  height: {
    type: Number,
    default: 40
  }
});
const emits = defineEmits(["click"]);
const x = ref(0);
const y = ref(0);
const screenWidth = ref(0);
const screenHeight = ref(0);

onMounted(() => {
  uni.getSystemInfo({
    success: res => {
      screenWidth.value = res.windowWidth;
      screenHeight.value = res.windowHeight;
      // 初始位置在屏幕右下角
      y.value = screenHeight.value - 200;
      x.value = screenWidth.value - 70;
    }
  });
});
// 拖动坐标更新(防抖)
const onChange = (e: { detail: { x: number; y: number } }) => {
  debounce(() => {
    x.value = e.detail.x;
    y.value = e.detail.y;
  }, 500);
};
// 触摸结束时吸附边缘
const onTouchend = () => {
  nextTick(() => {
    const threshold = 50; // 吸附阈值(rpx)
    if (Math.abs(x.value - 0) < threshold) {
      x.value = 0;
    } else if (Math.abs(x.value - screenWidth.value) < threshold) {
      x.value = screenWidth.value;
    }
    if (Math.abs(y.value - 0) < threshold) {
      y.value = 0;
    } else if (Math.abs(y.value - screenHeight.value) < threshold) {
      y.value = screenHeight.value;
    }
  });
};
const handleClick = () => {
  emits("click");
};
</script>

<style lang="scss">
.movable-area {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: calc(100vh - 100px); // 可根据自己的项目来计算
  pointer-events: none; /* 关键样式 */
  z-index: 9999;
  .movable-view {
    pointer-events: auto; /* 关键样式 */
    width: 100rpx;
    height: 100rpx;
    will-change: transform;
    .addBtn {
      border-radius: 50%;
      width: 40px;
      height: 40px;
      overflow: hidden;
      display: flex;
      justify-content: center;
      align-items: center;
      color: #fff;
      font-size: 14px;
      padding: 8px;
      box-shadow: 0 1px 5px 2px rgba(0, 0, 0, 0.3);
      background: #355db4;
      text-align: center;
    }
  }
}
</style>

相关文章

基于ElementUi再次封装基础组件文档


vue3+ts基于Element-plus再次封装基础组件文档


网站公告

今日签到

点亮在社区的每一天
去签到