draft-js 是一个基于 react 和 immutable-js 的富文本编辑器, 可以方便的集成到 react 代码中。
编辑器最终要解决的是两个方面问题:
state 和 input 的值input 的onChange 事件onChange 事件富文本的内容可以分为以下几个部分
它们之间的大致关系可以粗浅的立即为下图(箭头为包含关系)
为了解决以上两方面的问题,draft-js 引入了State 和 onChange。 对于熟悉 react的工程师来说,这两个概念已经不是新鲜的概念了。
其中State作为所有交互和输入数据的状态,被包装成了一个不可变的数据类型EditorState。
EditorState 的数据类型依托于
Record,其中包括了以下几类数据,用于描述draft-js 编辑器中的所有状态
整个editorState 就是要编辑的所有状态,所以最好是将所有状态的修改都通过 editorState 提供的 Api 来进行,而不要通过 immutable-js 的 Api 来进行.
ContentState可以理解为内容的状态,所有对内容的更新,本质上都是更新这个状态的实例
ContentBlock是在 ContentState 中实际描述内容的单元,每个 ContentBlock 实例包括了以下几部分:
每个 ContentBlock都有其唯一的 key,可以通过 key 来指定需要操作的 ContentBlock。
在 ContentBlock中,有时会对一些文本进行特殊展示,这种情况下可以使用 Decorator来对其进行装饰,使其在编辑器中展示出特别的样式和 html 结构。
每一个 Decorator 对象都有以下这两个属性:
strategy: handleStrategy (contentBlock, callback, contentState) => {},
component: HandleSpan (props) => {}
看一个具体的例子,下面的这段代码匹配到了 @ 和 # 并返回了富文本
// strategy
const HANDLE_REGEX = /\@[\w]+/g;
const HASHTAG_REGEX = /\#[\w\u0590-\u05ff]+/g;
function handleStrategy(contentBlock, callback, contentState) {
findWithRegex(HANDLE_REGEX, contentBlock, callback);
}
function hashtagStrategy(contentBlock, callback, contentState) {
findWithRegex(HASHTAG_REGEX, contentBlock, callback);
}
function findWithRegex(regex, contentBlock, callback) {
const text = contentBlock.getText();
let matchArr, start;
while ((matchArr = regex.exec(text)) !== null) {
start = matchArr.index;
callback(start, start + matchArr[0].length);
}
}
// component
const HandleSpan = (props) => {
return <span {...props} style={styles.handle}>{props.children}</span>;
};
const HashtagSpan = (props) => {
return <span {...props} style={styles.hashtag}>{props.children}</span>;
};
这里需要注意的是 callback 方法实际接收的是匹配到的文本内容的起始位置和结束位置,也可以称为 range。
另外,Decorator 需要通过
EditorState.set(editorState, {decorator: decorators})
的方式来添加到 editorState 中,这样才可以正常使用。
entity 是一个最小单元的富文本对象,每一个 entity 对象都有三个属性:
type 为 ‘LINK’ 的话,data 可以写成这样 {'url': 'https://foo.com'}entity 对象用于描述 contentState 中的selectionState, 举个例子,这是一个**创建 entity -> 获取 entityKey -> 使用 Modifier 将 entity 应用到 selectionState **
const contentState = editorState.getCurrentContent();
const contentStateWithEntity = contentState.createEntity(
'LINK',
'MUTABLE',
{url: 'http://www.zombo.com'}
);
const entityKey = contentStateWithEntity.getLastCreatedEntityKey();
const contentStateWithLink = Modifier.applyEntity(
contentStateWithEntity,
selectionState,
entityKey
);
重要的事情再强调一遍,Entity 中的 mutability 跟 Immutable Record 对象不是一回事儿,这个属性仅仅是标记在 editor 中当前的entity 是否会改变。
这个属性有三个可选择的值,类型都是字符串:
顾名思义,SelectionState就是 Selection 在编辑器中的状态;通过SelectionState可以获取到与 Selection 相关的ContentBlock。
除了表示内容的数据结构外,draft-js 还提供了一些其他的 Utils 供开发者使用