Files
components/demo.tsx
'use client';

import * as React from 'react';

import { Plate, usePlateEditor } from 'platejs/react';

import { EditorKit } from '@/components/editor/editor-kit';
import { Editor, EditorContainer } from '@/components/ui/editor';

import { DEMO_VALUES } from './values/demo-values';

export default function Demo({ id }: { id: string }) {
  const editor = usePlateEditor({
    plugins: EditorKit,
    value: DEMO_VALUES[id],
  });

  return (
    <Plate editor={editor}>
      <EditorContainer variant="demo">
        <Editor />
      </EditorContainer>
    </Plate>
  );
}
Visual block selection with keyboard support.
block-selection-demo
block-selection-demo

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

特性

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

套件使用

安装

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

'use client';

import { BlockSelectionPlugin } from '@platejs/selection/react';
import { getPluginTypes, KEYS } from 'platejs';

import { BlockSelection } from '@/components/ui/block-selection';

export const BlockSelectionKit = [
  BlockSelectionPlugin.configure(({ editor }) => ({
    options: {
      enableContextMenu: true,
      isSelectable: (element) => {
        return !getPluginTypes(editor, [
          KEYS.column,
          KEYS.codeLine,
          KEYS.td,
        ]).includes(element.type);
      },
    },
    render: {
      belowRootNodes: (props) => {
        if (!props.attributes.className?.includes('slate-selectable'))
          return null;

        return <BlockSelection {...(props as any)} />;
      },
    },
  })),
];

添加套件

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

import { createPlateEditor } from 'platejs/react';
import { BlockSelectionKit } from '@/components/editor/plugins/block-selection-kit';
 
const editor = createPlateEditor({
  plugins: [
    // ...其他插件
    ...BlockSelectionKit,
  ],
});

手动使用

安装

pnpm add @platejs/selection

添加插件

import { BlockSelectionPlugin } from '@platejs/selection/react';
import { createPlateEditor } from 'platejs/react';
 
const editor = createPlateEditor({
  plugins: [
    // ...其他插件
    BlockSelectionPlugin,
  ],
});

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

从选择中排除块

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

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

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 配置边界和滚动行为
BlockSelectionPlugin.configure({
  options: {
    areaOptions: {
      boundaries: `#${editor.meta.uid}`,
      container: `#${editor.meta.uid}`,
      behaviour: {
        scrolling: {
          // 推荐速度,接近原生
          speedDivider: 0.8,
        },
        // 开始选择区域的阈值
        startThreshold: 4,
      },
    },
  },
});

全页选择

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

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

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

<YourToolbarButton data-plate-prevent-unselect />

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

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

样式

选择区域

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

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

选中元素

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

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

render: {
  belowRootNodes: (props) => {
    if (!props.className?.includes('slate-selectable')) return null;
 
    return <BlockSelection />;
  },
},

插件

BlockSelectionPlugin

块选择功能的插件。

Options

Collapse all

    选择区域的选项。查看 SelectionJS 文档 获取所有可用选项。

    {
      boundaries: [`#${editor.meta.uid}`],
      container: [`#${editor.meta.uid}`],
      selectables: [`#${editor.meta.uid} .slate-selectable`],
      selectionAreaClass: 'slate-selection-area',
    }

    启用或禁用块选择的上下文菜单。

    • 默认值: false

    指示块选择当前是否处于活动状态。

    • 默认值: false

    在选择时处理键盘按下事件的函数。

    在块选择期间查询节点的选项。

    • 默认值: { maxLevel: 1 }

    当前选中块的 ID 集合。

    • 默认值: new Set()

    (内部) 当前选择中锚块的 ID。用于基于 Shift 的选择。

    • 默认值: null

    确定块元素是否可选择的函数。

    • 默认值: () => true

API

api.blockSelection.add

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

Parameters

Collapse all

    要选择的块的 ID。

api.blockSelection.clear

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

api.blockSelection.delete

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

Parameters

Collapse all

    要从选择中移除的块的 ID。

api.blockSelection.deselect

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

api.blockSelection.focus

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

api.blockSelection.getNodes

获取编辑器中的选中块。

ReturnsNodeEntry[]

Collapse all

    选中块的条目数组。

api.blockSelection.has

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

Parameters

Collapse all

    要检查的块的 ID。

Returns

Collapse all

    块是否被选中。

api.blockSelection.isSelectable

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

Parameters

Collapse all

    要检查的块元素。

    块元素的路径。

Returnsboolean

Collapse all

    块是否可选择。

api.blockSelection.moveSelection

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

向上移动时:

  • 从最顶部选中的块获取上一个可选择块
  • 将其设置为新锚点
  • 清除先前选择并仅选择此块 向下移动时:
  • 从最底部选中的块获取下一个可选择块
  • 将其设置为新锚点
  • 清除先前选择并仅选择此块

Parameters

Collapse all

    移动选择的方向。

api.blockSelection.selectAll

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

api.blockSelection.set

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

Parameters

Collapse all

    要选择的块的 ID。

api.blockSelection.shiftSelection

基于锚块扩展或收缩选择。

对于 Shift+ArrowDown

  • 如果锚点是最顶部:通过添加最底部下方的块向下扩展
  • 否则:从最顶部收缩(除非最顶部是锚点) 对于 Shift+ArrowUp
  • 如果锚点是最底部:通过添加最顶部上方的块向上扩展
  • 否则:从最底部收缩(除非最底部是锚点) 锚块始终保持选中状态。如果未设置锚点,则默认为:
  • Shift+ArrowUp 的最底部块
  • Shift+ArrowDown 的最顶部块

Parameters

Collapse all

    扩展/收缩选择的方向。

转换

tf.blockSelection.duplicate

复制选中的块。

tf.blockSelection.removeNodes

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

tf.blockSelection.select

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

tf.blockSelection.setNodes

在选中的节点上设置属性。

Parameters

Collapse all

    要在选中节点上设置的属性。

    设置节点的选项。

tf.blockSelection.setTexts

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

Parameters

Collapse all

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

    设置文本节点的选项,不包括 'at' 属性。

钩子

useBlockSelectable

提供使块元素可选择的属性的钩子,包括上下文菜单行为。

Returnsobject

Collapse all

    要应用于块元素的属性。

useBlockSelected

Returnsboolean

Collapse all

    上下文块是否被选中。

useBlockSelectionNodes

ReturnsNodeEntry[]

Collapse all

    选中块的条目数组。

useBlockSelectionFragment

ReturnsNode[]

Collapse all

    选中块的节点数组。

useBlockSelectionFragmentProp

ReturnsNode[]

Collapse all

    选中块的片段属性。

useSelectionArea

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