2.Draftjs 学习笔记-Rich Styling

来源:互联网 发布:六仔信誉盘源码 编辑:程序博客网 时间:2024/05/23 02:02

前提概要

draftjs的编辑器和input的区别就是,draft的值与状态是通过editorstate管理的,对比文档参考这里,editorstate的API 参考这里

正文

本章节主要是文本的简单样式控制,分别通过快捷键和按钮来实现

1. RichUtils and Key Commands(快捷键)

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 (      <Editor        editorState={editorState}        handleKeyCommand={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.

2. Styling Controls in UI (通过按钮控制样式)

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>        <button onClick={this._onBoldClick.bind(this)}>Bold</button>        <Editor          editorState={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 (            <div className={styles["RichEditor-root"]}>                <BlockStyleControls                    editorState={editorState}                    onToggle={this.toggleBlockType}                    />                <InlineStyleControls                    editorState={editorState}                    onToggle={this.toggleInlineStyle}                    />                <div className={className}  onClick={this.focus}>                    <Editor                        blockStyleFn={getBlockStyle}                        customStyleMap={styleMap}                        editorState={editorState}                        handleKeyCommand={this.handleKeyCommand}                        onChange={this.onChange}                        onTab={this.onTab}                        placeholder="Tell a story..."                        onFocus={()=>{console.log('focus')}}                        ref='editor'                        spellCheck={true}                        />                </div>            </div>        );    }}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 (            <span className={className} onMouseDown={this.onToggle}>                {this.props.label}            </span>        );    }}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 (        <div className={styles["RichEditor-controls"]}>            {BLOCK_TYPES.map((type) =>                <StyleButton                    key={type.label}                    active={type.style === blockType}                    label={type.label}                    onToggle={props.onToggle}                    style={type.style}                    />            )}        </div>    );};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 (        <div className={styles["RichEditor-controls"]}>            {INLINE_STYLES.map(type =>                <StyleButton                    key={type.label}                    active={currentStyle.has(type.style)}                    label={type.label}                    onToggle={props.onToggle}                    style={type.style}                    />            )}        </div>    );};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;}
2 0