ckeditor 从入门到放弃

真心复杂

有一个 CKEDITOR 的全局空间,

有一个 CKEDITOR.instances的全局实例引用

有 Classic 编辑和 Inline 编辑两种模式

有 Plugin 也有 Widget

有自成一体的编译打包工具,与 AMD\CMD\UMD社区不兼容

官方兼容性

  • Desktop environments:Internet Explorer:
    • 8.0 and 9.0 – close to full support,
    • 10 and 11 – full support,
    • 9.0 Quirks Mode and 9.0 Compatibility Mode – limited support.
    • Firefox, Chrome, Safari, Microsoft Edge, Opera (Latest stable release) – full support.
  • Mobile environments:
    • Safari (iOS 6+) – close to full support,
    • Chrome (Android) – close to full support,
    • Internet Explorer Mobile (Windows Phone 8.1+) – support under evaluation.

加载

<script src="js/ckeditor/ckeditor.js"></script>

生成编辑器

经典编辑(Classic Editing)

<textarea id="editor"></textarea>
<script>
CKEDITOR.replace('editor')
</script>

内嵌编辑(Inline Editing)

<div id="editor" contenteditable="true"></div>
<script>
CKEDITOR.disableAutoInline = true; // 关闭自动内嵌编辑
CKEDITOR.inline('editor'); // 手动对 #editor 元素开启内嵌编辑
</script>

按钮面板定制(Toolbar)

一组一组定义

config.toolbarGroups = [
    { name: 'clipboard',   groups: [ 'clipboard', 'undo' ] },
    { name: 'editing',     groups: [ 'find', 'selection', 'spellchecker' ] },
    { name: 'links' },
    { name: 'insert' },
    { name: 'forms' },
    { name: 'tools' },
    { name: 'document',    groups: [ 'mode', 'document', 'doctools' ] },
    { name: 'others' },
    '/',
    { name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ] },
    { name: 'paragraph',   groups: [ 'list', 'indent', 'blocks', 'align', 'bidi' ] },
    { name: 'styles' },
    { name: 'colors' },
    { name: 'about' }
];

一个一个定义

config.toolbar = [
    { name: 'document', items: [ 'Source', '-', 'NewPage', 'Preview', '-', 'Templates' ] },
    { name: 'clipboard', items: [ 'Cut', 'Copy', 'Paste', 'PasteText', 'PasteFromWord', '-', 'Undo', 'Redo' ] },
    '/',
    { name: 'basicstyles', items: [ 'Bold', 'Italic' ] }
];

插件机制

假如我们开发一个插入当前时间戳的插件

插件目录结构

  • ckeditor root/
    • plugins/
      • timestamp/
        • icons/
          • timestamp.png
        • plugin.js

插件代码

CKEDITOR.plugins.add( 'timestamp', {
    icons: 'timestamp',
    init: function( editor ) {
        editor.addCommand( 'insertTimestamp', {
            exec: function( editor ) {
                var now = new Date();
                editor.insertHtml( 'The current date and time is: <em>' + now.toString() + '</em>' );
            }
        });
        editor.ui.addButton( 'Timestamp', {
            label: 'Insert Timestamp',
            command: 'insertTimestamp',
            toolbar: 'insert'
        });
    }
});

通过 CKEDITOR.plugins.add方法添加插件,第一个参数为插件名,后面为参数列表。

通过editor.addCommand方法添加一个 insertTimestamp 的命令

通过editor.ui.addButton方法添加一个按钮控件,并绑定其执行的 command

通过 editor.insertHtml方法往编辑内容区域追加内容

加载插件

通过配置文件来开启插件

config.extraPlugins = 'timestamp';

如果这是一个会出现在 Toolbar 的插件,且 Toolbar 被定制过,则需要显性配置 toolbar让其显示

config.toolbar = {
  {name: 'insert', ['Timestamp']}
}

挂件(Widget)

挂件是由一组 html 元素组成的特殊富文本单元,类似于模板机制

与插件的区别

挂件有 template 字段,插件没有

挂件目录结构

与插件一致

挂件代码

CKEDITOR.plugins.add( 'simplebox', {
    
  	// 表明这是一个 widget
  	requires: 'widget',
 
    icons: 'simplebox',
 
    init: function( editor ) {
        CKEDITOR.dialog.add( 'simplebox', this.path + 'dialogs/simplebox.js' );
 
        editor.widgets.add( 'simplebox', {
 
       		// 鼠标 hover 在 toolbar 上出现的提示
            button: 'Create a simple box',
 
            // 挂件模板
            template:
                '<div class="simplebox">' +
                    '<h2 class="simplebox-title">Title</h2>' +
                    '<div class="simplebox-content"><p>Content...</p></div>' +
                '</div>',
 
            // 定义挂件中可编辑的部分
            editables: {
                title: {
                    selector: '.simplebox-title',
                    allowedContent: 'br strong em'
                },
                content: {
                    selector: '.simplebox-content',
                    allowedContent: 'p br ul ol li strong em'
                }
            },
 
            // 挂件内允许出现的组合
            allowedContent:
                'div(!simplebox,align-left,align-right,align-center){width};' +
                'div(!simplebox-content); h2(!simplebox-title)',
 
            // 挂件最小组合,如果这个 div 被删除,则自动清除该挂件
            requiredContent: 'div(simplebox)',
 
            dialog: 'simplebox',
 
            upcast: function( element ) {
                return element.name == 'div' && element.hasClass( 'simplebox' );
            },
 
            init: function() {
                var width = this.element.getStyle( 'width' );
                if ( width )
                    this.setData( 'width', width );
                if ( this.element.hasClass( 'align-left' ) )
                    this.setData( 'align', 'left' );
                if ( this.element.hasClass( 'align-right' ) )
                    this.setData( 'align', 'right' );
                if ( this.element.hasClass( 'align-center' ) )
                    this.setData( 'align', 'center' );
            },
 
            data: function() {
 
                if ( this.data.width == '' )
                    this.element.removeStyle( 'width' );
                else
                    this.element.setStyle( 'width', this.data.width );
 
                this.element.removeClass( 'align-left' );
                this.element.removeClass( 'align-right' );
                this.element.removeClass( 'align-center' );
                if ( this.data.align )
                    this.element.addClass( 'align-' + this.data.align );
            }
        } );
    }
} );

ACF

CKEditor 的高级内容过滤器,当用户在源码输入模式、editor.setData输入、直接粘贴 html 代码等输入时候,将不希望出现的内容给过滤掉。

自动模式(Automatic Mode)

config.allowedContent 没有设置的时候,ACF 就会进入自动模式。

自动模式通过config.removePluginsconfig.removeButtonsconfig.format_tag 来做过滤微调

config.removePlugins = 'image,table,tabletools,horizontalrule';
config.removeButtons = 'Anchor,Underline,Strike,Subscript,Superscript';
config.format_tags = 'p;h1;h2;pre';

自定义模式(Custom Mode)

通过 config.allowedContent 来进入自定义模式

config.allowedContent =
    'h1 h2 h3 p blockquote strong em;' +
    'a[!href];' +
    'img(left,right)[!src,alt,width,height];';

ACF语法

elements [attributes]{styles}(classes)

例如我们需要保留<span class=”mod_fillblank”>这样的富文本内容,规则为span(mod_fillblank),其 attributes 对 class 无效。

实战建议

  • 能用 CKEditor 社区插件解决的问题,用插件解决
  • 插件解决不了的问题,业务自己写plugin 或者 widget 解决
  • 业务自己写的部分,尽量不要用 CKEditor 自带的 CKEDITOR.dialog ,他们的实现是用 JS 去码DOM 结构,太复杂了。随便一个 Dialog 控件都能用得很舒服
  • 不要用CKEditor 的 jQuery Adapter,他家的 Adapter 对于同一个 DOM 的进行实例化、销毁等操作有 bug,时不时给你冒一个错误。自己包裹一个 Adapter 则肯定没有 bug
  • 工程化的时候,构建工具做依赖分析的时候,记得排除掉 CKEditor 目录,否则他家一堆的插件,会严重拖慢依赖分析那步

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏web前端教室

你可以从面试中学到什么?

讲一下我对面试的一些。。。“偏见”,哈哈,熟悉我的同学们一定要批判的读接下来的内容哈。

12300
来自专栏非著名程序员

「我真的没有改需求」

12010
来自专栏腾讯大讲堂的专栏

白底黑字or黑底白字,眼睛更喜欢哪一个?

12310
来自专栏FSociety

SQL中GROUP BY用法示例

GROUP BY我们可以先从字面上来理解,GROUP表示分组,BY后面写字段名,就表示根据哪个字段进行分组,如果有用Excel比较多的话,GROUP BY比较类...

5.2K20
来自专栏非著名程序员

这是对付产品经理的一副毒药,程序员慎入

程序员和产品经理的日常就像是一对天生的冤家,为了需求的实现,几乎天天在争吵。这不,就在昨天各大技术和产品群里一个程序员暴打产品经理的视频火了,被广泛传播。

12520
来自专栏haifeiWu与他朋友们的专栏

复杂业务下向Mysql导入30万条数据代码优化的踩坑记录

从毕业到现在第一次接触到超过30万条数据导入MySQL的场景(有点low),就是在顺丰公司接入我司EMM产品时需要将AD中的员工数据导入MySQL中,因此楼主负...

30040
来自专栏微信公众号:小白课代表

不只是软件,在线也可以免费下载百度文库了。

不管是学生,还是职场员工,下载各种文档几乎是不可避免的,各种XXX.docx,XXX.pptx更是家常便饭,人们最常用的就是百度文库,豆丁文库,道客巴巴这些下载...

44630
来自专栏腾讯NEXT学位

今天我就说三句话

11620
来自专栏前端桃园

知识体系解决迷茫的你

最近在星球里群里都有小伙伴说道自己对未来的路比较迷茫,一旦闲下来就不知道自己改干啥,今天我这篇文章就是让你觉得一天给你 25 个小时你都不够用,觉得睡觉都是浪费...

22340
来自专栏Ken的杂谈

【系统设置】CentOS 修改机器名

18230

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励