entities 是draft.js 抽象出来的基本粒子,我们常用到的@某人、链接及嵌入的其它元素都可以抽象为实体
一个entities 包含
1. type 自己定义的字符串 唯一标识这个实体
2. mutability 标识实体在用户编辑的时候展现出来的特性,分为
Immutable 不可变:有原子性,增、删、改一个地方则全部删除
Mutable 可变:例如链接,链接的文字是可以随意改变的
Segmented 部分可变:(或者翻译为分段不可变),片段数量可以增删改,但是单个片段内部不可变
3. data 实体包含的数据
常用的方法:
Entity.get(key) 静态方法,通过实体的Key获取实体
Entity.create 创建实体 如:Entity.create(‘LINK’, ‘MUTABLE’, {url: urlValue});
demo 演示了富文本编辑器中给部分文字添加链接 和 删除链接的功能
import React from 'react';
import ReactDOM from 'react-dom';
import{
convertToRaw,
CompositeDecorator,
ContentState,
Editor,
EditorState,
Entity,
RichUtils
}
from 'draft-js';
class LinkEditorExample extends React.Component {
constructor(props) {
super(props);
// 创建新的decorator
const decorator = new CompositeDecorator([
{
strategy: findLinkEntities,
component: Link,
},
]);
this.state = {
editorState: EditorState.createEmpty(decorator),
showURLInput: false,
urlValue: '',
};
this.focus = () => this.refs.editor.focus();
this.onChange = (editorState) => this.setState({editorState});
// 输出日志
this.logState = () => {
const content = this.state.editorState.getCurrentContent();
console.log(convertToRaw(content));
};
this.promptForLink = this._promptForLink.bind(this);
// 输入url改变
this.onURLChange = (e) => this.setState({urlValue: e.target.value});
// 确认URL的输入完成
this.confirmLink = this._confirmLink.bind(this);
this.onLinkInputKeyDown = this._onLinkInputKeyDown.bind(this);
this.removeLink = this._removeLink.bind(this);
}
// 添加链接
_promptForLink(e) {
e.preventDefault();
const {editorState} = this.state;
const selection = editorState.getSelection();
// 如果开始和结尾不是相同的(意味着选中的东西)
debugger;
if (!selection.isCollapsed()) {
this.setState({
showURLInput: true,
urlValue: '',
}, () => {
// 设置焦点
setTimeout(() => this.refs.url.focus(), 0);
});
}
}
// 确认输入
_confirmLink(e) {
// 取消默认事件
e.preventDefault();
const {editorState, urlValue} = this.state;
// 创建一个LINK 实体,可变,值是url 地址
const entityKey = Entity.create('LINK', 'MUTABLE', {url: urlValue});
// setState 是异步的,第二个参数是回调函数
this.setState({
// 借助 RichUtils 添加链接
editorState: RichUtils.toggleLink(
editorState,
editorState.getSelection(),
entityKey
),
showURLInput: false,
urlValue: '',
}, () => {
setTimeout(() => this.refs.editor.focus(), 0);
});
}
// 监听回车
_onLinkInputKeyDown(e) {
if (e.which === 13) {
this._confirmLink(e);
}
}
// 删除链接 仅仅会删除选中部分的链接
_removeLink(e) {
e.preventDefault();
const {editorState} = this.state;
const selection = editorState.getSelection();
// 疑问:如果选中的是部分链接内容会怎样?
if (!selection.isCollapsed()) {
this.setState({
// 借助 RichUtils 删除链接
editorState: RichUtils.toggleLink(editorState, selection, null),
});
}
}
render() {
let urlInput;
// 如果需要选择url 输入框
if (this.state.showURLInput) {
urlInput =
<div style={styles.urlInputContainer}>
<input
onChange={this.onURLChange}
ref="url"
style={styles.urlInput}
type="text"
value={this.state.urlValue}
onKeyDown={this.onLinkInputKeyDown}
/>
<button onMouseDown={this.confirmLink}>
Confirm
</button>
</div>;
}
return (
<div style={styles.root}>
<div style={{marginBottom: 10}}>
Select some text, then use the buttons to add or remove links
on the selected text.
</div>
<div style={styles.buttons}>
<button
onMouseDown={this.promptForLink}
style={{marginRight: 10}}>
Add Link
</button>
<button onMouseDown={this.removeLink}>
Remove Link
</button>
</div>
{urlInput}
<div style={styles.editor} onClick={this.focus}>
<Editor
editorState={this.state.editorState}
onChange={this.onChange}
placeholder="Enter some text..."
ref="editor"
/>
</div>
<input
onClick={this.logState}
style={styles.button}
type="button"
value="Log State"
/>
</div>
);
}
}
// 修饰器的查找方法 通过实体类型的名称进行查找
function findLinkEntities(contentBlock, callback) {
contentBlock.findEntityRanges(
(character) => {
const entityKey = character.getEntity();
return (
entityKey !== null &&
Entity.get(entityKey).getType() === 'LINK'
);
},
callback
);
}
// 链接的component
const Link = (props) => {
// 取得Link 实体的数据(url) 进行绘制
const {url} = Entity.get(props.entityKey).getData();
return (
<a href={url} style={styles.link}>
{props.children}
</a>
);
};
// 样式
const styles = {
root: {
fontFamily: '\'Georgia\', serif',
padding: 20,
width: 600,
},
buttons: {
marginBottom: 10,
},
// 输入框样式
urlInputContainer: {
marginBottom: 10,
},
urlInput: {
fontFamily: '\'Georgia\', serif',
marginRight: 10,
padding: 3,
},
editor: {
border: '1px solid #ccc',
cursor: 'text',
minHeight: 80,
padding: 10,
},
button: {
marginTop: 10,
textAlign: 'center',
},
link: {
color: '#3b5998',
textDecoration: 'underline',
},
};
ReactDOM.render(
<LinkEditorExample />,
document.getElementById('container')
);