前端实战:实现块级元素的拖拽与缩放功能

在现代网页开发中,用户交互是一个非常重要的部分。在这篇文章中,我们将详细介绍如何使用原生 JavaScript 实现块级元素的拖拽与缩放功能。具体来说,我们将实现以下功能:

  1. 点击并拖动 outer 元素,可以移动整个块。
  2. 点击并拖动 inner 元素,可以调整 outer 元素的宽高。
    在这里插入图片描述

实现思路

为了实现上述功能,我们需要对两个元素分别进行事件监听和处理。具体来说,我们需要监听 mousedownmousemovemouseup 事件,并根据事件触发的位置和元素的状态,来决定执行拖动还是缩放操作。

HTML 结构

首先,我们定义两个块元素 outerinnerinner 位于 outer 的右下角,用于调整 outer 的大小。

<div id="outer" style="width: 100px; height: 100px; border: 1px solid black; position: relative;">
    <span id="inner" style="position: absolute; bottom: 0; right: 0; width: 10px; height: 10px; background: red; cursor: nwse-resize;"></span>
</div>

在这里插入图片描述

CSS 样式

简单的样式来定义块元素的尺寸和位置:

#outer {
    width: 100px;
    height: 100px;
    border: 1px solid black;
    position: relative;
}

#inner {
    position: absolute;
    bottom: 0;
    right: 0;
    width: 10px;
    height: 10px;
    background: red;
    cursor: nwse-resize;
}

JavaScript 实现

接下来,我们编写 JavaScript 代码,实现块的拖动和缩放功能。我们需要两个主要的事件处理程序,一个用于 outer 的拖动,另一个用于 inner 的缩放。

拖动功能

首先实现 outer 的拖动功能:

document.addEventListener('DOMContentLoaded', function() {
    const outer = document.getElementById('outer');
    let isDragging = false;
    let dragStartX, dragStartY, startLeft, startTop;

    outer.addEventListener('mousedown', function(e) {
        if (e.target === outer) {
            isDragging = true;
            dragStartX = e.clientX;
            dragStartY = e.clientY;
            startLeft = outer.offsetLeft;
            startTop = outer.offsetTop;
            document.addEventListener('mousemove', drag);
            document.addEventListener('mouseup', stopDrag);
        }
    });

    function drag(e) {
        if (isDragging) {
            const dx = e.clientX - dragStartX;
            const dy = e.clientY - dragStartY;
            outer.style.left = `${startLeft + dx}px`;
            outer.style.top = `${startTop + dy}px`;
        }
    }

    function stopDrag() {
        isDragging = false;
        document.removeEventListener('mousemove', drag);
        document.removeEventListener('mouseup', stopDrag);
    }
});

以下是实现拖动效果,此时还未实现缩放功能。
在这里插入图片描述

缩放功能

接下来实现 inner 的缩放功能:

document.addEventListener('DOMContentLoaded', function() {
    const outer = document.getElementById('outer');
    const inner = document.getElementById('inner');
    let isResizing = false;
    let resizeStartX, resizeStartY, startWidth, startHeight;

    inner.addEventListener('mousedown', function(e) {
        e.stopPropagation(); // 阻止事件冒泡到 outer
        isResizing = true;
        resizeStartX = e.clientX;
        resizeStartY = e.clientY;
        startWidth = outer.offsetWidth;
        startHeight = outer.offsetHeight;
        document.addEventListener('mousemove', resize);
        document.addEventListener('mouseup', stopResize);
    });

    function resize(e) {
        if (isResizing) {
            const dx = e.clientX - resizeStartX;
            const dy = e.clientY - resizeStartY;
            outer.style.width = `${startWidth + dx}px`;
            outer.style.height = `${startHeight + dy}px`;
        }
    }

    function stopResize() {
        isResizing = false;
        document.removeEventListener('mousemove', resize);
        document.removeEventListener('mouseup', stopResize);
    }
});

组合功能

为了确保两个功能可以同时存在,我们需要确保在 inner 被拖动时,outer 的拖动功能不会被触发。为此,我们在 innermousedown 事件处理程序中调用 e.stopPropagation(),以阻止事件冒泡到 outer

完整代码

以下是完整的实现代码,包括 HTML、CSS 和 JavaScript 部分:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>拖拽与缩放功能</title>
    <style>
        #outer {
            width: 100px;
            height: 100px;
            border: 1px solid black;
            position: absolute;
        }

        #inner {
            position: absolute;
            bottom: 0;
            right: 0;
            width: 10px;
            height: 10px;
            background: red;
            cursor: nwse-resize;
        }
    </style>
</head>
<body>
    <div id="outer">
        <span id="inner"></span>
    </div>

    <script>
        document.addEventListener('DOMContentLoaded', function() {
            const outer = document.getElementById('outer');
            const inner = document.getElementById('inner');
            let isDragging = false;
            let isResizing = false;
            let dragStartX, dragStartY, startLeft, startTop;
            let resizeStartX, resizeStartY, startWidth, startHeight;

            outer.addEventListener('mousedown', function(e) {
                if (e.target === outer) {
                    isDragging = true;
                    dragStartX = e.clientX;
                    dragStartY = e.clientY;
                    startLeft = outer.offsetLeft;
                    startTop = outer.offsetTop;
                    document.addEventListener('mousemove', drag);
                    document.addEventListener('mouseup', stopDrag);
                }
            });

            inner.addEventListener('mousedown', function(e) {
                e.stopPropagation(); // 阻止事件冒泡到 outer
                isResizing = true;
                resizeStartX = e.clientX;
                resizeStartY = e.clientY;
                startWidth = outer.offsetWidth;
                startHeight = outer.offsetHeight;
                document.addEventListener('mousemove', resize);
                document.addEventListener('mouseup', stopResize);
            });

            function drag(e) {
                if (isDragging) {
                    const dx = e.clientX - dragStartX;
                    const dy = e.clientY - dragStartY;
                    outer.style.left = `${startLeft + dx}px`;
                    outer.style.top = `${startTop + dy}px`;
                }
            }

            function stopDrag() {
                isDragging = false;
                document.removeEventListener('mousemove', drag);
                document.removeEventListener('mouseup', stopDrag);
            }

            function resize(e) {
                if (isResizing) {
                    const dx = e.clientX - resizeStartX;
                    const dy = e.clientY - resizeStartY;
                    outer.style.width = `${startWidth + dx}px`;
                    outer.style.height = `${startHeight + dy}px`;
                }
            }

            function stopResize() {
                isResizing = false;
                document.removeEventListener('mousemove', resize);
                document.removeEventListener('mouseup', stopResize);
            }
        });
    </script>
</body>
</html>

总结

通过本文的介绍和代码示例,我们成功实现了使用原生 JavaScript 实现块级元素的拖拽与缩放功能。在实际开发中,这种交互功能非常常见,并且对于提升用户体验非常有帮助。希望本文能够帮助你更好地理解事件处理和 DOM 操作。如果你有任何问题或建议,欢迎交流讨论。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/745892.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

GPT-5的即将登场

人工智能领域正经历着一场前所未有的变革&#xff0c;而其中大语言模型的进步尤为瞩目。继GPT-4取得巨大成功后&#xff0c;OpenAI即将推出的GPT-5被寄予厚望。作为新一代大语言模型&#xff0c;GPT-5在各个方面都有望实现显著突破。本文将探讨GPT-5的潜在特性、应用前景以及其…

基于Flask开发的前后端交互项目(可用于期末大作业) MySQL数据库 文件上传 Spider爬虫 Echarts可视化展示 JS动态

项目描述&#xff1a; 开发一个基于Flask框架开发的前后端交互项目&#xff0c;项目内容为 东京奥运会 。对各个需要填写的字段做了数据验证&#xff0c;非法信息会被JS拦截提醒不合法&#xff1b;还对未登录就访问做了拦截&#xff0c;阻止未登录就访问。 前端&#xff1a;HT…

优思学院|精益生产3大特征、5个步骤、8大浪费、10大工具

前言 精益生产作为一种先进的生产管理理念&#xff0c;起源于丰田汽车公司的生产方式&#xff0c;其核心在于消除浪费、优化流程&#xff0c;以最少的投入获取最大的产出。本文将详细解析精益生产的三大特征、五个步骤、八大浪费和十大工具&#xff0c;帮助读者深入理解这一理…

含着“金钥匙”出生,“凤凰”重塑骨科未来!

凤凰&#xff0c;作为中华传统文化中的神鸟&#xff0c;象征着吉祥、和谐与重生。而Phoenix&#xff08;凤凰&#xff09;&#xff0c;这个名字本身就带有传奇色彩。 2024年6月20日-23日&#xff0c;由中国医师协会、中国医师协会骨科医师分会主办&#xff0c;江苏省医师协会骨…

【openmpi】怎样使用openmpi并行运行python脚本?

创作日志&#xff1a; 装过一次openmpi&#xff0c;但是半年之后就忘记怎么用了&#xff0c;所以记录一下 1. 测试openmpi是否安装好 cd /home/xxxx/SnapHiC_Call_Loop/openmpi-4.1.6/examples make mpirun -np 4 hello_c得到如下输出就说明是装好的了 2. 没有导入路径的话导…

智能护栏碰撞监测系统:强化道路安全的智能守卫

智能护栏碰撞监测系统是提升道路安全、加强交通管理智能化的重要技术手段&#xff0c;其为道路安全带来的好处和安装的必要性体现在以下几个方面&#xff1a; 1. 即时事故响应&#xff1a;系统能够实时监测到护栏遭受的碰撞事件&#xff0c;几乎瞬间触发报警机制&#xff0c;将…

服务器如何实现SSH免密码登录?

目录 一、服务器和电脑的区别二、什么是SSH三、什么是免密码登录四、服务器如何实现SSH免密码登录 一、服务器和电脑的区别 服务器和电脑是两种不同类型的计算机系统&#xff0c;它们在设计、功能和用途上存在明显的区别。首先&#xff0c;从硬件配置上看&#xff0c;服务器通…

408计算机网络--物理层

一、物理层概述 物理层是干嘛使得&#xff1f; 物理层解决如何在连接各种计算机的传输媒体上传输数据比特流&#xff0c;而不是指具体的传输媒体。 物理层主要任务是确定与传输媒体接口有关的一些特性。定义标准可以理解为插排上的两孔三孔 机械特性&#xff1a;定义物理连接…

ONLYOFFICE8.1版本桌面编辑器的测评

首先我们先出示一下我们所测评官网的链接&#xff1a; ONLYOFFICE官网链接&#xff1a;ONLYOFFICE - 企业在线办公应用软件 | ONLYOFFICE 我们这款ONLYOFFICE8.1版本有这一下优点 1.解决PDF痛点 ONLYOFFICE在PDF编辑方面支持高亮显示、下划线和删除线、添加批注等功能&#…

vue3集成Echarts,自定义ToolBox时无法监听参数变化

问题描述 在vue中集成echart中自定义ToolBox工具的点击事件&#xff0c;并将里面的typeBar赋给data中的变量&#xff0c;随后用watch监听这个变量的变化&#xff0c;发现监听不到&#xff01;&#xff01;&#xff01;&#xff01; 解决方案&#xff1a;一直以为是watch不能监…

jenkins构建allure报java.io.IOException: Can‘t find allure commandline <null>

jenkins构建allure报错 java.io.IOException: Can’t find allure commandline 配置allure commandline&#xff0c;注意将地址放在bin上一层

链式结构二叉树练习

一.二叉树的前序遍历 想要输出所给值&#xff0c;就要先用数组将数据存储起来&#xff0c;所以这里我们单独创建一个前序遍历函数&#xff0c;将所要数据前序遍历并放入数组&#xff0c;代码如下&#xff1a; void preOrder(struct TreeNode* root, int* a, int* pi)//前序遍历…

鸿蒙开发系统基础能力:【@ohos.pasteboard (剪贴板)】

剪贴板 说明&#xff1a; 本模块首批接口从API version 6开始支持。后续版本的新增接口&#xff0c;采用上角标单独标记接口的起始版本。 导入模块 import pasteboard from ohos.pasteboard;属性 系统能力: 以下各项对应的系统能力均为SystemCapability.MiscServices.Pasteb…

2024车载测试还可以冲吗?

2024年已过接近1/4了&#xff0c;你是不是还在围观车载测试行业的发展&#xff1f;同时也在思考着&#xff1a;现在进入车载测试行业还来得及吗&#xff1f;如何高效学习车载测试呢&#xff1f; 我们先来了解一下车载测试行情发展&#xff0c;通过某大平台&#xff0c;我们获取…

解决pycharm安装dlib失败的问题

今天使用pycharm来学习opencv人脸识别库face-recognition的时候出现了一点小问题&#xff0c;在pycharm中直接安装face-recognition会失败&#xff0c;说是因为缺少依赖库dlib&#xff0c;但是直接使用pycharm安装dlib库也有问题&#xff0c;不知道大家遇到没有 错误提示 note…

Avue-data数据大屏显示饼图(附Demo)

目录 前言1. Sql查询2. 颜色细节 前言 对于这部分知识&#xff0c;原先有过柱状图实战&#xff1a;Avue-data数据大屏显示柱状图&#xff08;附Demo讲解&#xff09; 以下直奔主题&#xff0c;以Sql数据库数据为主 1. Sql查询 以饼图为例&#xff0c;需要返回的形式如下&am…

MySQL数据库切换瀚高数据库(PostgreSQL)导致SQL适配问题:BadSqlGrammarException

温馨提示&#xff1a; 下面的出现的情况属于层层递进的&#xff0c;如果只解决其中一种情况会接着报下一个情况&#xff0c;如果只想了解解决方案请直接移步至结论。 1. 情况一&#xff1a;ERROR: operator does not exist: smallint character varying 报错详细描述&#xf…

每日一学(1)

目录 1、ConCurrentHashMap为什么不允许key为null&#xff1f; 2、ThreadLocal会出现内存泄露吗&#xff1f; 3、AQS理解 4、lock 和 synchronized的区别 1、ConCurrentHashMap为什么不允许key为null&#xff1f; 底层 putVal方法 中 如果key || value为空 抛出…

python-登录界面-demo

文章目录 前言python-登录界面-demo 前言 如果您觉得有用的话&#xff0c;记得给博主点个赞&#xff0c;评论&#xff0c;收藏一键三连啊&#xff0c;写作不易啊^ _ ^。   而且听说点赞的人每天的运气都不会太差&#xff0c;实在白嫖的话&#xff0c;那欢迎常来啊!!! python-…

Wp-scan一键扫描wordpress网页(KALI工具系列三十)

目录 1、KALI LINUX 简介 2、Wp-scan工具简介 3、信息收集 3.1 目标IP&#xff08;服务器) 3.2kali的IP 4、操作实例 4.1 基本扫描 4.2 扫描已知漏洞 4.3 扫描目标主题 4.4 列出用户 4.5 输出扫描文件 4.6 输出详细结果 5、总结 1、KALI LINUX 简介 Kali Linux 是一…