news 2026/9/15 14:05:04

pragmatic-drag-androp 如何接管和禁用锚点与图片元素的默认拖拽行为?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
pragmatic-drag-androp 如何接管和禁用锚点与图片元素的默认拖拽行为?

pragmatic-drag-androp 如何接管和禁用锚点与图片元素的默认拖拽行为?

【免费下载链接】pragmatic-drag-and-dropFast drag and drop for any experience on any tech stack项目地址: https://gitcode.com/GitHub_Trending/pr/pragmatic-drag-and-drop

页面里的<a><img>元素在浏览器中默认就是可拖拽的(相当于自带draggable="true")。当你在页面中使用 pragmatic-drag-and-drop 的 element adapter 时,会遇到两种需求:要么希望这些元素被 element adapter 接管、走你自定义的拖拽逻辑(事件、drop target、预览);要么根本不希望它们被拖出去。这篇文章基于核心包文档中的 Unregistered elements 与 Element adapter 两页,说明这两条路径的具体操作方式。

前提:element adapter 只响应显式注册的元素

在开始之前需要理解一个关键事实(来自文档原文):

  • 任何HTMLElement都可以通过加draggable="true"属性变得可拖拽;
  • <a><img>元素默认可拖拽,不需要任何属性;
  • element adapter只会被显式注册过的元素激活(即调用过draggable({element})的元素),页面上其他可拖拽元素不会触发它。

这意味着:一个没有注册过的<a>被拖拽时,走的是浏览器原生拖拽行为,你的onDragStartonDropTargetChange等回调都不会被调用。要接管,就必须注册;要禁用,则直接改属性。

准备:安装核心包

核心包是 vanilla JS 库(用 TypeScript 编写),可与任意视图库搭配使用。安装命令见 核心包文档:

# install the core package yarn add @atlaskit/pragmatic-drag-and-drop

element adapter 位于独立入口点@atlaskit/pragmatic-drag-and-drop/element/adapter(核心包把各模块拆分成各自入口点,以便只引入用到的代码)。

路径一:用 draggable() 接管锚点或图片的拖拽

把目标元素传给draggable()即可。接管后的效果:该元素的拖拽由 element adapter 驱动,你在注册时传入的事件回调(onGenerateDragPreviewonDragStartonDragonDropTargetChangeonDrop)都会生效,它也能被页面上的dropTargetForElements感知。

import { draggable } from '@atlaskit/pragmatic-drag-and-drop/element/adapter'; draggable({ element: myAnchor, });

myAnchor是你对<a>(或<img>)元素的引用,HTMLElement正是支持"draggable"属性的接口。draggable()的返回值是一个 cleanup 函数,在框架环境(如 React)中通常在 effect 的清理阶段调用它,避免重复注册。

接管后需要注意的默认行为:外部数据

文档明确说明:注册锚点或图片为draggable()不会改变浏览器为它们附加外部数据(external data)的默认行为。拖拽<a>时,浏览器会自动附加"text/plain""text/uri-list",其中"text/uri-list"的值就是该锚点的 URL。

如果你不希望拖出的数据是锚点默认 URL,可以用getInitialDataForExternal()覆盖或追加:

import { draggable } from '@atlaskit/pragmatic-drag-and-drop/element/adapter'; draggable({ element: myAnchor, getInitialDataForExternal: () => ({ // overriding the standard "text/uri-list" value 'text/uri-list': someOtherUrl, // adding some new value 'application/x.something-custom': myCustomData, }), });

这里someOtherUrlmyCustomData是文档示例中的变量,替换为你自己的值。需要警惕文档中的一条警告:附加给外部消费者的数据可以被用户拖放到的任何外部消费者访问,不要把私密数据放进去。

接管后需要注意的默认行为:拖拽预览

即使元素已注册为draggable(),浏览器在拖拽<a>/<img>时仍会自动生成原生拖拽预览。控制方式与其他元素相同(见 Drag previews),常用两种:

自定义原生预览,用setCustomNativeDragPreview()挂载一个新元素作为预览图:

import { setCustomNativeDragPreview } from '@atlaskit/pragmatic-drag-and-drop/element/set-custom-native-drag-preview'; draggable({ element: myAnchor, onGenerateDragPreview: ({ nativeSetDragImage }) => { setCustomNativeDragPreview({ render({ container }) { const preview = document.createElement('div'); preview.textContent = 'My Preview'; Object.assign(preview.style, { padding: '20px', backgroundColor: 'lightpink', }); container.appendChild(preview); }, nativeSetDragImage, }); }, });

或者干脆不要原生预览(例如你想自己渲染预览,或做类似 resizing 的体验):

import { disableNativeDragPreview } from '@atlaskit/pragmatic-drag-and-drop/element/disable-native-drag-preview'; draggable({ element: myAnchor, onGenerateDragPreview({ nativeSetDragPreview }) { disableNativeDragPreview({ nativeSetDragPreview }); }, });

disableNativeDragPreview的实现是渲染一张1x1的透明图片作为原生预览,文档称这是在多个浏览器和设备上效果最好的隐藏方式。

路径二:禁用锚点与图片的默认拖拽

如果你不需要这些元素被拖(无论是拖给浏览器原生行为还是拖给库),最简做法是把属性设为draggable="false"

<a href="/home" draggable="false">Home</a>

文档给出的就是这个用法:对<a><img>设置draggable="false"可以关闭浏览器对它们的默认draggable="true"设置。<img>同理,把draggable="false"加到<img>标签上即可。

另一条可编程的替代路径是注册后条件禁用——用canDrag()返回false来阻止拖拽:

draggable({ element: myAnchor, // disable dragging canDrag: () => false, });

但文档特别提醒了这个用法的边界:当某个draggablecanDrag()返回false时,@atlaskit/pragmatic-drag-and-drop会在内部调用event.preventDefault()取消整个拖拽操作,这会阻止页面上其他draggable被拖动(一旦拖拽事件开始,单个draggable无法单独退出、把机会让给其他元素)。如果只是想禁用某个元素但仍允许父级draggable被拖,文档建议改成条件性地调用draggable()本身(例如在 React 中根据状态决定是否在 effect 里注册),而不是用canDrag()

对于「就是不想让锚点/图片被拖」这个标题场景,draggable="false"是最直接、副作用最小的方案,因为它不涉及库,也不会影响页面上其他已注册的拖拽。

如何验证结果

文档提供的事件回调可以作为观察点:

  • 验证接管成功:在draggable({ element: myAnchor })中传入onDragStart/onDrop(如() => console.log('drag started')),拖动锚点时如果这些回调开始被调用,说明拖拽已由 element adapter 驱动,而不是浏览器原生行为;也可以注册一个 monitor 全局观察:
import { monitorForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter'; const cleanup = monitorForElements({ onDragStart: () => console.log('Dragging an element'); });
  • 验证禁用成功:对设置draggable="false"后的<a>/<img>执行拖拽,此时既不会产生浏览器原生拖拽预览,element adapter 的相关事件(monitor 的onDragStart等)也不会被该元素的拖拽触发。

边界与限制

  • draggable()注册不改变浏览器为锚点/图片附加外部数据的默认行为;要改数据必须显式提供getInitialDataForExternal()
  • 外部数据对任何外部消费者可见,不要附加私密数据(文档警告)。
  • canDrag()返回false会取消整个拖拽并连带阻止其他draggable,不要把它当作「只禁用单个元素」的手段;需要局部禁用时优先条件注册或draggable="false"
  • 浏览器仍会为已注册的<a>/<img>自动生成拖拽预览,需要自定义或关闭时按上文用setCustomNativeDragPreview()disableNativeDragPreview()处理。

更多细节可参考仓库中的 unregistered-elements 文档、drag-previews 文档 与 element adapter 文档。

【免费下载链接】pragmatic-drag-and-dropFast drag and drop for any experience on any tech stack项目地址: https://gitcode.com/GitHub_Trending/pr/pragmatic-drag-and-drop

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/15 14:02:49

如何下载 XRay-DINO 权重并加载 xray_dino_vitl16 骨干模型?

如何下载 XRay-DINO 权重并加载 xray_dino_vitl16 骨干模型&#xff1f; 【免费下载链接】dinov2 PyTorch code and models for the DINOv2 self-supervised learning method. 项目地址: https://gitcode.com/GitHub_Trending/di/dinov2 DINOv2 仓库在 2025-12-18 新增了…

作者头像 李华
网站建设 2026/9/15 14:01:51

Wasp 快速上手指南:三步创建并运行你的第一个全栈应用

Wasp 快速上手指南&#xff1a;三步创建并运行你的第一个全栈应用 【免费下载链接】wasp The batteries-included full-stack framework for the AI era. Develop JS/TS web apps (React, Node.js, and Prisma) using declarative code that abstracts away complex full-stack…

作者头像 李华
网站建设 2026/9/15 14:01:45

Scalar 仓库 AI Agent 协作指南:从环境搭建到代码提交流程的完整解读

Scalar 仓库 AI Agent 协作指南&#xff1a;从环境搭建到代码提交流程的完整解读 【免费下载链接】scalar Scalar is an open-source API platform:                                       &#x1f310; Modern REST API Client   …

作者头像 李华