React中如何优雅的使用UEditor

栏目: 前端 · 发布时间: 6年前

内容简介:本文将介绍笔者在React的项目中使用百度的富文本编辑器Ueditor的过程。注意本文不提供一条龙式的使用方法,只是将使用过程中的一些实现思路进行总结,供以参考。react项目中导入ueditor,会存在各种不正交的问题,需要注意。首先在ueditor官网下载最新安装包,然后在项目入口的html中导入(导入方式不一,可以采用import的方式,需要自行度娘。但是无论哪种引入方式,只要想自定义功能,不正交问题就难以避免QAQ)。不管三七二十一先跑起来再说。。在React项目中使用ueditor要注意

本文将介绍笔者在React的项目中使用百度的富文本编辑器Ueditor的过程。注意本文不提供一条龙式的使用方法,只是将使用过程中的一些实现思路进行总结,供以参考。react项目中导入ueditor,会存在各种不正交的问题,需要注意。

引入

首先在ueditor官网下载最新安装包,然后在项目入口的html中导入(导入方式不一,可以采用import的方式,需要自行度娘。但是无论哪种引入方式,只要想自定义功能,不正交问题就难以避免QAQ)。不管三七二十一先跑起来再说。。

<!DOCTYPE HTML>
<html lang="en-US">

<head>
    <meta charset="UTF-8">
    <title>ueditor demo</title>
</head>

<body>
    <!-- 配置文件 -->
    <script type="text/javascript" src="path/ueditor.config.js"></script>
    <!-- 编辑器源码文件 -->
    <script type="text/javascript" src="path/ueditor.all.js"></script>
	······
</body>

</html>
复制代码

在React项目中使用ueditor要注意

  1. 导入的路径,笔者使用的是项目经webpack打包之后的相对路径。
  2. 导入顺序,配置文件要先于源码。
  3. 笔者这种引入方式存在缓存问题,所以修改ueditor.all.js后需要及时清理缓存,测试新的代码。

封装

/**
 * 封装UEditor
 */
import React from 'react';
import './index.less';

class UEditor extends React.Component {
    constructor(props) {
        super(props);
        this.editor = {};
        this.id = '';
    }
	······
    componentDidMount() {
        let UE = window.UE;
        let id = this.id;
        if (id) {
            try {
                /* 加载之前先执行删除操作,否则如果存在页面切换,
            再切回带编辑器页面重新加载时不刷新无法渲染出编辑器 */
                UE.delEditor(id);
            } catch (e) {}
            let ueditor = UE.getEditor(id, {
                toolbars: [
                    ['bold', 'italic', 'underline', 'kityformula', 'diyimg']
                ],
                initialContent: '',
                autoHeightEnabled: false,
                autoFloatEnabled: false,
                elementPathEnabled: false,
                wordCount: false,
                enableAutoSave: false,
                initialFrameWidth: this.props.width,
                initialFrameHeight: this.props.height
            });
        }
    }
    render() {
        this.id = this.props.id;
        return <div styleName="content" id={this.id} />;
    }
}

export default UEditor;

复制代码

笔者在项目中使用了加粗,斜体,下划线,插入图片,公式等功能,想要自定义配置均可参照ueditor.config.js修改。具体的将一一介绍,最后实现效果如下:

React中如何优雅的使用UEditor

问题总结:

1. 禁止自动增高,改用滚动条

autoHeightEnabled: false
initialFrameWidth:this.props.width
initialFrameHeight:this.props.height
复制代码

autoHeightEnabled 可以阻止自动增高,然后再自定义容器宽度和高度。

2. 自定义全局样式,如容器的padding,p标签的line-height等

解决方法:ueditor.all.js的第6800多行的 render 方法,在其中可以自定义全局样式。

React中如何优雅的使用UEditor

3. 导航条切换后,无法再次渲染

解决方法:在每次ueditor实例化之前,先删除对应的id

UE.delEditor(id);
复制代码

原因分析:

从实例化和卸载实例的源码来看:

getEditor

UE.getEditor = function (id, opt) {
    var editor = instances[id];
    if (!editor) {
        editor = instances[id] = new UE.ui.Editor(opt);
        editor.render(id);//渲染编辑器
    }
    return editor;
};
复制代码

delEditor

UE.delEditor = function (id) {
    var editor;
    if (editor = instances[id]) {
        editor.key && editor.destroy();
        delete instances[id]
    }
};
复制代码

UE在全局管理了一个实例池,每次实例化都会根据id检索,然后生成实例。从 getEditor 的源码中可以看出,ueditor的一个实例在 第一次初始化时 存在一个 editor.render() ,这是将此id的实例渲染到对应的id容器上。然而,当用户tab切换编辑器再切回来时,此时由于 该实例已在实例池中存在 ,于是直接执行 return editor ,所以少了editor.render()这一步,于是不能重新渲染。所以,在Ueditor组件每次实例化之前,先进行delEditor卸载。这里需要注意,从 delEditor 中可以看出ueditor卸载实例时调用了实例的destroy方法。从destroy的注释来看: 销毁编辑器实例,使用textarea代替 ,这解释了为什么在切换编辑器或者卸载编辑器时,会出现编辑器变为textarea的情况,如图所示:

React中如何优雅的使用UEditor

4. 模拟placeholder实现预置文案

解决方法:在UE的实例中自定义方法,实现填充文字模拟placeholder的效果,代码如下:

//模拟placeholder和控制toolbar显示隐藏
UE.Editor.prototype.initDiy = function (placeholder) {
    var _editor = this;
    //获取焦点
    _editor.addListener("focus", function () {
        UE.isEditored = true;
        var Text = `<p style="color: #CDCDCD">${placeholder}</p>`
        var localHtml = _editor.getContent();
        if (localHtml === Text) {
            _editor.setContent("");//点击时清空
            _editor.focus(true);
        }
        //使得其他 工具 条display置为none
        var list = document.querySelectorAll('.edui-editor-toolbarbox');
        list.forEach((ele) => {
            ele.style.display = 'none';
        });
        var toolbar = findKey(_editor.key);
        toolbar.style.display = 'block';
    });
    // 插入图片时存在问题
    // _editor.addListener("blur", function () {
    //     var localHtml = _editor.getContent();
    //     if (localHtml === '') {
    //         _editor.setContent(`<p style="color: #CDCDCD">${placeholder}</p>`);
    //     }
    //     // window.activeEditor = _editor.key;
    // });
    _editor.ready(function () {
        // _editor.fireEvent("blur");
        _editor.setContent(`<p style="color: #CDCDCD">${placeholder}</p>`);//填充预置文案
    });  
}
//寻找工具条
function findKey(key) {
    let ele = document.querySelector(`#${key}`);
    let toolbar = ele.querySelector('.edui-editor-toolbarbox');
    return toolbar;
}
复制代码

原来,笔者实现的效果是点击时清空,失焦时还原。但是,在做自定义工具条时产生了bug(在5中我会细说),因此我采用了另一种方案: 初始时设置预设文案,当用户聚焦时清空预设,用户失焦后不再恢复该预设文案 。也就是将blur事件注释了。。。

5. 工具条显示在编辑器头部,显示为悬浮效果,默认隐藏,聚焦时出现

实现思路:将themes/default/css/ueditor.css中加入:

.edui-default .edui-editor-toolbarbox {
    position: absolute;
    ······
    top: -36px;
}
复制代码

首先实现头部偏移,然后通过控制toolbar对应dom元素的display来隐藏工具条。实现效果如下:

React中如何优雅的使用UEditor

下面解释一下 为什么编辑器失焦的时候不恢复预置文案

从4中的代码可以看出,我们是通过触发focus和blur事件分别清空和填充编辑器的内容。但是当我们点击工具条时,编辑器就会触发blur事件!!于是就会出现各种bug。以百度官网的ueditor为例,控制台输入:

React中如何优雅的使用UEditor

为该编辑器注册点击事件,当点击加粗按钮时,控制台输出:

React中如何优雅的使用UEditor

为了避免点击工具条时触发blur事件,笔者将自定义的blur事件全部注释了。

6. 自定义按钮和七牛云图片上传

首先,在ueditor.config.js中找到toolbars数组,增加一个diyimg字符串,然后在zh-cn.js找到labelMap数组,在末尾加上 'diyimg': '插入图片' 。最后,在ueditor.all.js中找到btnCmds数组,加入diyimg字符串。初始化时使用这个字符串,工具条上就会显示一个按钮,但是我们发现他显示的是这样的:

React中如何优雅的使用UEditor

这是因为ueditor默认使用加粗的icon作为自定义按钮的默认icon,所以为了使用默认的插入图片的图标,我们需要到themes/default/css/ueditor.css中,在最后一行加入:

/*自定义图片上传按钮 */
.edui-default .edui-toolbar .edui-for-diyimg .edui-icon {
    background-position: -380px 0px;//这个位置是“插入图片”的icon,其他图标可自行调整
}
复制代码

添加后,显示效果如下:

React中如何优雅的使用UEditor

图标正常显示后,需要为该图标添加相应的点击事件,在ueditor.all.js中加入:

//图片上传
UE.commands['diyimg'] = {
    execCommand : function(){
        const upload = async(e) => {
            ······//完成图片上传的代码
        }
        const fileInput = document.getElementById('diyimg');//获取dom上隐藏的一个input标签
        fileInput.onchange = upload;
        fileInput.click();//触发input标签实现文件上传
        return true; 
    },
    queryCommandState:function(){
    
    }
};
复制代码

笔者这里不赘述图片上传的代码,度娘上很多,我简单说说实现的思路:

先实现一个插入图片的按钮,然后为该按钮注册相应的事件 diyimg ,然后 在页面中添加一个 input file 标签并隐藏 diyimg 事件会触发该标签的点击事件,弹出文件上传弹窗,此时选择文件点击后会触发 onchange事件 ,执行相应的图片上传代码。上传成功到服务器后,服务器会返回图片对应的url,此时拿到该url填入对应编辑器实例,执行编辑器的插入图片的代码:

this.execCommand('insertimage', {
    src: res.data.downloadUrl,//回调传来的url
    width:'60'
    // height:'45'
});
复制代码

7. 给在编辑器内部的img等标签添加内联样式

ueditor默认存在 xss过滤 !!!这里以给 img 标签添加style=“vertical-top”为例。

首先要找到ueditor.config.js,在其中搜索xss,在第403行左右有代码:

img:    [src', 'alt', 'title', 'width', 'height', 'id', '_src', 'loadingclass', 'class', 'data-latex'],
复制代码

往数组里加入 style 字符串,然后在ueditor.all.js中搜索UE.commands['insertimage'] ,在第约11172行找到str,往里面加入内联样式即可。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

创业就是要细分垄断

创业就是要细分垄断

李开复、汪华、傅盛 / 文化发展出版社 / 2017-5-1 / CNY 45.00

对各方面资源极为有限的创业公司而言,想在激烈的市场竞争中站立下来的第一步是:成为细分市场的垄断者。不管是资本还是尖端人才,追逐的永远是行业里尖端的企业,第二名毫无意义。 首先,要精准定位潜在市场。这个市场的需求仍没有被满足,并且潜力巨大。其次,抓住时代和行业的红利,通过高速增长实现“小垄断”,抢滩登陆。最后,在细分领域里建立起自己的竞争壁垒,应对巨头和竞争对手的复制,去扩展更大的市场,从而扩......一起来看看 《创业就是要细分垄断》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具