wangeditor3如何集成highlightJs實(shí)現(xiàn)代碼高亮?

最近在整改個(gè)人博客的過(guò)程中,想順手將以前使用的一個(gè)富文本編輯器wangEditor也升級(jí)一下,卻碰到了一個(gè)非常操蛋的問(wèn)題,在版本迭代到了3.x的時(shí)候(本文中使用的是3.1.1版本),作者將代碼高亮功能取消了,實(shí)在是讓人頭大。

wangeditor3如何集成highlightJs實(shí)現(xiàn)代碼高亮?

我去他的GitHub上溜達(dá)了一圈,發(fā)現(xiàn)對(duì)于拿掉代碼高亮這個(gè)功能,困惑的人還不少,作者也做了不少答復(fù),總結(jié)下來(lái)有兩個(gè)原因。

一、個(gè)人精力有限

wangeditor3如何集成highlightJs實(shí)現(xiàn)代碼高亮?

二、受眾群體主要不是程序員

wangeditor3如何集成highlightJs實(shí)現(xiàn)代碼高亮?

這種涉及到高亮的issue都是在2017年提出來(lái)的,都3年了,作者也還是一直沒(méi)有抽出精力來(lái)優(yōu)化,而在2018年的時(shí)候,作者回復(fù)了一個(gè)關(guān)于代碼高亮的issue,并給出了具體的實(shí)現(xiàn)思路,瞬間讓我感動(dòng)的淚流滿面,大佬終究還是沒(méi)有放棄我們這一小撮程序猿受眾群體。

wangeditor3如何集成highlightJs實(shí)現(xiàn)代碼高亮?

如上圖,作者給出了4個(gè)步驟,甚至把需要修改的代碼在多少行都指出來(lái)了,話都說(shuō)到這一步了,跟他自己寫(xiě)出來(lái)也么啥兩樣了,今天就來(lái)教大家如何按照作者的這個(gè)思路來(lái)將highlight.js集成進(jìn)來(lái),實(shí)現(xiàn)代碼高亮(作者說(shuō)的比較抽象,我實(shí)現(xiàn)起來(lái),步驟可能稍微有些差異)。

一、修改代碼塊對(duì)應(yīng)的_createPanel方法,增加編程語(yǔ)言下拉框

代碼位置大概在2024行,源代碼如下:

_createPanel: function _createPanel(value) {
    var _this = this;
    // value - 要編輯的內(nèi)容
    value = value || '';
    var type = !value ? 'new' : 'edit';
    var textId = getRandom('texxt');
    var btnId = getRandom('btn');
    var panel = new Panel(this, {
        width: 500,
        // 一個(gè) Panel 包含多個(gè) tab
        tabs: [{
            // 標(biāo)題
            title: '插入代碼',
            // 模板
            tpl: '<div>\n <textarea id="' + textId + '" style="height:145px;;">' + value + '</textarea>\n <div class="w-e-button-container">\n <button id="' + btnId + '" class="right">\u63D2\u5165</button>\n </div>\n <div>',
            // 事件綁定
            events: [
            // 插入代碼
            {
                selector: '#' + btnId,
                type: 'click',
                fn: function fn() {
                    var $text = $('#' + textId);
                    var text = $text.val() || $text.html();
                    text = replaceHtmlSymbol(text);
                    if (type === 'new') {
                        // 新插入
                        _this._insertCode(text);
                    } else {
                        // 編輯更新
                        _this._updateCode(text);
                    }
                    // 返回 true,表示該事件執(zhí)行完之后,panel 要關(guān)閉。否則 panel 不會(huì)關(guān)閉
                    return true;
                }
            }]
        } // first tab end
        ] // tabs end
    }); // new Panel end
    // 顯示 panel
    panel.show();
    // 記錄屬性
    this.panel = panel;
}

從tpl參數(shù)可以看到,代碼塊輸入框基本上就是由一個(gè)textarea組成的,那我們想要的一個(gè)編程語(yǔ)言下拉框,那就在這里給它拼一個(gè)select下拉框放進(jìn)去。

_createPanel: function _createPanel(value) {
    var _this = this;

    // value - 要編輯的內(nèi)容
    value = value || '';
    var type = !value ? 'new' : 'edit';
    var textId = getRandom('texxt');
    var btnId = getRandom('btn');

    // 編程語(yǔ)言
    var select = "<select class='code-type' style='border:1px solid #666;color:#666;margin-top:4px'><option value=''>編程語(yǔ)言</option>";
    jQuery.each(hljs.listLanguages(), function(i, e) {
        select += "<option value='" + e + "'>" + e + "</option>";
    });
    select += "</select>";

    var panel = new Panel(this, {
        width: 500,
        // 一個(gè) Panel 包含多個(gè) tab
        tabs: [{
            // 標(biāo)題
            title: '插入代碼',
            // 模板
            tpl: '<div><textarea id="' + textId + '" style="resize:vertical;min-height:145px">' + value + '</textarea><div class="w-e-button-container">' + select + '<button id="' + btnId + '" class="right">\u63D2\u5165</button></div><div>',
            // 事件綁定
            events: [
            // 插入代碼
            {
                selector: '#' + btnId,
                type: 'click',
                fn: function fn() {
                    var $text = $('#' + textId);
                    var text = $text.val() || $text.html();
                    text = replaceHtmlSymbol(text);
                    if (type === 'new') {
                        // 新插入
                        _this._insertCode(text);
                    } else {
                        // 編輯更新
                        _this._updateCode(text);
                    }

                    // 返回 true,表示該事件執(zhí)行完之后,panel 要關(guān)閉。否則 panel 不會(huì)關(guān)閉
                    return true;
                }
            }]
        } // first tab end
        ] // tabs end
    }); // new Panel end

    // 顯示 panel
    panel.show();

    // 記錄屬性
    this.panel = panel;
}

二、修改_insertCode方法,增加hljs高亮樣式,并觸發(fā)高亮

代碼位置大概在2075行,源代碼如下:

// 插入代碼
_insertCode: function _insertCode(value) {
 var editor = this.editor;
 editor.cmd.do('insertHTML', '<pre><code>' + value + '</code></pre><p><br></p>');
}

可以看到insertHtml的時(shí)候,并沒(méi)有帶上highlight.js高亮需要的樣式,也沒(méi)有調(diào)用highlight.js的api觸發(fā)高亮,我們都在這里給它加上去。

// 插入代碼
_insertCode: function _insertCode(value) {
    var editor = this.editor;
    // 將語(yǔ)言類型加到css中
    var codeType = jQuery('select.code-type').val();
    editor.cmd.do('insertHTML', '<pre><code class="hljs '+codeType+'">' + value + '</code></pre><p><br></p>');
    // 觸發(fā)高亮
    document.querySelectorAll('pre code').forEach((block) => {
        hljs.highlightBlock(block);
    });
}

三、修改onClick方法,在代碼回顯時(shí)保證排版不亂

這一步,也不知道大家理不理解,就是我將光標(biāo)點(diǎn)在代碼塊上,再去點(diǎn)擊上方工具欄中的“插入代碼”圖標(biāo)時(shí),會(huì)自動(dòng)將代碼塊的內(nèi)容回填到那個(gè)textarea中去。

代碼位置大概在1992行,源代碼如下:

onClick: function onClick(e) {
    var editor = this.editor;
    var $startElem = editor.selection.getSelectionStartElem();
    var $endElem = editor.selection.getSelectionEndElem();
    var isSeleEmpty = editor.selection.isSelectionEmpty();
    var selectionText = editor.selection.getSelectionText();
    var $code = void 0;
    if (!$startElem.equal($endElem)) {
        // 跨元素選擇,不做處理
        editor.selection.restoreSelection();
        return;
    }
    if (!isSeleEmpty) {
        // 選取不是空,用 <code> 包裹即可
        $code = $('<code>' + selectionText + '</code>');
        editor.cmd.do('insertElem', $code);
        editor.selection.createRangeByElem($code, false);
        editor.selection.restoreSelection();
        return;
    }
    // 選取是空,且沒(méi)有夸元素選擇,則插入 <pre><code></code></prev>
 if (this._active) {
 // 選中狀態(tài),將編輯內(nèi)容
        this._createPanel($startElem.html());
    } else {
        // 未選中狀態(tài),將創(chuàng)建內(nèi)容
        this._createPanel();
    }
}

大家注意2017行代碼,$startElem.html()獲取的內(nèi)容是帶有了html標(biāo)簽的,回顯到填寫(xiě)代碼塊的那個(gè)textarea中肯定不行,可是我改成$startElem.text()之后,發(fā)現(xiàn)html標(biāo)簽是沒(méi)有了,但是樣式排版也沒(méi)了,比如說(shuō)回車換行和空格符之類的,都被過(guò)濾掉了,所以不能用這幾個(gè)API了,我直接獲取了元素的innerText。

onClick: function onClick(e) {
    var editor = this.editor;
    var $startElem = editor.selection.getSelectionStartElem();
    var $endElem = editor.selection.getSelectionEndElem();
    var isSeleEmpty = editor.selection.isSelectionEmpty();
    var selectionText = editor.selection.getSelectionText();
    var $code = void 0;
    if (!$startElem.equal($endElem)) {
        // 跨元素選擇,不做處理
        editor.selection.restoreSelection();
        return;
    }
    if (!isSeleEmpty) {
        // 選取不是空,用 <code> 包裹即可
        $code = $('<code>' + selectionText + '</code>');
        editor.cmd.do('insertElem', $code);
        editor.selection.createRangeByElem($code, false);
        editor.selection.restoreSelection();
        return;
    }
    // 選取是空,且沒(méi)有夸元素選擇,則插入 <pre><code></code></prev>
    if (this._active) {
        // 選中狀態(tài),將編輯內(nèi)容
        this._createPanel($startElem[0].innerText);
        // 編程語(yǔ)言下拉回顯
        var className = $startElem.attr('class');
        if (className) {
            jQuery('select.code-type').val(className.split(' ')[1]);
        }
    } else {
        // 未選中狀態(tài),將創(chuàng)建內(nèi)容
        this._createPanel();
    }
}

四、修改_updateCode方法,二次編輯確認(rèn)之后,觸發(fā)hljs高亮

代碼位置大概在2081行,源代碼如下:

// 更新代碼
_updateCode: function _updateCode(value) {
    var editor = this.editor;
    var $selectionELem = editor.selection.getSelectionContainerElem();
    if (!$selectionELem) {
        return;
    }
    $selectionELem.html(value);
    editor.selection.restoreSelection();
}

可以看到,這里并沒(méi)有觸發(fā)高亮的動(dòng)作,所以在我們修改了代碼塊之后,會(huì)出現(xiàn)hljs高亮丟失的情況,給它加兩行跟_insertCode一樣的代碼。

// 更新代碼
_updateCode: function _updateCode(value) {
    var editor = this.editor;
    var $selectionELem = editor.selection.getSelectionContainerElem();
    if (!$selectionELem) {
        return;
    }
    // 獲取最新的編程語(yǔ)言
    var codeType = jQuery('select.code-type').val();
    jQuery($selectionELem).prop('class', '');
    jQuery($selectionELem).prop('class', 'hljs ' + codeType);

    $selectionELem.html(value);
    editor.selection.restoreSelection();
    // highlight.js
    document.querySelectorAll('pre code').forEach((block) => {
        hljs.highlightBlock(block);
    });
}

一套下來(lái),行云流水,直接上效果圖:

wangeditor3如何集成highlightJs實(shí)現(xiàn)代碼高亮?

我將我改好的一份js放到了網(wǎng)盤,大家有覺(jué)著麻煩的,或者前端基礎(chǔ)薄弱的,可以直接來(lái)我公眾號(hào)(雨落無(wú)影)回復(fù)“wangEditor3”領(lǐng)取哦?。?!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容