header-bg.jpg
KindEditor 优化以及整合 SyntaxHighLighter 方案汇总
发表于 2017-04-21 01:54
|
分类于 JavaScript
|
评论次数 1
|
阅读次数 6602

cover.png

KindEditor 是一款优秀的国产富文本编辑器,但是 2011 年已经停止更新了,所以目前存在许多 BUG 需要优化,本文将总结如何优化 KindEditor。

取消上传网络图片选项

找到 KindEditor/plugins/image/image.js 第 13 行:

allowImageRemote = K.undef(self.allowImageRemote, true)

将上面代码中的 true 改为 false 即可,前后对比图效果如下:

before:

1.png

after:

2.png

解决无法保存空格的 BUG

找到 KindEditor/kindeditor.js,大约第 752 行,将第一个和最后一个 \s 替换成 [ \f\n\r\t\v] ,替换后的代码如下所示:

var re = /([ \f\n\r\t\v]*)<(\/)?([\w\-:]+)((?:\s+|(?:\s+[\w\-:]+)|(?:\s+[\w\-:]+=[^\s"'<>]+)|(?:\s+[\w\-:"]+="[^"]*")|(?:\s+[\w\-:"]+='[^']*'))*)(\/)?>([ \f\n\r\t\v]*)/g;

解决复制粘贴、点击图片等操作滚动条自动下拉的 BUG

找到 KindEditor/kindeditor.js,大约第 1521 行,将 y = box.top + pos.y; 替换为如下代码:

y = pos.y;

图片上传路径问题

举个栗子:修改图片上传路径为根目录下的 atcImg文件夹:

找到 KindEditor/php/upload_json$save_path 为图片上传的路径,$save_url 为 KindEditor 中生成 img 标签的 src 属性值,修改为如下代码即可:

$save_path =  '../../atcImg/';// 文件保存目录路径
$save_url = 'atcImg/';// img 的 src 属性

KindEditor 默认上传图片生成的 url 路径是不带域名的绝对路径,如果我们希望生成之后带上域名就需要对 urlType 进行设置。

KindEditor 中的 urlType 参数有 4 个值,初始化时可以对此参数进行指定:

3 种不同的路径效果如下图所示:

绝对路径

absolute.png

相对路径

relative.png

带域名的绝对路径

domain.png

解决文本中插入的程序代码里的 HTML 实体标签被直接解析出来的 BUG

在 PHP 中添加此函数,在向 Kindeditor 中插入文本内容之前使用此函数将文本内容中的实体符号替换即可解决:

function htmlRep($html){
    $html = str_replace(' ', ' ', $html);
    $html = str_replace('>', '>', $html);
    $html = str_replace('<', '<', $html);
    return $html;
}

设置 KindEditor 生成的 iframe 中的样式(也就是编辑器内容框的样式)

例如,修改 body 节点的内边距为 10px

找到 kindeditor.js 第 3535 行,找到 _getInitHtml 函数,第一行 arr 数组里的代码就是 iframe 的 HTML 内容:

那么直接将 style 标签中的代码:

'body {margin:0;padding:5px;}'

替换为如下即可:

'body {margin:0;padding:10px;}'

整合 SyntaxHighlighter 至编辑器中

一般大家都是在文章页引入语法高亮插件,在这里我想说的是,为什么不直接引入至编辑器中呢?不要嫌麻烦,带来好处是不言而喻的:

(1)可以直接在编辑器就中看到代码被渲染的效果,一点对比色都没有的代码在写文章的时候是真滴辣眼睛;

(1)是减少文章页的 HTTP 请求,减少服务器压力,提升页面加载速度,仅仅引入一个 css 文件即可;

(3)SyntaxHighlighter 是异步渲染的,访客访问你的文章页假如内容特别多,那么在 DOM 没有加载完,你的代码就等着不会被着色,很难受!

那么废话就不多讲了,直接上干货,首先需要引入 SyntaxHighlighter.css,在初始化 Kindeditor 时指定 cssPath 参数:

cssPath : './SyntaxHighlighter/styles/shCoreDefault.css'

找到 kindeditor.js 第 3594 行,将 arr.push 中的内容替换为如下(在编辑器生成的 iframe 中引入 SyntaxHighlighter 的 JS 文件):

arr.push('</head><body ' + (bodyClass ? 'class="' + bodyClass + '"' : '') + '><script src="./SyntaxHighlighter/scripts/0.js"></script><script src="./SyntaxHighlighter/scripts/shCore.js"></script><script src="./SyntaxHighlighter/scripts/shBrushJScript.js"></script></body></html>');

注意 : 0.js 这个文件是个空文件 , 原因是 KindEditor 有一个迷之 BUG,不解析引入的第一个 JS 文件,可能是哪里设置了什么东西吧,那我们不理它就好了,直接在这里引入 SyntaxHighlighter 的 JS 文件之前先引入一个空文件来解决这个 BUG。

找到 KindEditor/plugins/code.js 将默认的 pre 标签的 class 改成 SyntaxHighlighter 需要的 class

yesBtn : {
    name : self.lang('yes'),
    click : function(e) {
        var type = K('.ke-code-type', dialog.div).val(),
            code = textarea.val(),
            //更改了这里 将class替换成"brush: js"这种形式 ("brush: "是固定的 , "js"是上面options中的val值)
            cls = type === '' ? '' : type,
            html = '<pre class="brush: ' + cls + '">\n' + K.escape(code) + '</pre>';
        if (K.trim(code) === '') {
            alert(lang.pleaseInput);
            textarea[0].focus();
            return;
        }
        self.insertHtml(html).hideDialog().focus();
        //加入了此行 每次插入代码后调用highlight()方法着色pre标签的代码
        document.getElementsByClassName('ke-edit-iframe')[0].contentWindow.SyntaxHighlighter.highlight();
    }
}

找到 43 行 yesBtn 属性,将其替换为以上代码,然后你需要清除以前的缓存,下次在插入代码后就能让代码立刻被着色。

那么骚年,你以上已经完事了吗?不存在的,是不是感觉还差点什么?快想想~

猜到了吗?你还需要增加一个隐藏域来保存编辑器的内容,为啥?因为 Kindeditor 还有个很烦的 BUG:源码中的 div 标签里的值被强行缩进了。

可以来看看是什么样子的,你改完就能发现这个东西了,点击显示 HTML 代码的那个按钮,原本着色后的代码行号是这样的:

code.png

很整齐对吧~

然而 KindEditor 显示的源码中竟然被莫名其妙弄出这么大片的空白出来,你想改还改不掉:

error.png

虽然在编辑器中样式是正确的,但是插入到数据库中空白就会被保存下来,再放到文章页显示那效果就爆炸咯,是这个样子:

boom.png

scare.png

没办法,这个时候只能增加一个隐藏域来接受 iframe 中的 HTML 值,提交之前将值保存进去,再插入到数据库,这样保存下来的代码就不会有一点缩进,做法如下:

例如,你有一个隐藏域,和一个 classformform 表单,将这段代码加入到你的提交页面中:

<input type="hidden" class="hidden" name="content" required>
<form class="form"></form>

保存文本内容使用如下 JS 代码即可:

//Helper
function C(c, a, f){
    if(a){
        return f ? f.getElementsByClassName(c) : document.getElementsByClassName(c);
    }else{
        return f ? f.getElementsByClassName(c)[0] : document.getElementsByClassName(c)[0];
    }
}
 
function rmCd(p, c){
    var i = 0;
    while(c[i]){
        p.removeChild(c[i]);
    }
}
 
//Submit Event
C('form').onsubmit = function(e){
    var b = C('ke-edit-iframe').contentWindow.document.body,
        s = b.getElementsByTagName('script'),
        k = C('ke-script', false, b),
        h = C('hidden');
    rmCd(b, s);
    if(k){ rmCd(b, k); }
    h.value = b.innerHTML;
};

上面的代码中,C 函数是我常用的获取 element 的自定义函数,rmCd 函数功能是将多余的 divJS 标签删除,只取出纯真~的文章内容的 HTML 代码。

完成以上工作后,基本算是大工告成了,但是还可能出现小瑕疵,经过测试 Chrome 下可能出现行数稍有误差的情况,Firefox 下却不会,解决这个问题也很简单,单独给Chrome 加个样式就好了:

找到 kindeditor.js 大约 3586 行,找到此函数 _each(),将其内容替换为以下内容即可:

_each(cssPath, function(i, path) {
    if (path) {
        arr.push('<link href="' + path + '" rel="stylesheet">');
        arr = arr.concat([
            '<style>',
            '@media screen and (-webkit-min-device-pixel-ratio:0) {',
            '    .syntaxhighlighter table td {',
            '        font-family:"Microsoft YaHei" !important;',
            '    }',
            '    .syntaxhighlighter a, .syntaxhighlighter div, .syntaxhighlighter code, .syntaxhighlighter table, .syntaxhighlighter table td, .syntaxhighlighter table tr, .syntaxhighlighter table tbody, .syntaxhighlighter table thead, .syntaxhighlighter table caption, .syntaxhighlighter textarea {',
            '        top: 6px !important;',
            '        height: 19px !important;',
            '    }',
            '}',
            '</style>'
        ]);
    }
});

美化工具栏(删除不必要的功能按钮,并增加宽高间距)

先来看两张对比效果:

before:

before.png

after:

after.png

想要达到以上的效果很简单,有两种方法:

(1)初始化时指定 item 选项的值

(2)直接修改 kindeditor.js 里面 item 的默认值

这里我毫不犹豫地选择了第二种方式,暴力修改

优雅.png

找到 kindeditor.js,第 257 行:

items : [
    'source', '|', 'code', '|',
    'fontsize', 'forecolor', 'bold', '|',
    'image', 'multiimage', 'link', '|',
    'fontname', 'italic', 'underline', 'strikethrough', '|',
    'flash', 'media', 'insertfile', 'table', 'hr', 'baidumap', 'pagebreak', 'anchor', '|',
    'selectall', 'undo', 'redo'
],

修改完 JS 之后你以为就能舒服了么?nonono~你现在只是将图标删除了而已,还有样式也需要改,那么找到 Kindeditor/themes/default.css,修改如下代码:

//434行 .ke-toolbar-icon 修改样式:
{
    margin: 3px auto;
}
 
//444行 .ke-toolbar .ke-outline 增加样式:
{ 
    box-sizing: border-box;
    width: 38px;
    height: 25px;
}
 
//459行 .ke-toolbar .ke-separator 修改样式:
{
    margin: 6px 3px 5px;
}

行数可能会稍有偏差,根据选择器修改指定内容即可,修改完之后你就可以舒服了~

编辑页初始高度自适应

当进入编辑页时,编辑器里是有内容的,内容高度比编辑器的初始高度高很多,此时还需要自己手动去拉伸 textarea 岂不是很麻烦?

虽然用全屏模式不会有此问题,但是全屏模式编写文章时看到的样式和发布文章之后去文章页看到的样式差距会很大(因为宽度不一样)。

所以我不用全屏模式,解决这个问题也很简单,我写了一个定时器监听文本高度,等待初始化完成之后直接改变编辑器高度即可:

window.onload = function(){
    function ifChg(){
        var k = document.getElementsByClassName('ke-edit')[0];
        if(k && k.style.height){
            clearInterval(ift);
            var f = k.firstElementChild;
            var b = f.contentWindow.document.querySelector('.ke-content').offsetHeight + 50;
            var x = k.lastElementChild;
            k.style.height = b + 'px';
            f.style.height = b + 'px';
            x.style.height = b - 2 + 'px';
        }
    }
    var ift = setInterval(ifChg, 300);
};

工具栏根据滚动条智能定位

当我的文本内容很多的时候,编辑器的高度是非常高的,这就导致滚动条需要拉很远才能到最底部,而此时工具栏是固定在编辑器最上方的。

那我需要将底部文字小小地加个,岂不是都要拉滚动条拉个 1 分钟才能加到粗?然后加完粗再拉个 1 分钟拉回底部?

brother.png

所以为了解决这个问题,我加了一个滚动条监听事件,当滚动条到达工具栏的高度时,工具栏定位就固定在屏幕上方,也就是 position: fixed;,完整代码如下:

function C(e, a){ return a ? document.getElementsByClassName(e) : document.getElementsByClassName(e)[0]; }
function getTop(e){
    var t = 0;
    while(e.nodeName !== 'BODY'){
        t += e.offsetTop;
        e = e.offsetParent;
    }
    return t;
}
KindEditor.ready(function(K) {
    var s = true, t = getTop(C('ke-container')), c = C('ke-toolbar'), d = true;
    function onScroll(){
        if(s){
            requestAnimationFrame(relFun);
            s = false;
        }
    }
    function relFun(){
        if(pageYOffset >= t){
            if(d){
                c.classList.add('toFix');
                d = false;
            }
        }else{
            if(!d){
                c.classList.remove('toFix');
                d = true;
            }
        }
        s = true;
    }
    window.addEventListener('scroll',onScroll,false);
});

上面的代码中,我将 scroll 监听事件绑定到 DOM 加载完成事件上(kindEditor.ready),如果你写了 ready 函数了,那么你只需要将我的代码追加进去即可。

我只展示了实现智能定位这个功能的代码,CgetTop 两个函数是我经常用到的自定义函数,功能就是类似于 JQuery 的 $offset()

当然加了这段 JS 你还是不能舒服,因为还缺少样式,比如点击按钮的下拉栏是根据 body 定位的,你也需要将其改为 fixed 定位,所以你还需要在Kindeditor/themes/default.css 中做以下修改:

//537行  .ke-menu  增加样式
{
    position: fixed !important;
    left: 640px !important;
    top: 167px !important;
}
 
//596行  .ke-colorpicker 增加样式:
{
    position: fixed !important;
    left: 640px !important;
    top: 167px !important;
}
 
//新增class:
.toFix{
    position: fixed;
    top: 136px;
    box-shadow: 0 0 10px #5b5b5b;
    border: 0;
}

CSS 和 JS 配合使用,这次就真滴舒服了,阔以来看看修改完后的效果:

complete.png

以上只展示了我的编辑器的部分功能,更多的功能代码都放在了我的 GitHub 上~感兴趣的童鞋阔以去下载,gayhub传送门

发布评论
评论
共计 1条评论
最新评论
2017-12-06 11:02:26Xrunnoob[中国河南省郑州市网友]
赞一个
1
4
回复