Recently, the h5 end of the project is to upload graphics and text, but also to support user input format, such as line change, so using input control to save input content, picture upload control is not appropriate, because it is difficult to know the user's input style.
If you use some of the existing rich text editors, it seems not very cost-effective, so considering the use of div to achieve their own is an ideal solution.
Consider first what problems need to be solved if you use div to implement a simple rich text editor.
First of all, div is not editable by default and needs to be set up to edit it. This is very simple and only needs to be used.
contentEditable="true"
Secondly, we need to insert the image at the position specified by div. The position specified is the position of the cursor. When we insert the image, we need to know the position of the cursor. We need to search online for a simple use directly on the getSelection API W3Cschool. Interested children's shoes can be seen.
Get the current cursor selection position
let selection = window.getSelection(); let range = selection.getRangeAt(0);
So knowing the cursor position, how to insert the picture?
let img = document.createElement("img"); img.src = json.url; //Maximum width is mobile phone width minus 20 img.style.maxWidth = (width-20) + 'px'; range.insertNode(img);//Picture insertion at selected location
Is that all?
Of course, it's not over yet. Another problem encountered in the implementation is the change of focus. If I want to insert an image, I need to upload the image first, but when I click on the button to upload the image, the focus has changed. At this time, the selected position is where you click!
So how to solve this problem?
Careful analysis, when clicking, when the focus changes, we need to record the location of the last focus, where was the last focus? In editable divs, when the focus changes, the editable div loses focus!
Is it possible to monitor div out of focus? Of course the answer is yes!
onBlur={() => { let selection = window.getSelection(); range = selection.getRangeAt(0); }}
Is it easy to implement onBlur monitoring for div?
Next, take a look at the complete code
import React, {Component} from "react"; import "../../assets/css/topic/DivEdit.css"; import "../../assets/common/second-common.css"; let range; let width = document.documentElement.clientWidth; //Headbar class DivEdit extends Component { constructor(props) { super(props); let typeArr = [".png", ".jpg", ".jpeg", ".bmp", ".gif"]; this.state = { id:'', inputValueHtml: '', fileType: typeArr, showTips:true } } //Cursor position at the beginning of editable div setStartFocus() { document.querySelector('#my-question-define-edit').focus(); } //The cursor is located at the end of the content setEndFocus() { let srcObj = document.querySelector('#my-question-define-edit'); let selection = window.getSelection(); range = document.createRange(); range.selectNodeContents(srcObj); selection.removeAllRanges(); selection.addRange(range); range.setStart(srcObj, 1); range.setEnd(srcObj, 1); } // input Selection File triggerSelect() { return document.getElementById('topic-add-img').click(); } //Processing uploaded files handleChange(file) { // Judge the file type and upload it if (window.typeMatch(this.state.fileType, file.name)) { // Upload files this.saveFile(file); } else { Toast.fail("File type does not match, please re-select", 3); } } // Upload files saveFile(file) { //Handling uploads by yourselves/ when it's successful let img = document.createElement("img"); img.src = json.url; img.style.maxWidth = (width-20) + 'px'; if(range) { range.insertNode(img); }else{ this.setStartFocus(); let selection = window.getSelection(); range = selection.getRangeAt(0); range.insertNode(img); } } componentDidMount() { let question=this.props.question; this.setState({ inputValueHtml: '<p>' + question + '</p><br/><br/><br/>',showTips:!(question&&question!=='') }, () => { if(question&&question!==''){ this.setEndFocus(); } }); } getHtml(){ return this._editDiv.innerHTML; } render() { return ( <div className={'add-my-question-first-edit'} > <div id={'my-question-define-edit'} onFocus={() => { this.setState({showTips:false}); }} onBlur={() => { let selection = window.getSelection(); range = selection.getRangeAt(0); }} onClick={() => { let selection = window.getSelection(); range = selection.getRangeAt(0); }} ref={(editDiv) => this._editDiv = editDiv} className={'add-my-question-edit'} contentEditable="true" dangerouslySetInnerHTML={{__html: this.state.inputValueHtml}}/> { this.state.showTips? <span style={{ position: 'absolute', top:10, left:10, marginTop:'1.333rem', fontSize:17,color:'#E8E8E8' }}>Enter your questions...</span>:null } <div className={'add-bottom-menu'}> <img style={{width: 20, position: 'absolute', left: 10}} src={require("../../assets/images/topic_topic_show.png")} alt='Arrow'/> <div className={'topic-add-pic'} onClick={() => { //Pick up the uploaded picture this.triggerSelect(); }}> <img style={{width: 20}} src={require("../../assets/images/topic_upload_pic.png")} alt='Upload pictures'/> <span style={{marginLeft: 10, fontSize: 15}}>Upload pictures</span> </div> </div> <div style={{visibility: 'hidden'}}> <input type="file" id={'topic-add-img'} style={{display: "none"}} onChange={e => this.handleChange(e.target.files[0])} /> </div> </div> ); } } export default DivEdit;
style sheet
.add-my-question-first-edit { display: flex; flex-direction: column; flex: 1; } .add-my-question-first-edit .add-my-question-edit{ flex: 1; margin-top: 1.333rem; /*margin-bottom: 1.333rem;*/ font-size: 0.453rem; background-color: #fff; padding: 10px 10px 1.867rem; } .add-my-question-first-edit .add-bottom-menu{ position: fixed; bottom: 0; width: 100%; display: flex; flex-direction: row; align-items: center; justify-content: center; height: 1.067rem; background-color: #fff; border-top: #E8E8E8 solid 1px; } .add-my-question-first-edit .add-bottom-menu .topic-add-pic{ display: flex; flex-direction: row; align-items: center; align-self: center; }
More content, please pay attention to the author's two-dimensional code synchronously!