Js高级技巧—拖放
拖放基本功能实现
拖放是一种非常流行的用户界面模式。它的概念很简单:点击某个对象,并按住鼠标按钮不放,将 鼠标移动到另一个区域,然后释放鼠标按钮将对象“放”在这里。拖放功能也流行到了 Web 上,成为 了一些更传统的配置界面的一种候选方案。 拖放的基本概念很简单:创建一个绝对定位的元素,使其可以用鼠标移动。这个技术源自一种叫做“鼠标拖尾”的经典网页技巧。鼠标拖尾是一个或者多个图片在页面上跟着鼠标指针移动。 单元素鼠标 拖尾的基本代码需要为文档设置一个 onmousemove 事件处理程序,它总是将指定元素移动到鼠标指针 的位置,如下面的例子所示
EventUtil.addHandler(document, "mousemove", function(event){ var myDiv = document.getElementById("myDiv"); myDiv.style.left = event.clientX + "px"; myDiv.style.top = event.clientY + "px";
});
在这个例子中,元素的 left 和 top 坐标设置为了 event 对象的 clientX 和 clientY 属性,这 就将元素放到了视口中指针的位置上。它的效果是一个元素始终跟随指针在页面上的移动。只要正确的 时刻(当鼠标按钮按下的时候)实现该功能,并在之后删除它(当释放鼠标按钮时),就可以实现拖放了。最简单的拖放界面可用以下代码实现:
var DragDrop = function(){ var dragging = null; function handleEvent(event){ //获取事件和目标event = EventUtil.getEvent(event); var target = EventUtil.getTarget(event); //确定事件类型switch(event.type){ case "mousedown": if (target.className.indexOf("draggable") > -1){ dragging = target; } break; case "mousemove": if (dragging !== null){ //指定位置dragging.style.left = event.clientX + "px"; dragging.style.top = event.clientY + "px"; } break; case "mouseup": dragging = null; break; } }; //公共接口return { enable: function(){ EventUtil.addHandler(document, "mousedown", handleEvent); EventUtil.addHandler(document, "mousemove", handleEvent); EventUtil.addHandler(document, "mouseup", handleEvent); },
disable: function(){ EventUtil.removeHandler(document, "mousedown", handleEvent); EventUtil.removeHandler(document, "mousemove", handleEvent); EventUtil.removeHandler(document, "mouseup", handleEvent); } }
}();
DragDrop 对象封装了拖放的所有基本功能。这是一个单例对象,并使用了模块模式来隐藏某些实 现细节。dragging 变量起初是 null,将会存放被拖动的元素,所以当该变量不为 null 时,就知道正在拖动某个东西。handleEvent()函数处理拖放功能中的所有的三个鼠标事件。它首先获取 event 对 象和事件目标的引用。之后,用一个 switch 语句确定要触发哪个事件样式。当 mousedown 事件发生时,会检target 的 class 是否包含"draggable"类,如果是,那么将 target 存放到 dragging 中。这个技巧可以很方便地通过标记语言而非 JavaScript 脚本来确定可拖动的元素。
handleEvent()的 mousemove 情况和前面的代码一样,不过要检查 dragging 是否为 null。当 它不是 null,就知道 dragging 就是要拖动的元素,这样就会把它放到恰当的位置上。mouseup 情况就仅仅是将 dragging 重置为 null,让 mousemove 事件中的判断失效。
DragDrop 还有两个公共方法:enable()和 disable(),它们只是相应添加和删除所有的事件处理程序。这两个函数提供了额外的对拖放功能的控制手段。
要使用 DragDrop 对象,只要在页面上包含这些代码并调用 enable()。拖放会自动针对所有包含 "draggable"类的元素启用,如下例所示:
<div class="draggable" style="position:absolute; background:red"> </div>
注意:为了元素能被拖放,它必须是绝对定位的。
修缮拖放功能
当你试了上面的例子之后,你会发现元素的左上角总是和指针在一起。这个结果对用户来说有一点 不爽,因为当鼠标开始移动的时候,元素好像是突然跳了一下。理想情况是,这个动作应该看上去好像 这个元素是被指针“拾起”的,也就是说当在拖动元素的时候,用户点击的那一点就是指针应该保持的 位置
要达到需要的效果,必须做一些额外的计算。你需要计算元素左上角和指针位置之间的差值。这个 差值应该在 mousedown 事件发生的时候确定,并且一直保持,直到 mouseup 事件发生。通过将 event 的 clientX 和 clientY 属性与该元素的 offsetLeft 和 offsetTop 属性进行比较,就可以算出水平方向和垂直方向上需要多少空间
为了保存 x 和 y 坐标上的差值,还需要几个变量。diffX 和 diffY 这些变量需要在 onmousemove 事件处理程序中用到,来对元素进行适当的定位,如下面的例子所示。
var DragDrop = function(){ var dragging = null; diffX = 0; diffY = 0; function handleEvent(event){ //获取事件和目标event = EventUtil.getEvent(event); var target = EventUtil.getTarget(event); //确定事件类型switch(event.type){ case "mousedown": if (target.className.indexOf("draggable") > -1){ dragging = target; diffX = event.clientX - target.offsetLeft; diffY = event.clientY - target.offsetTop; } break; case "mousemove": if (dragging !== null){ //指定位置dragging.style.left = (event.clientX - diffX) + "px"; dragging.style.top = (event.clientY - diffY) + "px"; } break; case "mouseup":
dragging = null; break; } }; //公共接口return { enable: function(){ EventUtil.addHandler(document, "mousedown", handleEvent); EventUtil.addHandler(document, "mousemove", handleEvent); EventUtil.addHandler(document, "mouseup", handleEvent); }, disable: function(){ EventUtil.removeHandler(document, "mousedown", handleEvent); EventUtil.removeHandler(document, "mousemove", handleEvent); EventUtil.removeHandler(document, "mouseup", handleEvent); } }
}();
diffX 和 diffY 变量是私有的,因为只有 handleEvent()函数需要用到它们。当 mousedown 事件发生时,通过 clientX 减去目标的 offsetLeft,clientY 减去目标的 offsetTop,可以计算到这两个变量的值。当触发了 mousemove 事件后,就可以使用这些变量从指针坐标中减去,得到最终的坐 标。最后得到一个更加平滑的拖动体验,更加符合用户所期望的方式。
添加自定义事件
拖放功能还不能真正应用起来,除非能知道什么时候拖动开始了。从这点上看,前面的代码没有提供任何方法表示拖动开始、正在拖动或者已经结束。这时,可以使用自定义事件来指示这几个事件的发生,让应用的其他部分与拖动功能进行交互。
由于 DragDrop 对象是一个使用了模块模式的单例,所以需要进行一些更改来使用 EventTarget类型。首先,创建一个新的 EventTarget 对象,然后添加 enable()和 disable()方法,最后返回这个对象。看以下内容。
var DragDrop = function(){ var dragdrop = new EventTarget(), dragging = null, diffX = 0, diffY = 0; function handleEvent(event){ //获取事件和对象event = EventUtil.getEvent(event); var target = EventUtil.getTarget(event); //确定事件类型switch(event.type){ case "mousedown": if (target.className.indexOf("draggable") > -1){ dragging = target; diffX = event.clientX - target.offsetLeft; diffY = event.clientY - target.offsetTop; dragdrop.fire({type:"dragstart", target: dragging, x: event.clientX, y: event.clientY}); } break; case "mousemove": if (dragging !== null){ //指定位置dragging.style.left = (event.clientX - diffX) + "px"; dragging.style.top = (event.clientY - diffY) + "px"; //触发自定义事件dragdrop.fire({type:"drag", target: dragging, x: event.clientX, y: event.clientY}); } break; case "mouseup": dragdrop.fire({type:"dragend", target: dragging, x: event.clientX, y: event.clientY}); dragging = null; break; } }; //公共接口dragdrop.enable = function(){ EventUtil.addHandler(document, "mousedown", handleEvent); EventUtil.addHandler(document, "mousemove", handleEvent); EventUtil.addHandler(document, "mouseup", handleEvent); }; dragdrop.disable = function(){ EventUtil.removeHandler(document, "mousedown", handleEvent); EventUtil.removeHandler(document, "mousemove", handleEvent); EventUtil.removeHandler(document, "mouseup", handleEvent); }; return dragdrop;
}();
这段代码定义了三个事件:dragstart、drag 和 dragend。它们都将被拖动的元素设置为了 target,并给出了 x 和 y 属性来表示当前的位置。它们触发于 dragdrop 对象上,之后在返回对象前给对象增加 enable()和 disable()方法。这些模块模式中的细小更改令 DragDrop 对象支持了事件,如下:
DragDrop.addHandler("dragstart", function(event){ var status = document.getElementById("status"); status.innerHTML = "Started dragging " + event.target.id;
});
DragDrop.addHandler("drag", function(event){ var status = document.getElementById("status"); status.innerHTML += "<br/> Dragged " + event.target.id + " to (" + event.x + "," + event.y + ")";
});
DragDrop.addHandler("dragend", function(event){ var status = document.getElementById("status"); status.innerHTML += "<br/> Dropped " + event.target.id + " at (" + event.x + "," + event.y + ")";
});
这里,为 DragDrop 对象的每个事件添加了事件处理程序。还使用了一个元素来实现被拖动的元素当前的状态和位置。一旦元素被放下了,就可以看到从它一开始被拖动之后经过的所有的中间步骤。
为 DragDrop 添加自定义事件可以使这个对象更健壮,它将可以在网络应用中处理复杂的拖放功能。
生活
这周一直都很忙,先是参观小组和招新宣讲会,之后是面试,中间参杂着学校官网的评比,视频项目后台进度几乎是0,连着好几天中午都没休息了,另外一个搭档也挺辛苦的,今天晚上的假期必须好好睡觉~
下周计划
首当其冲的肯定是项目了,下周要好好赶赶了。
当然啦,我也是有组员的人儿啦~。
感觉都很乖,都很好,也很看好他们,希望他们通过自己的努力,取得令自己满意的成绩,加油,追梦人!!
分享最近喜欢的一首歌儿 《GO GO GO GO》~~~~~~~~~~~~~~~
相关文章:

Js高级技巧—拖放
拖放基本功能实现 拖放是一种非常流行的用户界面模式。它的概念很简单:点击某个对象,并按住鼠标按钮不放,将 鼠标移动到另一个区域,然后释放鼠标按钮将对象“放”在这里。拖放功能也流行到了 Web 上,成为 了一些更传统…...

ELF和静态链接:为什么程序无法同时在Linux和Windows下运行?
目录 疑问 编译、链接和装载:拆解程序执行 ELF 格式和链接:理解链接过程 小结 疑问 既然我们的程序最终都被变成了一条条机器码去执行,那为什么同一个程序,在同一台计算机上,在 Linux 下可以运行,而在…...

【爬虫实战】python微博热搜榜Top50
一.最终效果 二.项目代码 2.1 新建项目 本文使用scrapy分布式、多线程爬虫框架编写的高性能爬虫,因此新建、运行scrapy项目3步骤: 1.新建项目: scrapy startproject weibo_hot 2.新建 spider: scrapy genspider hot_search "weibo.com" 3…...

【网络基础】——传输层
目录 前言 传输层 端口号 端口号范围划分 知名端口号 进程与端口号的关系 netstat UDP协议 UDP协议位置 UDP协议格式 UDP协议特点 面向数据报 UDP缓冲区 UDP的使用注意事项 基于UDP的应用层协议 TCP协议 TCP简介 TCP协议格式 确认应答机制&#…...

删除字符串特定的字符(fF)C语言
代码: #include <stdio.h> void funDel(char *str) {int i, j;for (i j 0; str[i] ! \0; i)if (str[i] ! f && str[i] ! F)str[j] str[i];str[j] \0; }int main() {char str[100];printf("请输入一个字符串:");gets(str);pr…...
C++入门(1):命名空间,IO流 输入输出,缺省参数
一、命名空间 1.1 命名空间的作用: 避免标识符命名冲突 1.2 命名空间定义: 关键字:namespace namespace test {// 命名空间内可以定义变量/函数/类型int a 10;int Add(int x, int y){return x y;}struct Stack{int* a;int top;int …...
Go 语言面试题(三):并发编程
文章目录 Q1 无缓冲的 channel 和 有缓冲的 channel 的区别?Q2 什么是协程泄露(Goroutine Leak)?Q3 Go 可以限制运行时操作系统线程的数量吗? Q1 无缓冲的 channel 和 有缓冲的 channel 的区别? 对于无缓冲的 channel,…...

Linux - make命令 和 makefile
make命令和 makefile 如果之前用过 vim 的话,应该会对 vim 又爱又恨吧,刚开始使用感觉非常的别扭,因为这种编写代码的方式,和在 windows 当中用图形化界面的方式编写代码的方式差别是不是很大。当你把vim 用熟悉的之后࿰…...

FPGA复习(功耗)
减小功耗 就得减小电流 电流和CF有关( C: 电容(被门数目和布线长度影响) F:时钟频率) 方法大纲 减小功耗:1 时钟控制 2输入控制 3减小供电电压 4双沿触发器 5修改终端 同步数字电路降低动态功耗:动态禁止…...

element ui el-table表格复选框,弹框关闭取消打勾选择
//弹框表格复选框清空 this.$nextTick(()>{this.$refs.table.clearSelection();})<el-table ref"table" v-loading"crud.loading" :header-cell-style"{ color: #FFF, background: #333 }":cell-style"{ color: #FFF, background: #3…...
数据结构——队列
1.队列元素逆置 【问题描述】 已知Q是一个非空队列,S是一个空栈。仅使用少量工作变量以及对队列和栈的基本操作,编写一个算法,将队列Q中的所有元素逆置。 【输入形式】 输入的第一行为队列元素个数,第二行为队列从首至尾的元素…...

【Unity引擎核心-Object,序列化,资产管理,内存管理】
文章目录 整体介绍Native & Managed Objects什么是序列化序列化用来做什么Editor和运行时序列化的区别脚本序列化针对序列化的使用建议 Unity资产管理导入Asset Process为何要做引擎资源文件导入Main-Assets和 Sub-Assets资产的导入管线Hook,AssetPostprocessor…...

Generics/泛型, ViewBuilder/视图构造器 的使用
1. Generics 泛型的定义及使用 1.1 创建使用泛型的实例 GenericsBootcamp.swift import SwiftUIstruct StringModel {let info: String?func removeInfo() -> StringModel{StringModel(info: nil)} }struct BoolModel {let info: Bool?func removeInfo() -> BoolModel…...

数据结构之手撕顺序表(增删查改等)
0.引言 在本章之后,就要求大家对于指针、结构体、动态开辟等相关的知识要熟练的掌握,如果有小伙伴对上面相关的知识还不是很清晰,要先弄明白再过来接着学习哦! 那进入正题,在讲解顺序表之前,我们先来介绍…...

进阶JAVA篇- ZoneId 类与 ZoneDateTime 类、Instant类的常用API(七)
目录 API 1.0 ZoneId 类的说明 1.1 如何创建 ZoneId 类的对象呢? 1.2 ZoneId 类中的 getAvailableZoneIds() 静态方法 2.0 ZoneDateTime 类的说明 2.1 如何创建 ZoneDateTime 类的对象呢? 3.0 Instant 类的说明 3.1 如何创建 Instant 类的对象呢…...
bat脚本字符串替换:路径中\需要替换,解决一些文件写入路径不对的问题
脚本 set dir_tmp%~dp0 set dir%dir_tmp:\\\\\% set dir_tmp%~dp0 新建一个变量dir_tmp,存储获取的脚本当前路径 set dir%dir_tmp:\\\\\% 新建一个变量dir ,存储字符串替换之后的路径 其中黄色的\\实际上代表的是一个\...

python一行命令搭建web服务,实现内网共享文件
python一行命令搭建web服务,实现内网共享文件 有时候我们在本地电脑访问自己的虚拟机的时候,可能因为某些原因无法直接CV文件到虚拟机。但此时我们又想上传文件到虚拟机,如果虚拟机和本地电脑可以互通。那么我们可以直接通过python来启动一个…...

RK3562开发板:升级摄像头ISP,突破视觉体验边界
RK3562开发板作为深圳触觉智能新推出的爆款产品,采用 Rockchip 新一代 64 位处理器 RK3562(Quad-core ARM Cortex-A53,主频最高 2.0GHz),最大支持 8GB 内存;内置独立的 NPU,可用于轻量级人工智能…...

数据结构与算法-队列
队列 🎈1.队列的定义🎈2.队列的抽象数据类型定义🎈3.顺序队列(循环队列)🔭3.1循环队列🔭3.1循环队列类定义🔭3.2创建空队列🔭3.3入队操作🔭3.4出队操作&#…...

腾讯云轻量2核4G5M可容纳多少人访问?
腾讯云2核4G5M服务器支持多少人在线访问?卡不卡?腾讯云轻量2核4G5M带宽服务器支持多少人在线访问?5M带宽下载速度峰值可达640KB/秒,阿腾云以搭建网站为例,假设优化后平均大小为60KB,则5M带宽可支撑10个用户…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...
【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15
缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下: struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...

MongoDB学习和应用(高效的非关系型数据库)
一丶 MongoDB简介 对于社交类软件的功能,我们需要对它的功能特点进行分析: 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具: mysql:关系型数据库&am…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...
React Native在HarmonyOS 5.0阅读类应用开发中的实践
一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...

【项目实战】通过多模态+LangGraph实现PPT生成助手
PPT自动生成系统 基于LangGraph的PPT自动生成系统,可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析:自动解析Markdown文档结构PPT模板分析:分析PPT模板的布局和风格智能布局决策:匹配内容与合适的PPT布局自动…...

c#开发AI模型对话
AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...

均衡后的SNRSINR
本文主要摘自参考文献中的前两篇,相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程,其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt 根发送天线, n r n_r nr 根接收天线的 MIMO 系…...

零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)
本期内容并不是很难,相信大家会学的很愉快,当然对于有后端基础的朋友来说,本期内容更加容易了解,当然没有基础的也别担心,本期内容会详细解释有关内容 本期用到的软件:yakit(因为经过之前好多期…...