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

一、最终效果

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

三、组件源码

html 复制代码
<template>
  <movable-area class="movable-area" @touchend="onTouchend">
    <movable-view class="movable-view" :x="x" :y="y" direction="all" @change="onChange">
      <view class="addBtn" @tap="handleClick">{{title}}</view>
      <slot />
    </movable-view>
  </movable-area>
</template>

<script lang="ts" setup>
import { debounce } from "@/utils";
defineProps({
  title: {
    type: String
  }
});
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再次封装基础组件文档

相关推荐
计算机学姐2 小时前
基于SpringBoot的汉服租赁系统【颜色尺码套装+个性化推荐算法+数据可视化统计】
java·vue.js·spring boot·后端·mysql·信息可视化·推荐算法
+VX:Fegn08952 小时前
计算机毕业设计|基于springboot + vue建筑材料管理系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
雪碧聊技术2 小时前
ElementPlus徽章组件:展示日期面板每天未完成的待办数量
vue.js·日期选择器·elementplus·el-badge徽章组件
沐墨染3 小时前
敏感词智能检索前端组件设计:树形组织过滤与多维数据分析
前端·javascript·vue.js·ui·数据挖掘·数据分析
xkxnq4 小时前
第二阶段:Vue 组件化开发(第 18天)
前端·javascript·vue.js
WebGISer_白茶乌龙桃4 小时前
Cesium实现“悬浮岛”式,三维立体的行政区划
javascript·vue.js·3d·web3·html5·webgl
计算机学姐4 小时前
基于SpringBoot的汽车租赁系统【个性化推荐算法+数据可视化统计】
java·vue.js·spring boot·后端·spring·汽车·推荐算法
不一样的少年_4 小时前
产品催: 1 天优化 Vue 官网 SEO?我用这个插件半天搞定(不重构 Nuxt)
前端·javascript·vue.js
BingoGo4 小时前
免费可商用商业级管理后台 CatchAdmin V5 正式发布 插件化与开发效率的全面提升
vue.js·后端·php
计算机徐师兄5 小时前
Java基于微信小程序的食堂线上预约点餐系统【附源码、文档说明】
java·微信小程序·食堂线上预约点餐系统小程序·食堂线上预约点餐微信小程序·java食堂线上预约点餐小程序·食堂线上预约点餐小程序·食堂线上预约点餐系统微信小程序