选区
选区 selection 是指编辑器内容中被选中的区域,有 4 种类型的选区:
RangeSelection范围选区NodeSelection节点选区GridSelection网格选区null表示选区为空
提示
选区是 Editor State 编辑器状态里的一部分,也就是说每次编辑器更新时选区也会同步更新,这样就确保了选区在更新前后的(相对于 node tree 节点树)一致性。
Lexical 提供了 helper function 方法 $getSelection() 获取编辑器当前的选区
注意
$getSelection() 该方法只能在 editor.update(callback) 或 editorState.read(callback) 或 editor.registerCommand(callback) 的回调函数中使用
import { $getSelection } from 'lexical';
editor.update(() => {
const selection = $getSelection();
});
Lexical 还提供了一个内置指令 SELECTION_CHANGE_COMMAND 当编辑器的选区改变时就会自动分发该指令
提示
相当于 DOM 原生的 selectionchange 事件
// SELECTION_CHANGE_COMMAND 是内置指令
// 当编辑器的选区改变时就会分发
// 类似于 document.onselectionchange() 的作用
import { $getSelection, SELECTION_CHANGE_COMMAND } from 'lexical';
// 为 SELECTION_CHANGE_COMMAND 指令注册响应函数
editor.registerCommand(SELECTION_CHANGE_COMMAND, () => {
const selection = $getSelection();
console.log(selection);
}, 0);
RangeSelection
范围选区 RangeSelection 是最常见的一种选区类型
提示
这种类型的选区对象有三个属性:
anchor属性:一个对象,表示范围选区的一侧端点(锚定「不动」的一端,即框选开始时光标的位置)focus属性:一个对象,表示范围选区的另一侧端点(焦点「延伸」的一端,即框选结束时光标的位置)说明
因为用户可以从左向右框选,也可以从右向左框选,所以
anchor所对应的光标位置可能在focus所对应的光标位置的右侧
以上两个属性都是一个对象,以表示编辑器中的一个位置,其中主要包含的属性如下:key属性:一个数字,是该选区端点所在的节点的标识符NodeKeyoffset属性:一个数字,表示选区的端点位于节点的何处(偏移量)。如果是文本节点,则以字符为单位来计算;如果是元素节点,则以子节点为单位来计算。序号从0开始算起,如果光标在节点的开头,则offset为0type属性:element或text,表示该选区端点所在的节点类型
format属性:以(经过位运算的)数字表示当前被选中的所含有的文本格式
以下是一些范围选区的例子



NodeSelection
节点选区 NodeSelection 是指选择多个节点,如三个图片被同时选中
可以通过方法 nodeSelection.getNodes() 返回一个数组,其中各元素就是选中的节点
GridSelection
网格选区 GridSelection 是指对网格布局的内容进行框选,例如表格。
这种类型的选区对象主要有以下三个属性:
gridKey属性:表示选区所在的父节点(即网格布局的容器),用一个数字表示节点anchor属性:一个数字(表示网格的某个单元),表示网格选区的一端的单元格(锚定「不动」的一端)focus属性:一个数字(表示网格的某个单元),表示网格选区的另一端的单元格(焦点「延伸」的一端)
null
当编辑器的内容没有被选中时,或编辑器(可编辑元素)失去焦点时,或在选中了编辑器里(不可编辑的)组件的内容时,则该编辑器的选区就是 null
编程式创建选区
可以通过一些 helper function 方法来创建选区(即以编程式的方式来创建选区,而不是用户手动框选创建选区)
import { $setSelection, $createRangeSelection, $getNodeByKey, $createNodeSelection } from 'lexical';
// 以编程式的方式创建选区
// 其流程和使用浏览器原生的 Selection 和 Range API 创建选区的流程类似
editor.update(() => {
/**
* 范围选区
*/
// 初始化/创建一个(空的)范围选区对象
const rangeSelection = $createRangeSelection();
// 将该选区应用到编辑器中
// 不过实际上需要等到这一次更新 commit 到**页面**上时,才会真的框选住相应的内容
$setSelection(rangeSelection);
// 还可以通过节点的相关方法来*间接*创建范围选区
const someNode = $getNodeByKey(someKey);
// On element nodes, this will create a RangeSelection with type "element",
// referencing an offset relating to the child within the element.
// On text nodes, this will create a RangeSelection with type "text",
// referencing the text character offset.
someNode.select();
someNode.selectPrevious();
someNode.selectNext();
// On element nodes, you can use these.
someNode.selectStart();
someNode.selectEnd();
/**
* 节点选区
*/
const nodeSelection = $createNodeSelection();
// Add a node key to the selection.
nodeSelection.add(someKey);
$setSelection(nodeSelection);
/**
* 清除选区
*/
// 将选区设置为 null
$setSelection(null);
});
注意
这些 helper function 方法只能在 editor.update(callback) 或 editor.registerCommand(callback) 的回调函数中使用