Vue实现一个可以拖拽的工具栏

最近一直在做编辑器的小项目,怎么说呢?一个看起来非常简单的小工具也需要大量的巧思和优化。

其实我发现随随便便的一个小工具都有重新做一遍的价值,一来是符合新的使用习惯,二来新的UI风格也更顺眼。

现在AI编程真的是"害人不浅",比较难的功能随手Trea一下,直接代码就写好了,这简直是程序员的"盛夏"。

做编辑器的过程中发现一个复制的功能,放在工具栏需要两步操作,点击工具,然后再点击复制到哪个平台。

还是放出来比较合适,但是放在外层又有点儿遮挡,所以做了一个可以拖拽的工具栏。

源码

html 复制代码
<template>
    <div class="tool-copy-container" :style="toolPosition">
        <!-- 拖拽部分 -->
        <div class="tool-copy-drag" @mousedown="startDragging">
            <i class="iconfont icon-drag"></i>
        </div>

        <div class="tool-copy-item" v-for="(item, index) in tools" :key="index">
            <el-tooltip
                class="box-item"
                effect="dark"
                :content="'复制到' + item.name"
                placement="left"
            >
                <i class="iconfont" :class="item.icon" :style="{color: item.color}"></i>
            </el-tooltip>
        </div>
    </div>
</template>

<script setup>
import { reactive, ref } from "vue";

// 工具列表数据
const tools = reactive([
    {
        name: '公众号',
        title: 'wechat',
        icon: 'icon-wechat',
        color: '#07C874'
    },
    ......
]);

// 初始位置
const toolPosition = reactive({
    top: '300px',
    right: '20px'
});

// 拖拽相关状态
// 定义一个响应式的布尔变量,用于追踪是否正在拖动
const isDragging = ref(false);
// 定义一个响应式的对象,用于存储拖动偏移量
const dragOffset = reactive({
    x: 0,
    y: 0
});

/**
 * 开始拖动的函数
 * @param {MouseEvent} event - 触发的鼠标事件
 */
function startDragging(event) {
    isDragging.value = true;

    // 获取目标元素的位置信息
    const rect = event.target.getBoundingClientRect();
    // 计算鼠标点击位置相对于元素左上角的偏移量
    dragOffset.x = event.clientX - rect.left;
    dragOffset.y = event.clientY - rect.top;

    // 添加鼠标移动和释放事件监听器
    document.addEventListener('mousemove', onMouseMove);
    document.addEventListener('mouseup', onMouseUp);
}

/**
 * 鼠标移动时的处理函数
 * @param {MouseEvent} event - 触发的鼠标事件
 */
function onMouseMove(event) {
    if (!isDragging.value) return;

    // 计算新的鼠标位置,并减去初始偏移量
    const x = event.clientX - dragOffset.x;
    const y = event.clientY - dragOffset.y;

    // 设置新的位置
    toolPosition.top = `${y}px`;
    toolPosition.right = `${window.innerWidth - (x + rect().width)}px`;

    // 禁止文本选择,防止用户在拖动时选择页面内容
    document.body.style.userSelect = 'none';
}

/**
 * 鼠标释放时的处理函数
 */
function onMouseUp() {
    isDragging.value = false;
    // 移除鼠标移动和释放事件监听器
    document.removeEventListener('mousemove', onMouseMove);
    document.removeEventListener('mouseup', onMouseUp);
    // 恢复文本选择,允许用户选择页面内容
    document.body.style.userSelect = '';
}

/**
 * 获取工具容器的尺寸信息
 * @returns {DOMRect} - 元素的尺寸信息,如果没有找到元素则返回 { width: 0 }
 */
function rect() {
    const el = document.querySelector('.tool-copy-container');
    return el ? el.getBoundingClientRect() : { width: 0 };
}

</script>

<style scoped>
.tool-copy-container {
    background-color: #fff;
    border: 1px solid #ddd;
    position: fixed;
    top: 50%;
    right: 20px;
}

.tool-copy-drag {
    width: 100%;
    text-align: center;
    cursor: all-scroll;
}

.tool-copy-item {
    margin: 5px 0;
    text-align: center;
    padding: 0 5px;
    box-sizing: border-box;
    cursor: pointer;
}
</style>

原理

给要移动的DOM一个动态的style,通过绑定mousedown事件来触发拖动。

通过绑定mousemove事件来实时更新DOM位置,通过mouseup事件来结束拖动。

当然,这只是一个Demo,如果想要更好的效果还需要再优化。

Ps: 后期会把做的编辑器开源,希望大家捧场。万分感谢!

相关推荐
Amumu1213832 分钟前
NodeJs介绍
前端·node.js
咧咧小侠34 分钟前
Windows Codex 连接 Chrome 失败:一次 nodeRepl.fetch 报错排查记录
前端·chrome
Eider199836 分钟前
大模型输出格式幻觉解决思路
开发语言·前端·javascript
广州智造36 分钟前
Radioss时间步长(Time Step)
前端·设计·cad·建模·cae·radioss
志尊宝1 小时前
Vue3 零基础每日笔记(085):项目上线前 Checklist——环境变量、报错监控、安全自查
前端·javascript·笔记·安全·信息可视化·echarts
朱涛的自习室1 小时前
我让 Gemini 4 当高管、DeepSeek 当员工,开了一家软件公司(Day 1)
android·前端·人工智能
志尊宝1 小时前
Vue3 零基础每日笔记(088·完结):从零到一——一个完整 Vue3 项目的成长复盘
前端·javascript·vue.js·笔记·ecmascript·#vue.js
deli0071 小时前
加一台机器,为什么只有 1/N 的 key 要搬家?一致性哈希实测
前端
兔子零10241 小时前
FastAPI 零基础入门教程:写过 Node.js,就能轻松学会 Python 后端开发(一)
前端·后端·python
桔筐1 小时前
Vue中DOM的data-*自定义属性(dataset)与Vue data响应式变量区别详解
前端·javascript·vue.js