Back to Plate

块选择

docs/(plugins)/(functionality)/block-selection.cn.mdx

1.0.012.5 KB
Original Source
<ComponentPreview name="block-selection-demo" /> <PackageInfo>

块选择功能允许用户选择和操作整个文本块,而不是单个单词或字符。

功能特性

  • 通过单一操作选择整个块。
  • 使用鼠标拖动或键盘快捷键进行多块选择。
  • 对选中的块执行复制、剪切和删除操作。
  • 快速选择的键盘快捷键:
    • Cmd+A:选择所有块。
    • 方向键:选择上方或下方的块。
  • 可自定义选中块的样式。
</PackageInfo>

Kit 使用方式

<Steps>

安装

添加块选择最快的方式是使用 BlockSelectionKit,它包含预配置的 BlockSelectionPluginBlockSelection UI 组件。

<ComponentSource name="block-selection-kit" />

添加 Kit

BlockSelectionKit 默认启用上下文菜单,并提供默认的 isSelectable 逻辑来排除常见的不可选择块,如代码行和表格单元格。

tsx
import { createPlateEditor } from 'platejs/react';
import { BlockSelectionKit } from '@/components/editor/plugins/block-selection-kit';

const editor = createPlateEditor({
  plugins: [
    // ...otherPlugins,
    ...BlockSelectionKit,
  ],
});
</Steps>

手动使用方式

<Steps>

安装

bash
npm install @platejs/selection

添加插件

tsx
import { BlockSelectionPlugin } from '@platejs/selection/react';
import { createPlateEditor } from 'platejs/react';

const editor = createPlateEditor({
  plugins: [
    // ...otherPlugins,
    BlockSelectionPlugin,
  ],
});

将此插件放在任何覆盖 selectAllCmd+A 的其他插件(代码块、表格、列等)之前,以避免冲突。

从选择中排除块

您可以使用 options.isSelectable 控制哪些块可被选择。此函数接收元素及其路径,如果块可选择则返回 true

例如,排除代码行、列和表格单元格:

tsx
import { BlockSelectionPlugin } from '@platejs/selection/react';

BlockSelectionPlugin.configure({
  options: {
    isSelectable: (element, path) => {
      if (['code_line', 'column', 'td'].includes(element.type)) {
        return false;
      }
      // 排除表格行内的块
      if (editor.api.block({ above: true, at: path, match: { type: 'tr' } })) {
        return false;
      }
      return true;
    },
  },
});

自定义滚动行为

如果您的编辑器位于可滚动容器内,您可能需要配置选择区域的边界和滚动速度。

  1. 为滚动容器添加 id,例如 id={editor.meta.uid}
  2. 在容器上设置 position: relative
  3. 使用 areaOptions 配置边界和滚动行为。
ts
BlockSelectionPlugin.configure({
  options: {
    areaOptions: {
      boundaries: `#${editor.meta.uid}`,
      container: `#${editor.meta.uid}`,
      behaviour: {
        scrolling: {
          // 推荐速度,接近原生体验
          speedDivider: 0.8,
        },
        // 开始选择区域的阈值
        startThreshold: 4,
      },
    },
  },
});

全页面选择

您可以通过添加 data-plate-selectable 属性,为 <Editor /> 组件外部的元素启用块选择。

tsx
<Cover data-plate-selectable />
<Sidebar data-plate-selectable />

要防止点击某些元素(例如工具栏按钮)时取消选择块,请添加 data-plate-prevent-unselect 属性。

tsx
<YourToolbarButton data-plate-prevent-unselect />

要在点击可选择区域外部时重置选择,您可以使用点击处理程序或直接调用 API:

tsx
// 1. 直接调用 API
editor.api.blockSelection.deselect();

// 2. 外部点击处理程序
const handleClickOutside = (event: MouseEvent) => {
  if (!(event.target as HTMLElement).closest('[data-plate-selectable]')) {
    editor.api.blockSelection.deselect();
  }
};
</Steps>

样式

选择区域

通过定位 .slate-selection-area 类来设置选择区域的样式,该类会添加到编辑器容器上。

css
/* 使用 Tailwind CSS 工具类的示例 */
'[&_.slate-selection-area]:border [&_.slate-selection-area]:border-primary [&_.slate-selection-area]:bg-primary/10'

选中元素

使用 useBlockSelected hook 来确定块是否被选中。您可以渲染一个视觉指示器,例如专为此目的设计的 BlockSelection 组件。

Plate UI 使用 render.belowRootNodes 为所有可选择的块渲染此组件:

tsx
render: {
  belowRootNodes: (props) => {
    if (!props.className?.includes('slate-selectable')) return null;

    return <BlockSelection />;
  },
},

插件

BlockSelectionPlugin

块选择功能的插件。

<API name="BlockSelectionPlugin"> <APIOptions> <APIItem name="areaOptions" type="PartialSelectionOptions" optional> 选择区域的选项。查看 [SelectionJS 文档](https://github.com/Simonwep/selection-js) 了解所有可用选项。
ts
{
  boundaries: [`#${editor.meta.uid}`],
  container: [`#${editor.meta.uid}`],
  selectables: [`#${editor.meta.uid} .slate-selectable`],
  selectionAreaClass: 'slate-selection-area',
}
</APIItem> <APIItem name="enableContextMenu" type="boolean" optional> 启用或禁用块选择的上下文菜单。 - **默认值:** `false` </APIItem> <APIItem name="isSelecting" type="boolean" optional> 指示块选择当前是否处于活动状态。 - **默认值:** `false` </APIItem> <APIItem name="onKeyDownSelecting" type="(e: KeyboardEvent) => void" optional> 处理选择时键盘按下事件的函数。 </APIItem> <APIItem name="query" type="QueryNodeOptions" optional> 块选择期间查询节点的选项。 - **默认值:** `{ maxLevel: 1 }` </APIItem> <APIItem name="selectedIds" type="Set<string>" optional> 当前选中块的 ID 集合。 - **默认值:** `new Set()` </APIItem> <APIItem name="anchorId" type="string | null" optional> (内部)当前选择中锚点块的 ID。用于基于 Shift 的选择。 - **默认值:** `null` </APIItem> <APIItem name="isSelectable" type="(element: TElement, path: Path) => boolean" optional> 确定块元素是否可选择的函数。 - **默认值:** `() => true` </APIItem> </APIOptions> </API>

API

api.blockSelection.add

将一个或多个块添加到选择中。

<API name="add"> <APIParameters> <APIItem name="id" type="string | string[]"> 要选择的块的 ID。 </APIItem> </APIParameters> </API>

api.blockSelection.clear

将选中的 ID 集合重置为空集合。

api.blockSelection.delete

从选择中移除一个或多个块。

<API name="delete"> <APIParameters> <APIItem name="id" type="string | string[]"> 要从选择中移除的块的 ID。 </APIItem> </APIParameters> </API>

api.blockSelection.deselect

取消选择所有块并将 isSelecting 标志设置为 false。

api.blockSelection.focus

聚焦块选择的影子输入框。此输入框处理选中块的复制、删除和粘贴事件。

api.blockSelection.getNodes

获取编辑器中选中的块。

<API name="getNodes"> <APIParameters> <APIItem name="options" type="{ selectionFallback?: boolean }" optional> 获取节点的选项。 </APIItem> </APIParameters> <APIOptions type="object"> <APIItem name="selectionFallback" type="boolean" optional> 如果为 true,且块选择未选中任何块,该方法将使用编辑器的原始选择来获取块。- **默认值:** `false` </APIItem> </APIOptions> <APIReturns type="NodeEntry[]"> 选中块条目的数组。 </APIReturns> </API>

api.blockSelection.has

检查一个或多个块是否被选中。

<API name="has"> <APIParameters> <APIItem name="id" type="string | string[]"> 要检查的块的 ID。 </APIItem> </APIParameters> <APIReturns> <APIItem type="boolean">块是否被选中。</APIItem> </APIReturns> </API>

api.blockSelection.isSelectable

根据 isSelectable 插件选项检查给定路径的块是否可选择。

<API name="isSelectable"> <APIParameters> <APIItem name="element" type="TElement"> 要检查的块元素。 </APIItem> <APIItem name="path" type="Path"> 块元素的路径。 </APIItem> </APIParameters> <APIReturns type="boolean">块是否可选择。</APIReturns> </API>

api.blockSelection.moveSelection

将选择向上或向下移动到下一个可选择的块。

向上移动时:

  • 从最顶部选中的块获取前一个可选择的块
  • 将其设置为新的锚点
  • 清除之前的选择并仅选择此块 向下移动时:
  • 从最底部选中的块获取下一个可选择的块
  • 将其设置为新的锚点
  • 清除之前的选择并仅选择此块
<API name="moveSelection"> <APIParameters> <APIItem name="direction" type="'up' | 'down'"> 移动选择的方向。 </APIItem> </APIParameters> </API>

api.blockSelection.selectAll

选择编辑器中所有可选择的块。

api.blockSelection.set

将选择设置为一个或多个块,清除任何现有选择。

<API name="set"> <APIParameters> <APIItem name="id" type="string | string[]"> 要选择的块的 ID。 </APIItem> </APIParameters> </API>

api.blockSelection.shiftSelection

根据锚点块扩展或收缩选择。

对于 Shift+ArrowDown

  • 如果锚点在最顶部:通过在最底部下方添加块向下扩展
  • 否则:从最顶部收缩(除非最顶部是锚点) 对于 Shift+ArrowUp
  • 如果锚点在最底部:通过在最顶部上方添加块向上扩展
  • 否则:从最底部收缩(除非最底部是锚点) 锚点块始终保持选中状态。如果未设置锚点,则默认为:
  • Shift+ArrowUp 时为最底部的块
  • Shift+ArrowDown 时为最顶部的块
<API name="shiftSelection"> <APIParameters> <APIItem name="direction" type="'up' | 'down'"> 扩展/收缩选择的方向。 </APIItem> </APIParameters> </API>

Transforms

tf.blockSelection.duplicate

复制选中的块。

tf.blockSelection.removeNodes

从编辑器中移除选中的节点。

tf.blockSelection.select

在编辑器中选择由 getNodes() 返回的节点并重置选中的 ID。

tf.blockSelection.setNodes

设置选中节点的属性。

<API name="setNodes"> <APIParameters> <APIItem name="props" type="Partial<NodeProps<TElement>>"> 要设置到选中节点的属性。 </APIItem> <APIItem name="options" type="SetNodesOptions" optional> 设置节点的选项。 </APIItem> </APIParameters> </API>

tf.blockSelection.setTexts

设置选中节点的文本属性。

<API name="setTexts"> <APIParameters> <APIItem name="props" type="Partial<NodeProps<TText>>"> 要设置到选中节点的文本属性。 </APIItem> <APIItem name="options" type="Omit<SetNodesOptions, 'at'>" optional> 设置文本节点的选项,不包括 'at' 属性。 </APIItem> </APIParameters> </API>

Hooks

useBlockSelectable

提供使块元素可选择的 props 的 hook,包括上下文菜单行为。

<API name="useBlockSelectable"> <APIReturns type="object"> <APIItem name="props" type="object"> 要展开到块元素上的 props。 <APISubList> <APISubListItem parent="props" name="className" type="string"> 选择功能所需的类。- **默认值:** `'slate-selectable'` </APISubListItem> <APISubListItem parent="props" name="onContextMenu" type="(event: React.MouseEvent) => void" > 处理右键上下文菜单行为:- 为选中的块打开上下文菜单 - 为 void 元素打开 - 为带有 `data-plate-open-context-menu="true"` 的元素打开 - 使用 Shift 键添加块到选择以进行多选 </APISubListItem> </APISubList> </APIItem> </APIReturns> </API>

useBlockSelected

<API name="useBlockSelected"> <APIReturns type="boolean">上下文块是否被选中。</APIReturns> </API>

useBlockSelectionNodes

<API name="useBlockSelectionNodes"> <APIReturns type="NodeEntry[]">选中块条目的数组。</APIReturns> </API>

useBlockSelectionFragment

<API name="useBlockSelectionFragment"> <APIReturns type="Node[]">选中块节点的数组。</APIReturns> </API>

useBlockSelectionFragmentProp

<API name="useBlockSelectionFragmentProp"> <APIReturns type="Node[]">选中块的 fragment prop。</APIReturns> </API>

useSelectionArea

初始化和管理选择区域功能。