前端:拖动悬浮小窗

一、效果展示

二、代码

复制代码
<template>
  <div class="contents">
    <div 
      class="contents--menu" 
      :style="style"
      @mousedown="startDrag"
      @touchstart="startDrag"
      @mousemove="onDrag"
      @touchmove="onDrag"
      @mouseup="stopDrag"
      @touchend="stopDrag"
    >
      <m-button v-for="(item, index) in list" :key="index" @click="changeComponent(item)">{{item.name}}</m-button>
    </div>
    <component :is="activeComponent"></component>
  </div>
</template>
<script setup lang="ts">
  // const itemsButton = defineAsyncComponent(() => import('../items/button/index.vue'))
import itemsButton from '../items/button/index.vue'
import modulesButtons from '../modules/buttons/index.vue'
import modulesForm from '../modules/form/index.vue'
import modulesTable from '../modules/table/index.vue'
import pagesList from '../pages/list/index.vue'
const list = [
  { name: '按钮', component: itemsButton },
  { name: '按钮组', component: modulesButtons },
  { name: '表单', component: modulesForm },
  { name: '表格', component: modulesTable },
  { name: '列表', component: pagesList },
]
let activeComponent = ref(list[0].component)
const changeComponent = (item: any) => {
  activeComponent.value = item.component
}


const isDragging = ref(false);
const initialPosition = ref({ x: 0, y: 0 });
const currentPosition = ref({ x: 100, y: 100 }); // 初始位置

const style = computed(() => ({
  position: 'fixed' as const,
  left: `${currentPosition.value.x}px`,
  top: `${currentPosition.value.y}px`,
  cursor: isDragging.value ? 'grabbing' : 'grab',
  userSelect: 'none' as const,
}));

const startDrag = (e: MouseEvent | TouchEvent) => {
  e.preventDefault();
  isDragging.value = true;
  
  // 获取鼠标或触摸位置
  const clientX = e instanceof MouseEvent ? e.clientX : e.touches[0].clientX;
  const clientY = e instanceof MouseEvent ? e.clientY : e.touches[0].clientY;
  
  // 计算鼠标位置与元素左上角的偏移量
  initialPosition.value = {
    x: clientX - currentPosition.value.x,
    y: clientY - currentPosition.value.y
  };
};

const onDrag = (e: MouseEvent | TouchEvent) => {
  if (!isDragging.value) return;
  
  e.preventDefault();
  
  // 获取当前鼠标或触摸位置
  const clientX = e instanceof MouseEvent ? e.clientX : e.changedTouches[0].clientX;
  const clientY = e instanceof MouseEvent ? e.clientY : e.changedTouches[0].clientY;
  
  // 计算新位置
  currentPosition.value = {
    x: clientX - initialPosition.value.x,
    y: clientY - initialPosition.value.y
  };
};

const stopDrag = () => {
  isDragging.value = false;
};
</script>
<style scoped lang="scss">
.contents{
  &--menu{
    z-index: 20;
    border-radius: 8px;
    width: 200px;
    border: 2px solid #ccc;
    padding: 15px;
    background-color: #f9f9f9;
    border-radius: 4px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
    transition: box-shadow 0.2s;
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    
    &:hover {
      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
    }
    
    &.dragging {
      z-index: 9999;
    }
    .el-button+.el-button{
      margin: 0;
    }
  }
}
</style>
相关推荐
ComputerInBook几秒前
C++ 17 相比 C++ 14 新增之特征
开发语言·c++·c++ 17
KaMeidebaby1 分钟前
卡梅德生物技术快报|噬菌体筛选全流程技术方案:弧菌抑菌菌株筛选、特性鉴定与效果测试
前端·数据库·其他·百度·新浪微博
我命由我123456 分钟前
Android Framework P2 - 开机启动 Zygote 进程、Zygote 的预加载机制
android·java·开发语言·python·java-ee·intellij-idea·zygote
JAVA面经实录9179 分钟前
Java Codex 企业标准Prompt库
java·开发语言·prompt
Evand J15 分钟前
【MATLAB例程】5个UAV 分布式围捕编队运动仿真 —— 基于PID控制
开发语言·分布式·matlab
m0_5027249515 分钟前
golang 、java、c++、javascript 语言switch case异同
java·javascript·c++·golang
JiaWen技术圈38 分钟前
主流非 JWT 式 Access Token 方案
前端·安全
落羽的落羽42 分钟前
【项目】C++从零实现JsonRpc框架——项目引入
linux·服务器·开发语言·c++·人工智能·算法·机器学习
墨月白43 分钟前
【Python】程序设计基本方法
开发语言·python
TAN-90°-1 小时前
Java 5——final 抽象 接口
java·开发语言