道招

2021年的一点工作总结(二)富文本编辑器

如果您发现本文排版有问题,可以先点击下面的链接切换至老版进行查看!!!

2021年的一点工作总结(二)富文本编辑器

邮件项目的核心功能就是编辑邮件了,所以文本的编辑特别容易被用户吐槽了。用户报障的时候一个万能的吐槽点“没有xxx功能,不支持xxx,没有Outlook好用”。 其实作为一个web产品,如果需要更加公平的对比的话,应该远程web版网页邮箱对比(如outlook网页版),而不是客服端软件(如Outlook),普通用户不知道也不会这么对比,所以你也只能受着。。。 从原来的wangEditor替换成CKEditor也不是说就万事大吉了,官方什么插件都有,什么功能都不用自己开发了,那你就大错特错了。说去不负责任的话,支持功能越多,开放给用户的就越多,然后被吐槽的就越多。

2021年,因为富文本的缘故我做过几次相关的改造:

第一次改造:Vue -> React

项目从Vue迁移到React,虽然当时并未“动”编辑器,仍用的是老的wangEditor,但是为了邮件的编辑器“插件”签名和快捷回复功能(以下主要以“签名”为例),能跟原来一致的使用体验。

Vue时代

file

就是图中绿框中的部分。

这两个功能一直是用Vue写的,然后集中在一个名为editorChildren的div中,然后该div作为整体被wangEditor编辑器append到指定的dom结构中使用,大致用法如下:

  • 用Vue中编辑签名相应的功能 file

  • 在wangEditor的源码中将其整体插入

file

这里提到的iframe就是在上图中rich-editor.vue给预留的id为editorIframe的iframe,wangEditor之前已经被改造成在iframe中使用了。

按照这种模式可以将签名对应的功能直接用Vue来编写,不用费劲的用原生JS实现了,开发效率更高。

React时代

迁移到React后,发现不能原来这种模式了,这样会导致签名上面绑定的点击事件没有反应,这个应该是跟React对点击事件的响应机制有关。

所以不得不对此做些改动,将上述的editorChildren的那部分直接写成一个React组件ToolBar

file

然后用render方法生成对应的html,再有wangEditor将其插入对应的dom中

import ReactDom from 'react-dom';
import Toolbar from "../components/editor-widgets/Toolbar";

const children = document.querySelector('#editorChildren');
ReactDom.render(<Toolbar/>, tools);
iframe.contentDocument.body.append(children);

至此原来的签名和快捷回复功能算是能在React项目中正常使用了。

第二次改造 wangEditor -> CKEditor

这次算是最大的一次改造了,就是要把wangEditor替换成CKEditor。

CKEditor可不支持之前像wangEditor那样的骚操作了,它是有自己的插件编写规则的,我个人也不想像对带wangEditor那样改源码了。

CKEditor的插件都是用原生JavaScript编写的。

(function () {
    CKEDITOR.plugins.add( 'mailshortcutreply', {
        requires: ['mailcontent', 'mailshortcutreplyrichcombo'],
        lang: 'en,ja,zh-cn,zh,shark', // %REMOVE_LINE_CORE%
        template: '<div class="shortcutreply_container">{1}</div>',
        init: function( editor ) {
            var lang = editor.lang.mailshortcutreply;
            editor.addCommand( 'mailShortcutReplyTree', {
                exec: function( editor, tree ) {
                    CKEDITOR.mail.shortcutReplyTree = tree;
                    editor.ui.instances.ShortcutReply.reset();
                },
                editorFocus: false
            });
            var config = editor.config;

            var panelTitle = lang.label;
            var styles = {};

            editor.ui.addShortcutReplyRichCombo( 'ShortcutReply', {
                label: panelTitle,
                title: panelTitle,
                toolbar: 'styles,20',
                command: 'shortcutReply',
                // allowedContent: allowedContent,

                panel: {
                    css: [ CKEDITOR.skin.getPath( 'editor' ) ].concat( CKEDITOR.skin.getPath( 'wangeditor' ) ),
                    level: 'mailshortcutreply',
                    multiSelect: false,
                    attributes: { 'aria-label': panelTitle }
                },

                init: function() {
                    this.startGroup( panelTitle );
                    var that = this;
                    CKEDITOR.mail.shortcutReplyTree.forEach(function (item) {
                        that.add( item.key, item.title, item.title);
                    });
                    if (CKEDITOR.mail.shortcutReplyTree.length === 0) {
                        // 鉴于length === 0不会调用add方法,故需要手动设置标志位started
                        this._.list._.started = 1;
                    }
                    // 默认选中第一个,先缓存值
                    var firstCategory = CKEDITOR.mail.shortcutReplyTree[0];
                    if (firstCategory) {
                        this.storeInitValue(firstCategory.key);
                    }
                },

                selectedList: function(key, searchText) {
                    var category = CKEDITOR.mail.shortcutReplyTree.find(function (item) {
                        return item.key === key
                    });
                    if (category && category.children && category.children.length > 0) {
                        return category.children.filter(function(item) {
                            var tempDiv = document.createElement('div');
                            tempDiv.innerHTML = item.content;
                            var plainTextContent = tempDiv.innerText;
                            // 根据内容(里面可能有html代码)的纯文字来检索
                            return item.title.includes(searchText) || plainTextContent.includes(searchText);
                        });
                    }
                    return [];
                },
                fireSearch: function() {
                    var inputValue = this.getStoreInputValue();
                    var value = this.getStoreValue();
                    var list = this.selectedList(value, inputValue);
                    var that = this;
                    list.forEach(function (item) {
                        that.addResult( item.key, item.text, item.title);
                    });
                    this.setStoreValue(value);
                    this.commitResult();
                },
                storeInitValue: function(value) {
                    this.setStoreValue(value || '');
                },
                onClick: function( value ) {
                    this.setStoreValue(value);
                    this.fireSearch();
                },
                onSettingClick: function() {
                    $MailMessageCenter.publish('editor.goToSetting', ['shortcutReply']);
                },
                onChange: function(inputValue) {
                    this.setStoreInputValue(inputValue);
                    this.fireSearch();
                },
                onSelect: function(value) {
                    editor.focus();
                    editor.fire( 'saveSnapshot' );
                    var categoryKey = this.getStoreValue();
                    var category = CKEDITOR.mail.shortcutReplyTree.find(function (item) {
                        return item.key === categoryKey;
                    });
                    if (category) {
                        var shortcutReply = (category.children || []).find(function (item) {
                            return item.key === value;
                        });
                        CKEDITOR.mail.insertHtml(shortcutReply.text);
                    }
                },
                onOpen: function() {
                    this.showAll();
                },

                reset: function() {
                    if (this._.committed) { // 已经初始化过的,则需要进行重置
                        this.destroy();
                        this._.panel = void 0;
                        if (this._.list && this._.list.element) {
                            this._.list.element.$.remove();
                        }
                        this._.committed = 0;
                        this.createPanel(editor);
                    }
                },

                refresh: function() {
                    var elementPath = editor.elementPath();

                    if ( !elementPath )
                        return;
                }
            } );
        }
    });
})();

里面的过滤、搜索、选择什么写起来都没有以前那么爽了,这大概也是Vue、React这类框架的意义之一吧。

第三次改造 默认样式dom结构调整

因为CKEditor是支持格式刷功能,虽然部分场景有bug,但是还是决定开放给用户使用,原来的默认样式功能跟格式刷不兼容,导致这部分内容使用格式刷存在bug,所以只好改造了默认样式的dom结构。具体可以参考之前写过的 CKEditor系列(六)改造原编辑器默认样式dom结构效果对比

对于编辑器,有太多的坑,要想满足用户一切省事的需求,有太多的地方需要改造了,只看你觉得值不值了。

【这不是结束,这甚至不是结束的开始。但,这可能是开始的结束。】

更新时间:
上一篇:2021年的一点工作总结(一)迁移React技术栈下一篇:上海市2022年事业单位公开招聘及报名数据统计

相关文章

富文本编辑器wangEditor多语言、工具栏体验改造

支持多语言 首页wangEditro本身是支持使用多语言的,通过源码可以看到里面有个 replaceLang 方法,虽然这种写法有点非主流,但是是有效的,里面部分地方在支持多语言方面有些遗漏。 阅读更多…

富文本编辑器wangEditor迁移CKEditor前后效果对比

一、背景 富文本编辑器wangEditor的工具栏如图所示 富文本编辑器CKEditor4工具栏如图所示 二、wangEditor编辑器存在问题 1. 字号和字体设置 阅读更多…

wangEditor富文本编辑器改造记录之一——了解wangEditor结构

最近鉴于项目要求,需要对自己使用的富文本编辑器进行改造。 我们首先简单了解下wangEditor的源码结构 第一步:polyfill 当然现在这些基本都用不上了,现代点的浏览器都支持这些 阅读更多…

wangEditor输入中文后直接粘贴bug来了解compositionstart

昨天有人反馈邮件编辑过程中的一个报障,具体内容就是在编辑器中输入中文然后直接粘贴先前复制好的信息,然后出现了bug,比如之前复制了订单号“1234”,再输入“您的订单号”后直接粘贴,编辑器内显示的结 阅读更多…

在iframe中使用富文本编辑器wangEditor

自己做的邮件项目里面需要使用到富文本编辑器,邮件内容说白了就是HTML代码。前任使用的是wangEditor,部分定制化需求就是直接改的源码。 最近发现有的用户的邮件内容加进去的很多css信息, 阅读更多…

在iframe中使用富文本编辑器wangEditor

自己做的邮件项目里面需要使用到富文本编辑器,邮件内容说白了就是HTML代码。前任使用的是wangEditor,部分定制化需求就是直接改的源码。 最近发现有的用户的邮件内容加进去的很多css信息, 阅读更多…

关注道招网公众帐号
联系博主