在我的简单draft.js project上,我尝试将从外部表单上传的图像插入到编辑器的内容中。我使用的编辑器是内部使用draftjs编辑器的react-draft-wysiwyg 。
我的编辑器是从MyEditor.js渲染的:
import React, { Component } from 'react';
import { EditorState,AtomicBlockUtils } from 'draft-js';
import { Editor } from 'react-draft-wysiwyg';
import 'react-draft-wysiwyg/dist/react-draft-wysiwyg.css';
class MyEditor extends Component {
state = {
editorState: EditorState.createEmpty(),
}
onEditorStateChange: Function = (editorState) => {
this.setState({
editorState,
});
};
uploadCallback(file,callback) {
return new Promise( (resolve, reject) => {
var reader = new window.FileReader();
reader.onloadend= () => {
fetch('http://localhost:9090/image',{
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: file.name,
data: reader.result,
}),
})
.then((resp) => resp.json())
.then((data)=>{
console.log('Uploaded Data',data);
const imageUrl='http://localhost:9090/image/'+data.name;
resolve({data:{ link: imageUrl } });
});
}
reader.readAsDataURL(file);
});
}
insertImage(url) {
console.log(this);
const contentState = this.state.editorState.getCurrentContent();
const contentStateWithEntity = contentState.createEntity(
'image',
'IMMUTABLE',
{ src: url },
);
const entityKey = contentStateWithEntity.getLastCreatedEntityKey();
const newEditorState = EditorState.set(
contentState,
{ currentContent: contentStateWithEntity },
);
const state=AtomicBlockUtils.insertAtomicBlock(newEditorState, entityKey, ' ');
this.setState({editorState:state});
};
render() {
const { editorState } = this.state;
const config={
image: { uploadCallback: this.uploadCallback }
}
return (
<Editor
editorState={editorState}
wrapperClassName="demo-wrapper"
editorClassName="demo-editor"
onEditorStateChange={this.onEditorStateChange}
toolbar={ config }
/>
);
}
}
export default MyEditor;
我有以下上传者:
import React, { Component } from 'react';
class UploadForm extends Component {
state={
lastImgUploaded:""
};
onChange(event){
event.preventDefault();
console.log("File Changed");
const file=event.target.files[0];
const reader = new window.FileReader();
reader.onloadend= () => {
fetch('http://localhost:9090/image',{
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: file.name,
data: reader.result,
}),
})
.then((resp) => resp.json())
.then((data) => {
console.log('Uploaded Data',data);
const imageUrl='http://localhost:9090/image/'+data.name;
if(this.props.uploadCallback){ this.props.uploadCallback(imageUrl); }
this.setState({'lastImgUploaded':imageUrl})
});
}
reader.readAsDataURL(file);
}
render(){
return (
<div>
<h3>Upload an image and set it into the editor</h3>
<input type="file" onChange={ this.onChange.bind(this) } name="file"/>
</div>);
}
}
export default UploadForm;
我有和包含整个应用程序源的App.js:
import React, { Component } from 'react';
import Editor from './MyEditor';
import UploadForm from './UploadForm';
import logo from './logo.svg';
import './App.css';
class App extends Component {
state={
uploadedImage:""
};
uploadCallback(link){
this.setState({'uploadedImage':link});
this.__editor.insertImage(link).bind(this.__editor);
}
render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">Welcome to React</h1>
</header>
<div className="App-editor">
<Editor ref={ (editor) => {this.__editor=editor; } } />
</div>
<div className="SideBar">
<div className="LastUpload">
<h3>Last Uploaded Image</h3>
<img src={this.state.uploadedImage} />
</div>
<div className="sideBarUpload">
<UploadForm uploadCallback={ this.uploadCallback.bind(this) }/>
</div>
</div>
</div>
);
}
}
export default App;
我想要实现的是当图像从表单上传到我的api时,成功上传后将上传的图像插入到编辑器中。我尝试用MyEditor.js
上的以下方法实现:
insertImage(url) {
console.log(this);
const contentState = this.state.editorState.getCurrentContent();
const contentStateWithEntity = contentState.createEntity(
'image',
'IMMUTABLE',
{ src: url },
);
const entityKey = contentStateWithEntity.getLastCreatedEntityKey();
const newEditorState = EditorState.set(
contentState,
{ currentContent: contentStateWithEntity },
);
const state=AtomicBlockUtils.insertAtomicBlock(newEditorState, entityKey, ' ');
this.setState({editorState:state});
};
但由于某种原因,我得到错误:
editorState.getImmutable不是一个函数
在我的浏览器控制台上进一步调查证明,这种情况发生在以下方法中:
const newEditorState = EditorState.set(
contentState,
{ currentContent: contentStateWithEntity },
);
你知道为什么吗?
我设法通过将insertImage
中的MyEditor
更改为:
insertImage: Function = (url) => {
const editorState = this.state.editorState;
const block = new ContentBlock({
key: genKey(),
type: 'unstyled',
text: '<img src="'.concat(url).concat('"></img>'),
});
然后在App.js
我改变了uploadCallback
:
uploadCallback(link){
this.setState({'uploadedImage':link});
console.log(this.__editor);
this.__editor.insertImage(link);
}
但由于某种原因,我无法将图像看到编辑器的内容中。你知道为什么吗?
我试图使用回调onEditorStateChange
并且没有错误被抛出但我仍然没有获得Draft.js编辑器的更新内容。结果insertImage
是这一个:
insertImage: Function = (url) => {
console.log("Inserting Image");
const editorState = this.state.editorState;
const block = new ContentBlock({
key: genKey(),
type: 'unstyled',
text: url,
});
const contentState = editorState.getCurrentContent();
const blockMap = contentState.getBlockMap().set(block.key, block);
const newState = EditorState.push(editorState, contentState.set('blockMap', blockMap));
this.onEditorStateChange(newState);
};
最后,通过查看react-draft-wysiwyg的控件(https://github.com/jpuri/react-draft-wysiwyg/blob/master/src/controls/Image/index.js)有一个名为的方法:
addImage: Function = (src: string, height: string, width: string, alt: string): void => {
const { editorState, onChange, config } = this.props;
const entityData = { src, height, width };
if (config.alt.present) {
entityData.alt = alt;
}
const entityKey = editorState
.getCurrentContent()
.createEntity('IMAGE', 'MUTABLE', entityData)
.getLastCreatedEntityKey();
const newEditorState = AtomicBlockUtils.insertAtomicBlock(
editorState,
entityKey,
' ',
);
onChange(newEditorState);
this.doCollapse();
};
所以基于这个做这个:
insertImage: Function = (url) => {
console.log("Inserting Image",this.__editor);
const editorState = this.state.editorState;
const entityData = { src:url, height: 300, width: 300, };
const contentStateWithEntity=editorState.getCurrentContent().createEntity('IMAGE', 'IMMUTABLE', entityData);
const entityKey = contentStateWithEntity.getLastCreatedEntityKey();
let newEditorState = EditorState.set(editorState, { currentContent: contentStateWithEntity },);
newEditorState = AtomicBlockUtils.insertAtomicBlock(editorState,entityKey,' ',);
this.setState({editorState:newEditorState});
};