draft.js--富文本编辑器框架的实践(一)
来源:互联网 发布:一搜网络同志建站 编辑:程序博客网 时间:2024/05/17 18:17
市面上大多数的富文本编辑器都是现成的,很难根据自己的需求进行无论是功能亦或是渲染格式的修改。
而由脸书开源的这款draft.js在富文本编辑器中简直是一股清流般的存在。draft在英文中是“草稿”的意思,如它名字所言,它并不是一款现成的富文本编辑器,而是一款富文本编辑器框架,这意味着你可以在此基础上进行二次开发,写出适合你自己应用场景的富文本编辑器。
下面会写出一些我个人对这款富文本编辑器的实践路线。
- 安装
- 初始化一个draft编辑器的实例
- 对编辑器进行样式修改
- 增加格式按钮
- 行渲染以及行样式修改
- 默认块以及块样式修改
- 格式以及对应格式按钮之间的高亮联系
- 自定义块的元素渲染以及修改默认块所对应的映射元素
- 插入行元素,如emoji表情
- 插入块元素,如图片或者视频
- 数据存储
- 数据回显
(一)安装:
npm install --save draft-js
(二)初始化一个draft编辑器的实例:
//Editor.js//Editor是一个自定义的组件 import React, {findDOMNode, Component} from 'react';import { convertFromRaw, convertToRaw, CompositeDecorator, DefaultDraftBlockRenderMap, ContentState, Editor, EditorState, Entity, RichUtils, getDefaultKeyBinding, KeyBindingUtil, Modifier} from 'draft-js';import style from './css.css';//这里使用了css-Moudlesexport default class componentName extends Component{ constructor(props){ super(props); this.state = { editorState:EditorState.createEmpty() }; this.focus = () => this.refs.editor.focus(); this.onChange = (editorState) => this.setState({editorState}); } render(){ const {editorState} = this.state; const { } = this.props; return( <Editor editorState={editorState} onChange = {this.onChange} ref="editor" > </Editor> ) }}
这样,就能渲染出一个最简单的文本编辑器,你现在可以在里面输入点什么。
(三)对编辑器进行样式修改。
我的做法是,在<Editor/>
的最外层加几个样式DIV。
<div className={style.editorRoot} onClick={this.focus}> <Editor editorState={editorState} onChange = {this.onChange} blockStyleFn={getBlockStyle} ref="editor" > </Editor></div>
(四)增加格式按钮:光能输入不行,得有什么东西来控制输入文字的格式。按钮和编辑器是分开的,所以我写了一个编辑器按钮的组件,让这些组件与<editor/>
同级。
<div className={style.init}> <div className={style.operate}> <InlineStyle/> <BlockStyle/> <ColorStyle/> </div> <div className={style.editorRoot} onClick={this.focus}> <Editor editorState={editorState} onChange = {this.onChange} ref="editor" > </Editor> </div> <Post storeHandle={this.storeHandle}>保存</Post> </div>
至于里面具体的样式,你可以自己调。现在我的编辑器长这样:
但是现在只有格式,按钮并没有具体的功能,下面我们把功能加上去。
功能无非就是为输入的文字加上相应的格式。
一共有两种格式:行和块。
(五)行样式渲染以及修改: 这里最好分成几个小步骤
- 确定行格式需要的功能以及对应的类名
- 确定行样式的映射类
- 使用
RichUtils.toggleBlockType()
方法获取新的editorState - 在组件
<Editor/>
上添加映射类
开始步骤:
1)确定行格式需要的功能以及对应的类名:
// 行按钮,关键属性 styleName//这个数组可以用于渲染按钮,在点击事件中把styleName传给父方法_toggleInlineStyle()const InlineType = [ {key:1,label:'B',styleName:'Bold',title:'加粗',iconClassName:''}, {key:2,label:'I',styleName:'Italic',title:'斜体',iconClassName:''},];
2)确定行样式的映射类:
//行样式映射const editorStyleMap = { //字体 Bold:{ fontWeight: '600', }, Italic:{ fontStyle: 'italic', },};
3)使用RichUtils.toggleBlockType()
方法获取新的editorState:
//接受按钮传过来的styleName, RichUtils.toggleInlineStyle()返回一个新的editorState.使用this.onChange()进行更新。 _toggleInlineStyle = (inlineStyle)=>{ this.onChange( RichUtils.toggleInlineStyle( this.state.editorState, inlineStyle ) ) };
4)在组件<Editor/>
上添加映射类:
<Editor customStyleMap = {editorStyleMap} editorState={editorState} onChange = {this.onChange} ref="editor" > </Editor>
这样,当你选中一段文字,再点击相应的格式按钮时,你选中的文字内容就会被加上相应的css样式。
(六)默认块以及默认块样式修改:
draft.js提供了几个默认块的styleName以及对应渲染的元素:
也就是说,如果styleName使用了右侧这些名字,他们会被渲染成左侧这些标签。而不是行元素的span。
还是分成几个步骤吧:
1. 确定行格式需要的功能以及对应的类名
2. 使用RichUtils.toggleBlockType()
方法获取新的editorState
1)确定行格式需要的功能以及对应的类名:
//和行样式一样,可以用于渲染块格式按钮。//在点击事件中,把styleName传给父的RichUtils.toggleBlockType()中。//有一点必须注意,这里的styleName只能是Draft.js默认的样式名,也就是上图右侧的名字。因为我们现在就是使用默认块。const BlockType = [ {key:1,label: 'H', styleName: 'header-two',title:'小标题',iconClassName:''}, {key:2,label: '“ ”', styleName: 'blockquote',title:'引用',iconClassName:''}, {key:3,label: '</>', styleName: 'code-block',title:'代码块',iconClassName:''}, {key:4,label: '', styleName: 'unordered-list-item',title:'有序列表',iconClassName:'iconfont icon-other editorButtonIcon'}, {key:5,label: '', styleName: 'ordered-list-item',title:'无序列表',iconClassName:'iconfont icon-other editorButtonIcon'},];
2)使用RichUtils.toggleBlockType()
方法获取新的editorState
//块格式//按钮把styleName传给这个方法,得到新的editorState并更新。 _toggleBlockType = (blockType)=>{ this.onChange( RichUtils.toggleBlockType ( this.state.editorState, blockType ) ); };
这样就成功使用了draft.js默认的块格式了。下面是默认格式blockquote的效果图:
也许你觉得默认格式太丑了,我想修改一下。draft.js的组件<Editor/>
提供了一个属性blockStyleFn,就是用来读取自定义样式的。
- 在css中自定义格式。
- 声明一个方法,把自定义格式的css的类名和styleName对应上。
- 在
<Editor/>
上增加属性blockStyleFn。
1)在css中自定义格式。
//css//我使用了css-Moudles,所以加上了:global():global(.RichEditor-blockquote){ display:block; border-left: 5px solid #d2d2d2; color: #666; margin: 0 0; padding: 5px 20px; font-size: 15px; font-style: italic; background-color: #eff9ff;}
2)声明一个方法,把自定义格式的css和styleName对应上:
function getBlockStyle(blockName){ switch(blockName.getType()){ case 'blockquote' : return 'RichEditor-blockquote'; default: return null; }}
2)在<Editor/>
上增加属性blockStyleFn:
<Editor customStyleMap = {editorStyleMap} editorState={editorState} onChange = {this.onChange} blockStyleFn={getBlockStyle} ref="editor"/>
在css中可以发现,我把背景色由原来的灰色换成了浅蓝色。现在引用格式长这样:
(七)格式以及对应格式按钮之间的高亮联系:
draft.js的demo给出了当光标在有格式的文本时对应的格式按钮高亮的实现方法。在这里稍微介绍一下。
核心思路是,通过editorState
这个对象的一些方法获取当前光标所在的“标签”(也就是“格式”)的styleName,然后和按钮的styleName进行对比,如果===,则表示现在光标所在的文本格式中有用到这个styleName。这时加上对应的className即可。
行和块获取当前的styleName的方法是不一样的。
1)行:
//按钮组件与editor组件有一层中介组件InlineStyleControl组件,用以渲染按钮。//@InlineType就是由父组件Editor传进来的那个行按钮格式数组。 render(){ const { editorState, InlineType } = this.props; //获取所有的行样式名 const inlineType = editorState.getCurrentInlineStyle(); return( <div className={style.init}> {InlineType.map((obj)=>{ return <ButtonType key={obj.key} //进行对比。 active={inlineType.has(obj.styleName)} title={obj.title} label={obj.label} iconClassName = {obj.iconClassName} styleName={obj.styleName} onToggle = {this.props.onToggle} /> })} </div> ) }
//按钮组件ButtonType的renderrender(){ const { title, label, active, iconClassName, } = this.props; let classNames; if(active){ //有的话,加上这个CSS类名 classNames = 'editorActiveButton' } return( <span className={style.init + ' ' + classNames + ' ' + iconClassName} title={title} onClick = {this.onToggle} > {label} </span> ) }
现在的效果是这样,当光标在斜体内容里时,斜体按钮”I”会有红色高亮。
块格式实现相同的效果和行格式有一点点区别。区别在获取当前有哪些格式的方法上。
//BlockStyleControl组件render(){ const { editorState, BlockType } = this.props; // 这里开始获取当前光标所在的格式的类名 let selection = editorState.getSelection(); let blockStyle = editorState .getCurrentContent() .getBlockForKey(selection.getStartKey()) .getType(); return( <div className={style.init}> {BlockType.map((obj)=>{ return <ButtonType key={obj.key} //检查 active = {blockStyle === obj.styleName} title={obj.title} label={obj.label} iconClassName = {obj.iconClassName} styleName={obj.styleName} onToggle = {this.props.onToggle} /> })} </div> ) }
效果图如下:
有了这个小功能。用户就可以再点击一次按钮,把格式取消或者加上。
- draft.js--富文本编辑器框架的实践(一)
- draft.js--富文本编辑器框架的实践(二)
- (翻译)draft.js 创建简单的富文本编辑器
- 富文本编辑器需要用到的js框架
- 富文本编辑器实践
- 富文本编辑器的基本原理与实践
- 富文本编辑器的基本原理与实践
- 富文本编辑器ueditor的使用实践
- summernote富文本编辑器的基本使用(一)
- 自定义 富文本编辑器(一) 前言
- Android富文本编辑器总结(一)
- JS实现富文本编辑器
- js基础-富文本编辑器
- 收集到的相关CSS 框架 富文本编辑器
- 所见即所得的jQuery富文本编辑器插件-wysiwyg.js
- 目前可用的Draft.js rte编辑器
- (翻译)Draft.js编辑器简介
- 我的富文本编辑器
- 如何在 React Native 实现类微信小程序平台:WebView 调用原生组件
- 我是如何为技术博客设计一个推荐系统(上):统计与评分加权
- cocoaPods更新慢的问题
- 事件过滤器
- 常用工具SDK
- draft.js--富文本编辑器框架的实践(一)
- 第六章 注解式控制器详解——跟着开涛学Spring
- 《数据库SQL实战》取倒数第三
- 成为android工程师的30+个小技巧
- 问题笔记
- 猿味鸡汤 — 我有6个项目经理职场秘籍送给你
- linux常用概念
- 解决防火墙因存储空间被过多的更新包占用导致无法升级的问题
- Mac google右键翻译