概览
本文是关于最近使用braft-editor富文本编辑器的一些较为常见、实用的功能开发的记录,分为以下三部分:
- "格式刷"的实现
- 链接插入自动带上协议
- 插入自定义内容的实现
1、“格式刷”的实现
-
效果展示
-
核心代码
// 定义扩展控件
const extendControls = [
{
key: 'copy-style',
type: 'component',
component: (
<button
onClick={() => {
if (!copyStyles) {
const style = ContentUtils.getSelectionInlineStyle(editorState)
// 获得样式列表,如下方截图所示
copyStyles = style._map._list?._tail?.array || null
console.log(copyStyles)
} else {
copyStyles = null
alert('复制的样式已清除')
}
}}
className='control-item button '
style={{ color: copyStyles ? '#3498db' : '#6a6f7b' }}
>
复制样式
</button>
)
},
{
key: 'paste-style',
type: 'button',
text: '粘贴样式',
onClick: () => {
if (copyStyles) {
// 样式拷贝到选中区域
const nextEditorState = copyStyles.reduce((editorState, styleArray) => {
const style = styleArray[0]
return ContentUtils.toggleSelectionInlineStyle(editorState, style, '')
}, editorState)
setEditorState(nextEditorState)
} else {
alert('请先获得样式')
}
}
}
]
- 备注
- 增加扩展控件,详见官方文档
- 获得的样式列表实例截图
2、链接插入自动带上协议
-
效果展示
-
核心代码
const hooks = {
'toggle-link': ({ href, target }) => {
href = href.indexOf('http') === 0 ? href : `https://${href}`
return { href, target }
}
}
<BraftEditor hooks={hooks}/>
3. 插入自定义内容的实现
-
展示效果
-
核心代码
import React, { useState } from 'react'
import 'braft-editor/dist/index.css'
import 'braft-extensions/dist/table.css'
import BraftEditor from 'braft-editor'
import { ContentUtils } from 'braft-utils'
import './index.scss'
// 自定义组件,可加入自定义功能
const BlockColorComponent = (props: any) => {
const blockData = props.block.getData()
const text = blockData.get('text') // 获得捕获的插入文本
// 注意:通过blockRendererFn定义的block,无法在编辑器中直接删除,需要在组件中增加删除按钮
const removeBarBlock = () => {
props.blockProps.editor.setValue(
ContentUtils.removeBlock(props.blockProps.editorState, props.block)
)
}
return (
<div className='block-color'>
<i className='height_light_line_icon'></i> {text}
{/* 删除按钮,悬浮出现,定义输出时去掉 */}
<button className='button-remove' onClick={removeBarBlock}>
<i className='bfi-bin'></i>
</button>
</div>
)
}
// 声明blockRendererFn
const blockRendererFn = (block: any, { editor, editorState }: any) => {
// 对指定类型的捕获
if (block.getType() === 'block-color') {
return {
component: BlockColorComponent, // 自定义组件
editable: false, // 此处的editable并不代表组件内容实际可编辑,强烈建议设置为false
props: { editor, editorState } // 传入自定义组件BlockColorComponent的数据,通过props.blockProps获取到
}
}
// 不满足block.getType() === '***'的情况时请勿return任何内容以免造成其他类型的block显示异常
}
// 自定义block输入转换器,用于将符合规则的html内容转换成相应的block,通常与blockExportFn中定义的输出转换规则相对应
const blockImportFn = (nodeName: any, node: any) => {
if (nodeName === 'div' && node.classList.contains('block-color')) {
// 捕获标签内部文本
const text = node.innerText
return {
type: 'block-color',
data: { text } // 把文本传入后续的自定义组件
}
}
}
// 自定义block输出转换器,用于将不同的block转换成不同的html内容,通常与blockImportFn中定义的输入转换规则相对应
const blockExportFn = (contentState: any, block: any) => {
if (block.type === 'block-color') {
return {
start: `<div class='block-color'><i class='height_light_line_icon'></i>`,
end: '</div>'
}
}
}
const initContent = `<p><div class='block-color'>自定义高亮内容</div></p>`
export const CourseText = (props: any) => {
// 使用createEditorState时,需要将上文定义的blockImportFn和blockExportFn作为第二个对象参数的成员传入
const [editorState, setEditorState] = useState(
BraftEditor.createEditorState('<p></p>', {
blockImportFn,
blockExportFn
})
)
const handleChange = (editorState: any) => {
setEditorState(editorState)
}
const extendControls = [
{
key: 'insert-text',
type: 'button',
text: '插入高亮内容',
onClick: () => {
setEditorState(
ContentUtils.insertHTML(editorState, initContent, {
blockImportFn,
blockExportFn
})
)
}
}
]
// 在组件中传入上文定义的blockRendererFn
// 并将blockImportFn和blockExportFn传入组件的converts属性
return (
<div>
<div className='editor-wrapper'>
<BraftEditor
id='editor-1'
value={editorState}
onChange={handleChange}
placeholder={'请输入内容'}
blockRendererFn={blockRendererFn}
converts={{ blockImportFn, blockExportFn }}
extendControls={extendControls}
/>
</div>
</div>
)
}
- 备注
- 使用blockRendererFn和blockRenderMap两种方式扩展block
- 使用blockImportFn和blockExportFn定义block的输入和输出转换
- 详见可参考,官方实例