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: 后期会把做的编辑器开源,希望大家捧场。万分感谢!

相关推荐
遇见火星6 分钟前
Docker入门:快速部署你的第一个Web应用
前端·docker·容器
WeilinerL23 分钟前
泛前端代码覆盖率探索之路
前端·javascript·测试
浮游本尊26 分钟前
React 18.x 学习计划 - 第五天:React状态管理
前端·学习·react.js
-睡到自然醒~31 分钟前
[go 面试] 前端请求到后端API的中间件流程解析
前端·中间件·面试
洛卡卡了40 分钟前
Sentry 都不想接,这锅还让我背?这xx工作我不要了!
前端·架构
咖啡の猫44 分钟前
Vue 实例生命周期
前端·vue.js·okhttp
JNU freshman1 小时前
vue 之 import 的语法
前端·javascript·vue.js
剑亦未配妥1 小时前
Vue 2 响应式系统常见问题与解决方案(包含_demo以下划线开头命名的变量导致响应式丢失问题)
前端·javascript·vue.js
凉柚ˇ1 小时前
Vue图片压缩方案
前端·javascript·vue.js
慧一居士1 小时前
vue 中 directive 作用,使用场景和使用示例
前端