实战:基于 HTML5 规范的元素拖拽实现指南)
编程语言语言运行时编译器前端【免费下载链接】brythonBrython (Browser Python) is an implementation of Python 3 running in the browser项目地址https://gitcode.com/gh_mirrors/br/brython点击查看免费下载导读本文基于 Brython 官方 Cookbook 中的拖放示例法文版、英文版系统讲解如何在浏览器中用 Python 实现元素的拖放交互。BrythonBrowser Python是在浏览器中运行的 Python 3 实现它把 HTML5 的拖放 API 封装成贴合 Python 习惯的接口。读完本文你将掌握dragstart/dragover/drop三个核心事件的回调绑定、通过dataTransfer在拖放过程中传递数据、以及用unbind卸载事件回调的完整套路可直接照搬到自己的页面项目中。问题在网页上拖放一个元素拖放Drag and Drop是网页交互中的常见需求用户按住一个元素源把它移动到另一个区域目标松开鼠标完成放置。在 Brython 中实现这一行为并不需要写一行 JavaScript——全部逻辑都可以用 Python 表达由 Brython 运行时负责与浏览器底层 API 对接。解决方案基于 HTML5 规范的 Brython 拖放 APIBrython 实现了一套基于 HTML5 拖放规范的 API详见官方事件文档 drag_events.md。在本文示例的基础形态下只需要为 3 个事件定义回调函数事件绑定的元素触发时机dragstart可拖动的源元素用户开始拖动该元素时dragover目标区域被拖动的元素移动到目标区域上方时drop目标区域用户松开鼠标完成放置时把回调函数callback绑定到元素element的某个event上使用的方法是element.bind(event, callback)注原文档正文用斜体表示的_event_、_element_、_rappel_等标识符在代码中即对应事件名如dragstart、元素对象DOMNode实例与回调函数。回调函数的签名与数据传递每个回调函数只接收一个参数一个DOMEvent实例即浏览器原生事件对象的 Brython 封装。为了在拖放过程中传递信息该实例带有一个dataTransfer属性在dragstart回调中通过ev.dataTransfer.setData(text, 值)写入数据在drop回调中通过ev.dataTransfer.getData(text)读取数据从而识别当前被放置的是哪个元素。这一机制对应 HTML5 规范中的DataTransfer对象setData/getData负责携带数据effectAllowed声明源元素允许的操作如movedropEffect声明目标区域最终采用的操作效果。官方文档 drag_events.md 对此有更完整的字段说明例如对dragstart、drag、dragleave事件dropEffect初始为none且赋值不生效对drop、dragend事件dropEffect会被初始化为最后一次dragover结束时设定的值。放置后禁止再次拖动unbind示例中还演示了一个常见业务规则对象被放置后就不能再被拖动。做法是通过element.unbind(event)移除该元素上已绑定的回调elt.unbind(mouseover)完整示例把红色方块拖入绿色区域下面是原文档的完整可运行代码HTML 中通过exec_on_load指令在页面加载时执行。先把两个块定位在黄色面板内红色块为可拖动对象绿色块为放置目标。div stylewidth:400px;height:150px;background-color:yellow idpanel div iddest styleposition:absolute;width:180px;height:80px;background-color:green;color:white;zone de destination/div div idsource styleposition:absolute;width:80px;height:40px;background-color:red;objet déplaçable/div /divfrom browser import document panel document[panel] # zone jaune source document[source] # zone rouge # on la place à (10, 10) du bord supérieur gauche du panel source.style.top {}px.format(10 panel.abs_top) source.style.left {}px.format(10 panel.abs_left) # rend la zone rouge déplaçable source.draggable True dest document[dest] # zone verte # on la place à (10, 150) du bord supérieur gauche du panel dest.style.top {}px.format(10 panel.abs_top) dest.style.left {}px.format(150 panel.abs_left) # coordonnées de la souris relativement au bord supérieur gauche de lobjet # déplacé quand le glissement commence m0 [None, None] def mouseover(ev): Quand la souris passe sur lobjet déplaçable, changer le curseur. print(voilà la souris !) ev.target.style.cursor pointer source.bind(mouseover, mouseover) def dragstart(ev): Fonction appelée quand lutilisateur commence à déplacer lobjet. global m0 # calcul des coordonnées de la souris # ev.x et ev.y sont les coordonnées de la souris quand lévénement est déclenché # ev.target est lobjet déplacé. Ses attributs left et top sont des entiers, # la distance par rapport aux bords gauche et supérieur du document m0 [ev.x - ev.target.left, ev.y - ev.target.top] # associer une donnée au processus de glissement ev.dataTransfer.setData(text, ev.target.id) # permet à lobject dêtre déplacé dans lobjet destination ev.dataTransfer.effectAllowed move source.bind(dragstart, dragstart) def dragover(ev): Fonction appelée quand lobjet déplaçable vient au-dessus de la zone de destination. ev.dataTransfer.dropEffect move # il faut désactiver le comportement par défaut pour ce genre dévénement ev.preventDefault() dest.bind(dragover, dragover) def drop(ev): Fonction attachée à la zone de destination. Elle définit ce qui se passe quand lobjet est déposé, cest-à-dire quand lutilisateur relâche la souris alors que lobjet est au-dessus de la zone. # récupère les données stockées dans drag_start (lid de lobjet déplacé) src_id ev.dataTransfer.getData(text) elt document[src_id] # définit les nouvelles coordonnées de lobjet déplacé elt.style.left {}px.format(ev.x - m0[0]) elt.style.top {}px.format(ev.y - m0[1]) # ne plus déplacer lobjet elt.draggable False # enlever la fonction associée à mouseover elt.unbind(mouseover) elt.style.cursor auto ev.preventDefault() dest.bind(drop, drop)逐段拆解代码背后的关键机制1. 元素定位abs_top与abs_left示例没有使用 CSS 静态定位而是用panel.abs_top和panel.abs_left获取面板左上角相对文档的绝对坐标再把红色块放在(10, 10)、绿色块放在(150, 10)。这两个属性是 Brython 为DOMNode提供的只读扩展属性其取值直接来自内部函数$getPosition(self)返回的left/top即元素相对文档的像素偏移见 brython.js 中abs_left_get/abs_top_get的实现。使用绝对坐标而非固定像素值可以保证示例在页面滚动或布局变化时依然定位正确。2. 让元素可拖动draggable属性source.draggable Truedraggable是 HTML5 拖放规范定义的布尔属性。只有设置为True元素才能被浏览器识别为可拖动的源。Brython 的DOMNode把该原生属性直接暴露给 Python设置后即生效。3. 鼠标偏移量实现跟手拖动dragstart回调中记录了鼠标按下位置相对元素左上角的偏移m0 [ev.x - ev.target.left, ev.y - ev.target.top]其中ev.x、ev.y是事件触发时鼠标的坐标ev.target是被拖动的元素其left、top属性是相对文档左、上边界的整数距离。在drop回调中把鼠标当前位置减去该偏移就能让元素跟手地落在鼠标松开的位置elt.style.left {}px.format(ev.x - m0[0]) elt.style.top {}px.format(ev.y - m0[1])注意这里存储的是列表m0跨回调共享因此drop中才需要在dragstart中声明global m0。4.dataTransfer的角色与preventDefaultdragstart中ev.dataTransfer.setData(text, ev.target.id)把源元素的id写入拖放数据ev.dataTransfer.effectAllowed move声明允许移动操作dragover中ev.dataTransfer.dropEffect move指定目标侧的操作效果。关键的是必须调用ev.preventDefault()HTML5 规范规定dragover的默认行为是拒绝放置只有阻止默认行为drop事件才会被触发drop中ev.dataTransfer.getData(text)取回源元素id再通过document[src_id]取回该元素完成重定位。5. 放置后禁止再拖unbind的两种用法drop回调最后执行了三步收尾elt.draggable False # 禁止再次拖动 elt.unbind(mouseover) # 卸载鼠标悬停回调 elt.style.cursor auto # 恢复默认光标unbind是本例最有价值的细节它演示了事件生命周期的管理。查看运行时源码 brython.jsDOMNode.unbind支持两种调用形态element.unbind(event)移除该事件上的全部回调并把内部$events[event]置空element.unbind(event, func)只移除指定的回调函数若该回调不存在会抛出TypeError提示missing callback for event ...。与之对称bind的实现brython.js会为每个 Python 回调包装一个 JS 包装函数把原生事件转换为DOMEvent实例后调用 Python 函数并将配对关系登记在元素内部的$events表中这正是unbind能精准移除回调的基础。此外bind还支持第三个可选参数options可以是布尔值或字典会原样传给浏览器原生的addEventListener如capture等选项。延伸bind的更多形态与配套 API除了元素方法element.bind(event, callback)Brython 的browser模块还提供了模块级函数bind对应 brython.js 中browser.bind的实现它接收(elt, evt, options)返回一个装饰器风格的函数可直接用于装饰回调函数且能接受元素 id 字符串、DOMNode、JSObj或可迭代元素集合方便批量绑定from browser import bind bind(#source, dragstart) def dragstart(ev): ...配合本文示例还经常用到以下DOMNode扩展 API同样定义于 brython.jselement.bindings()返回字典列出该元素各事件当前绑定的 Python 回调列表见 brython.jselement.events(event)返回指定事件下已绑定的回调列表见 brython.jselement.trigger(event)手动触发一个事件见 brython.js。这些 API 可用于调试或实现更复杂的交互编排例如在drop前用bindings()检查是否已绑定过处理函数。动手实践建议直接运行把上面的 HTML exec_on_load代码块保存为.html在浏览器中打开本地file://或通过项目仓库的 server.py / server_aiohttp.py 启动 HTTP 服务均可。改造练习把drop回调中elt.draggable False和elt.unbind(mouseover)两行注释掉观察差异——元素被放置后仍可再次拖动mouseover每次经过都会打印提示直观体会unbind的作用。数据扩展setData的类型参数目前使用text可按需携带更多信息如多个id、坐标快照等实现多元素拖放排序、拖放进购物车等进阶场景。小结Brython 把 HTML5 拖放规范封装成了简洁的 Python 接口三个事件dragstart、dragover、drop加上bind/unbind两个方法配合dataTransfer的数据通道即可完成完整的拖放交互。示例中还展示了元素绝对定位abs_top/abs_left、鼠标偏移计算、draggable开关等实用技巧这些模式同样适用于 Brython 的其它 DOM 交互开发。更多事件类型与DataTransfer字段的完整说明可继续查阅 drag_events.md。赞分享编程语言语言运行时编译器前端【免费下载链接】brythonBrython (Browser Python) is an implementation of Python 3 running in the browser项目地址https://gitcode.com/gh_mirrors/br/brython点击查看免费下载相关推荐Brython 拖放Drag and Drop实战基于 HTML5 拖放规范的浏览器端 Python 实现Brython 拖放Drag and Drop实战基于 HTML5 拖放规范的浏览器端 Python 实现 本篇技术指南聚焦 BrythonBrowse编程语言语言运行时编译器前端Brython 实现 HTML5 拖放Drag and Drop基于 bind/unbind 与 dataTransfer 的完整实战Brython 实现 HTML5 拖放Drag and Drop基于 bind/unbind 与 dataTransfer 的完整实战 本文以 Bryth编程语言语言运行时编译器前端惠普OMEN性能终极解锁OmenSuperHub深度调优完全指南惠普OMEN性能终极解锁OmenSuperHub深度调优完全指南 OmenSuperHub是一款专为惠普OMEN/光影精灵游戏本设计的第三方控制台通过深度硬桌面应用硬件开发上一篇Virtual-Display-Driver终极指南Windows虚拟显示器驱动源码深度解析下一篇OmenSuperHub惠普游戏本性能控制的终极开源解决方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考