draftjs的编辑器和input的区别就是,draft的值与状态是通过editorstate管理的,对比文档参考这里,editorstate的API 参考这里
本章节主要是文本的简单样式控制,分别通过快捷键和按钮来实现
RichUtils has information about the core key commands available to web editors, such as Cmd+B (bold), Cmd+I (italic), and so on.
RichUtils 包含了快捷键映射的功能
继续修改components/MyEditor.js
import React from 'react';
import { Editor, EditorState, RichUtils } from 'draft-js';
class MyEditor extends React.Component {
constructor(props) {
super(props);
this.state = { editorState: EditorState.createEmpty() };
this.onChange = (editorState) => this.setState({ editorState });
this.handleKeyCommand = this.handleKeyCommand.bind(this);
}
handleKeyCommand(command) {
const newState = RichUtils.handleKeyCommand(this.state.editorState, command);
if (newState) {
this.onChange(newState);
return 'handled';
}
return 'not-handled';
}
render() {
const {editorState} = this.state;
return (
this.handleKeyCommand}
onChange={
this.onChange} />
);
}
}
MyEditor.propTypes = {
};
export default MyEditor;
可以在浏览器查看效果,输入一些文字,选中文字使用ctrl+b,和ctrl+i查看效果。
为何返回值是handled和not-handled?更多文档查看如下:
handleKeyCommand
The command argument supplied to handleKeyCommand is a string value, the name of the command to be executed. This is mapped from a DOM key event. See Advanced Topics - Key Binding for more on this, as well as details on why the function returns handled or not-handled.
Here’s a super-basic example with a “Bold” button to toggle the BOLD style.
一个通过按钮来实现加粗的例子:
添加如下代码:
class MyEditor extends React.Component {
// …
_onBoldClick() {
this.onChange(RichUtils.toggleInlineStyle(this.state.editorState, 'BOLD'));
}
render() {
return (
<div>
this.state.editorState}
handleKeyCommand={
this.handleKeyCommand}
onChange={
this.onChange}
/>
div>
);
}
}
3.添加多种样式按钮操作
修改components/MyEditor.jsx
import React from 'react';
import { Editor, EditorState, RichUtils } from 'draft-js';
import Immutable from 'immutable';
import "draft-js/dist/Draft.css";
import styles from './Rich.less'
class MyEditor extends React.Component {
constructor(props) {
super(props);
this.state = { editorState: EditorState.createEmpty() };
this.focus = () => this.refs.editor.focus();
this.onChange = (editorState) => this.setState({ editorState });
this.handleKeyCommand = (command) => this._handleKeyCommand(command);
this.onTab = (e) => this._onTab(e);
this.toggleBlockType = (type) => this._toggleBlockType(type);
this.toggleInlineStyle = (style) => this._toggleInlineStyle(style);
}
_handleKeyCommand(command) {
const {editorState} = this.state;
const newState = RichUtils.handleKeyCommand(editorState, command);
if (newState) {
this.onChange(newState);
return true;
}
return false;
}
_onTab(e) {
const maxDepth = 4;
this.onChange(RichUtils.onTab(e, this.state.editorState, maxDepth));
}
_toggleBlockType(blockType) {
this.onChange(
RichUtils.toggleBlockType(
this.state.editorState,
blockType
)
);
}
_toggleInlineStyle(inlineStyle) {
this.onChange(
RichUtils.toggleInlineStyle(
this.state.editorState,
inlineStyle
)
);
}
render() {
const {editorState} = this.state;
// If the user changes block type before entering any text, we can
// either style the placeholder or hide it. Let's just hide it now.
let className = styles['RichEditor-editor'];
var contentState = editorState.getCurrentContent();
if (!contentState.hasText()) {
if (contentState.getBlockMap().first().getType() !== 'unstyled') {
className += ' ' + styles['RichEditor-hidePlaceholder'];
}
}
return (
"RichEditor-root"]}>
this.toggleBlockType}
/>
this.toggleInlineStyle}
/>
this.focus}>
this.handleKeyCommand}
onChange={
this.onChange}
onTab={
this.onTab}
placeholder="Tell a story..."
onFocus={()=>{console.log('focus')}}
ref='editor'
spellCheck={
true}
/>
);
}
}
const styleMap = {
CODE: {
backgroundColor: 'rgba(0, 0, 0, 0.05)',
fontFamily: '"Inconsolata", "Menlo", "Consolas", monospace',
fontSize: 16,
padding: 2,
},
};
function getBlockStyle(block) {
switch (block.getType()) {
case 'blockquote': return styles['RichEditor-blockquote'];
default: return null;
}
}
class StyleButton extends React.Component {
constructor() {
super();
this.onToggle = (e) => {
e.preventDefault();
this.props.onToggle(this.props.style);
};
}
render() {
let className = styles['RichEditor-styleButton'];
if (this.props.active) {
className += ' ' + styles['RichEditor-activeButton'];
}
return (
this.onToggle}>
{
this.props.label}
);
}
}
const BLOCK_TYPES = [
{ label: 'H1', style: 'header-one' },
{ label: 'H2', style: 'header-two' },
{ label: 'H3', style: 'header-three' },
{ label: 'H4', style: 'header-four' },
{ label: 'H5', style: 'header-five' },
{ label: 'H6', style: 'header-six' },
{ label: 'Blockquote', style: 'blockquote' },
{ label: 'UL', style: 'unordered-list-item' },
{ label: 'OL', style: 'ordered-list-item' },
{ label: 'Code Block', style: 'code-block' },
];
const BlockStyleControls = (props) => {
const {editorState} = props;
const selection = editorState.getSelection();
const blockType = editorState
.getCurrentContent()
.getBlockForKey(selection.getStartKey())
.getType();
return (
"RichEditor-controls"]}>
{BLOCK_TYPES.map((type) =>
type.label}
active={
type.style === blockType}
label={
type.label}
onToggle={props.onToggle}
style={
type.style}
/>
)}
);
};
var INLINE_STYLES = [
{ label: 'Bold', style: 'BOLD' },
{ label: 'Italic', style: 'ITALIC' },
{ label: 'Underline', style: 'UNDERLINE' },
{ label: 'Monospace', style: 'CODE' },
];
const InlineStyleControls = (props) => {
var currentStyle = props.editorState.getCurrentInlineStyle();
return (
"RichEditor-controls"]}>
{INLINE_STYLES.map(type =>
type.label}
active={currentStyle.has(type.style)}
label={
type.label}
onToggle={props.onToggle}
style={
type.style}
/>
)}
);
};
MyEditor.propTypes = {
};
export default MyEditor;
样式文件 component/Rich.less
.RichEditor-root {
background: #fff;
border: 1px solid #ddd;
font-family: 'Georgia', serif;
font-size: 14px;
padding: 15px;
}
.RichEditor-editor {
border-top: 1px solid #ddd;
cursor: text;
font-size: 16px;
margin-top: 10px;
}
.RichEditor-editor .public-DraftEditorPlaceholder-root,
.RichEditor-editor .public-DraftEditor-content {
margin: 0 -15px -15px;
padding: 15px;
}
.RichEditor-editor .public-DraftEditor-content {
min-height: 100px;
}
.RichEditor-hidePlaceholder .public-DraftEditorPlaceholder-root {
display: none;
}
.RichEditor-editor .RichEditor-blockquote {
border-left: 5px solid #eee;
color: #666;
font-family: 'Hoefler Text', 'Georgia', serif;
font-style: italic;
margin: 16px 0;
padding: 10px 20px;
}
.RichEditor-editor .public-DraftStyleDefault-pre {
background-color: rgba(0, 0, 0, 0.05);
font-family: 'Inconsolata', 'Menlo', 'Consolas', monospace;
font-size: 16px;
padding: 20px;
}
.RichEditor-controls {
font-family: 'Helvetica', sans-serif;
font-size: 14px;
margin-bottom: 5px;
user-select: none;
}
.RichEditor-styleButton {
color: #999;
cursor: pointer;
margin-right: 16px;
padding: 2px 0;
display: inline-block;
}
.RichEditor-activeButton {
color: #5890ff;
}