拖动手柄 React 扩展
你是否曾想过在基于 React 的编辑器中拖动节点?我们也有同样的需求——所以这里有一个扩展实现它。
DragHandleReact 组件允许你轻松处理编辑器中节点的拖动。你可以定义自定义渲染函数、位置等。
它本质上将 DragHandle 扩展封装到一个 React 组件中,该组件会自动向编辑器注册和注销扩展。
安装
npm install @tiptap/extension-drag-handle-react @tiptap/extension-drag-handle @tiptap/extension-node-range @tiptap/extension-collaboration @tiptap/y-tiptap yjs y-protocols属性
所有属性遵循与 DragHandle 扩展相同的结构。
children
应显示在拖动手柄内部的内容。
<DragHandle>
<div>拖动我!</div>
</DragHandle>computePositionConfig
拖动手柄的位置计算配置,使用 floating-ui/dom 包。你可以传递在 floating-ui 文档 中可用的任何选项。
默认值:{ placement: 'left-start', strategy: 'absolute' }
<DragHandle
computePositionConfig={{
placement: 'left',
strategy: 'fixed',
}}
>
<div>拖动我!</div>
</DragHandle>onNodeChange
当节点被悬停时返回一个节点或 null。这可以用于高亮当前悬停的节点。
默认值:undefined
function Component() {
const [selectedNode, setSelectedNode] = useState(null)
return (
<DragHandle
onNodeChange={({ node, editor, pos }) => {
setSelectedNode(node)
// 对节点进行某些操作
}}
>
<div>拖动我!</div>
</DragHandle>
)
}getReferencedVirtualElement
一个返回拖动手柄虚拟元素的函数。当菜单需要相对于特定的 DOM 元素定位时,这很有用。
默认值:undefined
<DragHandle
getReferencedVirtualElement={() => {
// 返回一个用于自定义定位的虚拟元素
return null
}}
>
<div>拖动我!</div>
</DragHandle>locked
锁定拖动手柄的位置和可见性。如果拖动手柄原本可见,则会保持可见直到解除锁定;如果原本隐藏,则保持隐藏直到解除锁定。
默认值:false
<DragHandle locked={true}>
<div>拖动我!</div>
</DragHandle>pluginKey
在编辑器中存储插件时应使用的键。如果在同一个编辑器中有多个拖动手柄,这非常有用。
默认值:undefined
<DragHandle pluginKey="myCustomDragHandle">
<div>拖动我!</div>
</DragHandle>onElementDragStart
当元素开始被拖动时调用的函数。可以用于添加拖动开始时的自定义逻辑。
<DragHandle
onElementDragStart={(e: DragEvent) => {
// 拖动开始时执行某些操作
}}
>
<div>拖动我!</div>
</DragHandle>onElementDragEnd
当元素停止被拖动时调用的函数。可以用于添加拖动结束时的自定义逻辑。
<DragHandle
onElementDragEnd={(e: DragEvent) => {
// 拖动结束时执行某些操作
}}
>
<div>拖动我!</div>
</DragHandle>nested
启用针对嵌套内容(如列表项、引用块及其他嵌套结构)的拖动手柄。
启用后,拖动手柄不仅会出现在顶级块,还会出现在嵌套块。基于规则的评分系统会根据光标位置和配置规则确定目标节点。
默认值:false
// 使用默认值启用
<DragHandle nested={true}>
<div>拖动我!</div>
</DragHandle>
// 使用自定义边缘检测启用
<DragHandle nested={{ edgeDetection: { threshold: -16 } }}>
<div>拖动我!</div>
</DragHandle>带嵌套支持的完整示例
import DragHandle from '@tiptap/extension-drag-handle-react'
import { EditorContent, useEditor } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit'
import { useState } from 'react'
const NESTED_CONFIG = { edgeDetection: { threshold: -16 } }
export default function Editor() {
const [nested, setNested] = useState(true)
const editor = useEditor({
extensions: [StarterKit],
content: '<ul><li>Item 1</li><li>Item 2</li></ul>',
})
return (
<>
<button onClick={() => setNested(!nested)}>
切换嵌套
</button>
<DragHandle editor={editor} nested={nested ? NESTED_CONFIG : false}>
<div className="drag-handle" />
</DragHandle>
<EditorContent editor={editor} />
</>
)
}性能提示
当使用 React 状态切换 nested 属性时,请将配置对象定义为组件外部的常量,避免不必要的重新渲染。
请参见 DragHandle 嵌套文档 获取包括边缘检测、自定义规则及允许容器等详细配置选项。
命令
请参见 DragHandle 扩展以获取可用的编辑器命令。