最近项目中h5端要实现图文上传,而且还要支持用户用户输入的格式,例如换行啥的,那么使用输入控件保存输入内容,图片上传控件就不合适了,因为很难知道用户的输入样式。

如果使用一些现有的富文本编辑器,貌似又不是很划算,所以综合考虑使用div来自己实现一个就是比较理想的方案了。

先来考虑一下,如果使用div来实现简单的富文本编辑器,需要解决哪些问题?

首先,div默认是不可编辑的,需要设置它可以编辑,这个很简单只需要使用

   contentEditable="true"

其次,我们需要在div指定的位置插入图片,指定位置就是光标所在的位置,那么我们插入图片的时候,需要知道光标的位置,网上查了下应该是需要getSelection API W3Cschool上面直接有简单的用法,感兴趣的童鞋可以去看看。

获取当前光标选中位置

let selection = window.getSelection();
let range = selection.getRangeAt(0);

那么知道了光标位置,怎么插入图片?

 let img = document.createElement("img");img.src = json.url;//最大宽度为手机宽度减去20img.style.maxWidth = (width-20) + 'px';range.insertNode(img);//选中位置插入图片

这就完了?

当然还没完,实现中遇到了另一个问题,那就是焦点的变化。如果我想插入图片,我就首先需要上传图片,但是当我点击上传图片的按钮的时候,焦点就已经发生了变化,这个时候获取的选中位置就是你点击的位置!

那么该如何解决这个问题呢?

仔细分析,点击的时候,焦点变化的时候,我们需要记录下上次焦点的位置,上次焦点的位置在哪里?在可编辑的div中,焦点变化的时候,就是可编辑div失去焦点的时候!

那么是否可以监听div失焦这个事件呢?答案当然是的!

 onBlur={() => {let selection = window.getSelection();range = selection.getRangeAt(0);}}

给div实现onBlur监听就可以了,是不是很简单?

接下来看一下完整的代码

import React, {Component} from "react";
import "../../assets/css/topic/DivEdit.css";
import "../../assets/common/second-common.css";
​
let range;
let width = document.documentElement.clientWidth;
//头部栏
class DivEdit extends Component {constructor(props) {super(props);let typeArr = [".png", ".jpg", ".jpeg", ".bmp", ".gif"];this.state = {id:'',inputValueHtml: '',fileType: typeArr,showTips:true}}
​
​//光标定位在可编辑div的开始的位置setStartFocus() {
​document.querySelector('#my-question-define-edit').focus();
​}
​
​//光标定位在内容的尾端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 选择文件triggerSelect() {return document.getElementById('topic-add-img').click();}
​
​//处理上传文件handleChange(file) {// 判断文件类型进行上传if (window.typeMatch(this.state.fileType, file.name)) {// 上传文件this.saveFile(file);} else {Toast.fail("文件类型不符,请重新选择", 3);}}
​// 上传文件saveFile(file) {//你们自己处理上传的处理 //当成功的时候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'}}>输入您的问题...</span>:null
​}
​<div className={'add-bottom-menu'}>
​<img style={{width: 20, position: 'absolute', left: 10}}src={require("../../assets/images/topic_topic_show.png")}alt='箭头'/>
​
​<div className={'topic-add-pic'}onClick={() => {//调起上传图片this.triggerSelect();}}><img style={{width: 20}}src={require("../../assets/images/topic_upload_pic.png")}alt='上传图片'/>
​<span style={{marginLeft: 10, fontSize: 15}}>上传图片</span></div>
​
​</div><div style={{visibility: 'hidden'}}><inputtype="file"id={'topic-add-img'}style={{display: "none"}}onChange={e => this.handleChange(e.target.files[0])}/></div>
​</div>
​);}
}
​
export default DivEdit;​

样式表

.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;
​
}

更多内容,欢迎同步关注作者公众号二维码!
程序员内功修炼手册 主要发布计算机基础、设计模式、计算机网络基础知识,同时重点关注大前端知识
Android、iOS、web前端、Flutter、React Native等,想学习大前端知识的速度来吧,一起学习、一起成长!

React H5 使用div自定义简单富文本编辑器相关推荐

  1. 原生API编写简单富文本编辑器001

    原生API编写简单富文本编辑器001 系列文章快速阅读: 富文本编辑器开发系列-1-基础概念 富文本编辑器开发系列2-document.execCommand 的API 富文本编辑器开发系列3-sel ...

  2. html自定义实现文本编辑器,自定义开发富文本编辑器(Javascript实现点击插入内容到textarea光标处)...

    富文本编辑器相信很多程序员都用过,但是如何自己制作一个仿富文本的编辑器来解决一些简单的或自定义的需求呢?下面给大家共享一个使用JavaScript实现在textarea光标处插入指定文本内容以及字符串 ...

  3. 灵活可扩展,2023年值得尝试的13款富文本编辑器

    作为前端开发人员,我们经常需要为网站和应用程序添加文本内容.与传统的文本编辑器不同,富文本编辑器可让您轻松创建各种类型的文本内容,包括加粗字体.斜体字.框架.列表.图片和视频等. 本文我将向大家推荐 ...

  4. html实现富文本编辑器,前端程序员福利,6款轻量级富文本编辑器,轻松实现富文本编辑...

    1.国产富文本编辑wangEditor 基于javascript跟css开发的 Web富文本编辑器, 轻量.简洁.易用.开源免费,样式可自定义typecho 富文本编辑器,菜单栏可以自定义配置. 下载 ...

  5. 富文本编辑器开发系列5——浏览器`Selection API`探究

    系列文章快速阅读: 富文本编辑器开发系列-1-基础概念 富文本编辑器开发系列2-document.execCommand 的API 富文本编辑器开发系列3-selection 富文本编辑器开发系列4- ...

  6. vue 是否有word编辑控件_GitHub - C84882428/editor-ui: vue集成 tinymce 富文本编辑器,增加导入 word 模板...

    editor-ui vue 集成 tinymce 富文本编辑器 自定义 tinymce 富文本编辑器, 在原来的编辑器中增加上传 word 模板 最终展示效果: 主要代码: 整体思路: 1,在编辑器原 ...

  7. Taro React组件开发(2) —— RuiEditor 富文本编辑器【兼容H5和微信小程序】

    1. 富文本编辑器需求分析 需要实现图片上传显示,上传使用Taro的 chooseImage 和 uploadFile,完成图片的上传!!! 文字的居左.居中.居右展示,使用格式化方法 format! ...

  8. html编辑器自定义脚本,CKeditor富文本编辑器使用技巧之添加自定义插件的方法

    本文实例讲述了CKeditor富文本编辑器使用技巧之添加自定义插件的方法.分享给大家供大家参考,具体如下: 首先就是在CKeditor的plugins目录下新建一个目录qchoice: qchoice ...

  9. Quill – 可以灵活自定义的开源的富文本编辑器

    Quill 的建立是为了解决现有的所见即所得(WYSIWYG)的编辑器本身就是所见即所得(指不能再扩张)的问题.如果编辑器不正是你想要的方式,这是很难或不可能对其进行自定义以满足您的需求. Quill ...

最新文章

  1. JavaScript代码检查工具——JSLintMate
  2. Ardino基础教程 21_最简单最快控制LCD1602
  3. 数据库原理与应用(SQL Server)教程 主键、外键以及联合主键、复合主键和设置种子数目和增量
  4. 杭州保俶塔实验机器人_【科教有闻】高照实验学校Pepper机器人课程亮相2020(杭州)国际数字教育大会“智能教育引领未来”论坛...
  5. 第十届数据技术嘉年华活动彩蛋!
  6. NoSQL架构的几幅图
  7. AI创作教程之 Stable Diffusion 为何是人工智能新时代艺术创作的基石
  8. DeepFace--Facebook的人脸识别
  9. c语言输出最大的数ns流程图_c语言中swtich怎么画流程图
  10. Agents and Multi-agent System考试重要知识点整理
  11. 不用重启电脑,就可以刷新系统变量
  12. 任正非的“先僵化、后优化、再固化”方针
  13. 中望3D 2022 基准平面
  14. html5 2020视觉效果,体验未来:10个会让你惊叹不已的HTML5画布(CANVAS)技术应用演示-UI博客精选...
  15. 英汉互译在线翻译器如何语音互译中英文
  16. 「Unity2D」使用Unity创建一个2D游戏系列-9
  17. 外卖跑腿小程序APP定制开发扫码点餐配送
  18. html中常用的三种列表,在html语言中,常用的列表有哪三种
  19. 恢复桌面上的IE图标,并非快捷方式
  20. Windows预览体验计划0x80072ee7、0x0报错解决方法

热门文章

  1. 计算2个时间段的重叠天数
  2. 不敢相信!那些真实存在的机器人女友们!
  3. 劝学:不积跬步,无以至千里,不积小流,无以成江海.
  4. uniapp的项目,scss和js实现跑马灯
  5. 使用jdbc:nested exception is java.sql.SQLException: No value specified for parameter或bad SQL grammar
  6. 论文阅读:基于多模态词向量的语句距离计算方法
  7. 便签里的文件怎么分享?怎么把便签里的内容弄成文件发送
  8. 智能硬件开发如何选择低功耗MCU?
  9. STM32F4之ADC介绍
  10. 【Devc++】战斗1.0.2