图文
显示
-
以Entity的格式添加图片:
// 通过新建一个Entity,插入图片 appendImage(image) { const {editorState} = this.state; const contentState = editorState.getCurrentContent(); const imageSrc = image.data || image.file.path; // AtomicBlockUtils插入图片 const contentStateWithEntity = contentState.createEntity( 'image', 'IMMUTABLE', {src: imageSrc, image}, ); const entityKey = contentStateWithEntity.getLastCreatedEntityKey(); const newEditorState = EditorState.set( editorState, {currentContent: contentStateWithEntity} ); const newEditorStateWithAtomic = AtomicBlockUtils.insertAtomicBlock(newEditorState, entityKey, ' '); this.setState({ editorState: newEditorStateWithAtomic, }); }
通过
AtomicBlockUtil
创建的entity有一些问题:当前为空行时,图片会自动插入下一行; focus、删除等操作不是很正常; -
通过
blockRenderFn
属性传入自定义的图片组件// 自定义block样式 blockRendererFn(contentBlock) { const type = contentBlock.getType(); let result = null; if (type === 'atomic') { result = { component: DraftImage, editable: false, }; } return result; }
对contentBlock类型为
atomic
指定了自定义组件DraftImage
-
在
image.onload()
方法中获取图片原尺寸,根据输入框大小限定显示的图片尺寸import React from 'react'; import cs from 'classnames'; export default class DraftImage extends React.Component { constructor(props) { super(props); this.state = { src: '', isActive: false, }; } componentDidMount() { this.setImageSrc(this.props); } componentWillReceiveProps(nextProps) { this.setImageSrc(nextProps); } setImageSrc(props) { const {block, contentState} = props; const key = block.getEntityAt(0); if (!key) { return ''; } const entity = contentState.getEntity(key); if (entity && entity.getType() === 'image') { const data = entity.getData(); const image = new Image(); const imgSrc = data.src; image.onload = () => { const size = this.getImageSize(image); this.setState({ src: imgSrc, width: size.width + 'px', height: size.height + 'px', }); }; image.src = imgSrc; } } handleClick(e) { e.stopPropagation(); this.setState({ isActive: !this.state.isActive, }); } // 根据输入框宽高限制图片 getImageSize(image) { const origWidth = image.width; const origHeight = image.height; const editorWrapperRect = document.getElementsByClassName('chat-draft-editor')[0].getBoundingClientRect(); const maxWidth = editorWrapperRect.width - 10; const maxHeight = editorWrapperRect.height - 10; let newWidth = ''; let newHeight = ''; let ratio = 1; if (origHeight <= maxHeight && origWidth <= maxWidth) { newHeight = origHeight; newWidth = origWidth; } if (origHeight <= maxHeight && origWidth > maxWidth) { ratio = origWidth / maxWidth; newHeight = origHeight / ratio; newWidth = maxWidth; } if (origHeight > maxHeight) { ratio = origHeight / maxHeight; newWidth = origWidth / ratio; newHeight = maxHeight; } return {width: newWidth, height: newHeight}; } render() { const imgCls = cs({ 'draft-editor-image': true, 'img-active': this.state.isActive, }); if (this.state.src !== '' ) { return ( <img className={imgCls} style={{width: this.state.width, height: this.state.height}} src={this.state.src} onClick={this.handleClick.bind(this)} /> ); } else { return null; } } }
-
通过监听
onPastedFiles(files)
方法处理粘贴的文件handlePastedFiles(files) { files.forEach((blob) => { if (blob.type.startsWith('image/')) { const image = clipboard.readImage(); const url = image.isEmpty()? '': image.toDataURL(); this.appendImage({ data: url, }); } }); return 'handled'; }
Draftjs这个方法提供的
files
对象数据不够,只用来判断type是否为图片,读取数据仍使用的clipboard
;
发送
-
消息发送后,需要将文本框置空
这里有个bug,清空输入框文本时,不能立即Focus,否则内容不会被清空
为保证图文消息的发送顺序与输入框编辑时一致,对数组遍历时,设置固定延时: