js显示格式化代码并高亮(vue中实现代码高亮)
文章目錄
- js 實(shí)現(xiàn)代碼格式化
- 調(diào)用 api
- 實(shí)現(xiàn)代碼高亮
- 引入
- 用法
- highlight.js 高亮代碼不換行
- innerText 和 innerHTML 有什么區(qū)別
- 解決 innerHTML 渲染為真實(shí)節(jié)點(diǎn)的問(wèn)題
- 上色后都是 span 標(biāo)簽,是怎么做到換行的?
- vue 中使用 highlight.js
- 用指令使用 js_beautify
- 關(guān)于文章開(kāi)頭的編輯器
- 獲取的代碼再次格式化格式亂了
實(shí)現(xiàn)一個(gè)簡(jiǎn)易版的網(wǎng)頁(yè)編輯器,沒(méi)有智能提示,也不會(huì)自動(dòng)高亮標(biāo)簽(需要手動(dòng)高亮)
用的是 vue+ Highlight.js + js-beautify
效果如下圖
js 實(shí)現(xiàn)代碼格式化
首先我們會(huì)用到 <pre></pre>和 <code></code> 標(biāo)簽,包裹我們要展示的 html 代碼,因?yàn)橹挥羞@樣他們才能保持換行/縮進(jìn)等
格式化代碼用到的是 js-beautify
js-beautify 是分別為 js,css,html 提供了 3 個(gè) JS,不必一次性引入那么多不需要的內(nèi)容,比如我要實(shí)現(xiàn)的效果只需要引入 html 的即可
- cdn 方式:
- npm 方式
調(diào)用 api
<pre><code id="html_code"></code></pre> <pre><code id="css_code"></code></pre> <pre><code id="js_code"></code></pre><script>document.querySelector('#html_code').innerText = html_beautify('<div><div>html格式化</div><div>第二行</div></div>',{indent_size: 2,space_in_empty_paren: true})document.querySelector('#css_code').innerText = js_beautify('body{background:red;width:100%;}', {indent_size: 2,space_in_empty_paren: true})document.querySelector('#js_code').innerText = css_beautify("var test = 'a';function(){console.log('test',test)}",{indent_size: 2,space_in_empty_paren: true}) </script>配置項(xiàng)的參數(shù)有很多,具體可以參照 GitHub 提供的參數(shù)配出相應(yīng)的格式 注意 pre 標(biāo)簽后,不要有空格和回車(chē),不然也會(huì)渲染出來(lái),也一定要有 pre 標(biāo)簽,不然代碼縮進(jìn)的空格也渲染不出來(lái)
小小吐槽一下 html_beautify,感覺(jué)這個(gè) api 有點(diǎn)雞肋,還不如 innerHtml 來(lái)得快,比如
<pre><code id="html_template_code"></code></pre><div style="display: none;" id="html_template"><div><h1>標(biāo)簽格式化</h1><div>html格式化</div></div> </div><script>document.querySelector('#html_template_code').innerText = document.querySelector('#html_template').innerHTML </script>也能達(dá)到一樣的效果,并且還少引入了一個(gè)庫(kù)~
實(shí)現(xiàn)代碼高亮
用到的就是 highlight.js
highlight.js 中文網(wǎng)、highlight.js 官網(wǎng)
引入
- cdn 模式
- npm 模式
用法
在對(duì)應(yīng)的 code/pre 標(biāo)簽上,標(biāo)注上對(duì)應(yīng)的語(yǔ)言,比如:
<pre><code class="language-html"></code></pre> <pre><code class="language-javascript"></code></pre> <pre><code class="language-css"></code></pre>在頁(yè)面渲染好了之后,執(zhí)行下面的方法,就可以高亮代碼了
hljs.highlightAll()如果節(jié)點(diǎn)是往后渲染,或者你只想更新某個(gè)代碼塊,可以用下面的方法
hljs.highlightBlock(document.querySelector('#html_code'))更多的還有 hljs.config 等 api,可以翻一下文檔
highlight.js 高亮代碼不換行
如下圖,剛才用 js-beautify 還搞的好好的,高亮后換行都沒(méi)了
有文章說(shuō)是 pre 的 css 問(wèn)題,其實(shí)研究一下高亮后的 html,其實(shí)和 pre 沒(méi)多大關(guān)系,如果你沒(méi)寫(xiě)pre標(biāo)簽?zāi)蔷驼娴挠嘘P(guān)系
看下正確示范:
怎么做到的?把 innerText,改為 innerHTML。下面仔細(xì)說(shuō)說(shuō)
innerText 和 innerHTML 有什么區(qū)別
渲染后界面看上去確實(shí)是一樣的,改換行的換行,改空格的空格,不過(guò)內(nèi)部的 html 就很不一一樣。
- innerText 方法顯然把代碼塊有換行的地方幫我們替換了<br>標(biāo)簽
- innerHtml 方法則是把 html 代碼給渲染了出來(lái)
highlight.js 執(zhí)行高亮的時(shí)候是針對(duì) dom 節(jié)點(diǎn),然后改變 dom 節(jié)點(diǎn)插入標(biāo)簽進(jìn)行高亮的,顯然把代碼中的 <br> 標(biāo)簽給過(guò)濾了(因?yàn)榭吹轿臋n有一個(gè)是否使用<br>標(biāo)簽的配置,所以自身的 br 標(biāo)簽就和他沖突了,純屬個(gè)人猜測(cè))
解決 innerHTML 渲染為真實(shí)節(jié)點(diǎn)的問(wèn)題
html = html.replace(/</g, '<').replace(/>/g, '>') html = html.replace(/</g, '<').replace(/>/g, '>')也是 innerHTML 和 innerText 的區(qū)別,innerHTML 時(shí)會(huì)進(jìn)行編碼重新轉(zhuǎn)換,把 <> 重新渲染為字符,innerText 則是字符原樣輸出
別看第一段代碼塊沒(méi)換行,其實(shí)中間的空格符隱藏了 \n。所以這也是為啥強(qiáng)調(diào)要用 pre 和 code 標(biāo)簽的原因,普通的div或者其他標(biāo)簽都會(huì)把\n和連續(xù)的空格給過(guò)濾掉。
上色后都是 span 標(biāo)簽,是怎么做到換行的?
明白了上面的內(nèi)容后,再來(lái)看一邊上色效果
代碼塊如下:
再怎么看,這都是 span 標(biāo)簽,那 span 標(biāo)簽是怎么控制什么時(shí)候換行,什么時(shí)候不換行,純 css 是做不到的,答案還是 \n
所以明白為什么 br 無(wú)效 \n 有效,為啥要用 innerHTML 了把
vue 中使用 highlight.js
使用方式有很多種,可以用上面的 hljs 的 api 進(jìn)行。也可以用 vue 的特性(自定義指令)來(lái)完成這一系列的東西
import Hljs from 'highlight.js'let Highlight = {} // 自定義插件 Highlight.install = function(Vue) {// 自定義指令 v-highlightVue.directive('highlight', {// 被綁定元素插入父節(jié)點(diǎn)時(shí)調(diào)用inserted: function(el) {Hljs.highlightBlock(el)},// 指令所在組件的 VNode 及其子 VNode 全部更新后調(diào)用componentUpdated: function(el) {Hljs.highlightBlock(el)}}) }export default Highlight指令寫(xiě)好后記得要用 Vue 注冊(cè)一下:
import Vue from 'Vue' import Highlight from '上面那段代碼的對(duì)應(yīng)目錄' Vue.use(Highlight)// 使用的時(shí)候 <code v-highlight>這里寫(xiě)代碼</code>用指令使用 js_beautify
結(jié)合上面的指令,直接封裝一個(gè),先格式化代碼,在高亮代碼的指令!
貪圖方便我就不用項(xiàng)目了,直接建了個(gè) html,用 cdn 引入對(duì)應(yīng)的庫(kù)實(shí)現(xiàn)了一個(gè)
核心的要點(diǎn)上面也都說(shuō)過(guò)了,當(dāng)然代碼還有更好的實(shí)現(xiàn)方式和更多的拓展性,剩下的就多看文檔了~
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title><script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.0/beautify.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.0/beautify-css.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.0/beautify-html.min.js"></script><script src="https://cdn.bootcdn.net/ajax/libs/highlight.js/11.0.1/highlight.min.js"></script><link href="https://cdn.bootcss.com/highlight.js/9.12.0/styles/atom-one-dark.min.css" rel="stylesheet" /><script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.9/vue.min.js"></script></head><body><div id="app"><pre><code v-code class="language-html"><div><div>html格式化</div><div>第二行</div></div></code></pre><hr /><pre><code v-code class="language-css">body{background:red;width:100%;}</code></pre><hr /><pre><code v-code class="language-javascript">var test = 'a';function(){console.log('test',test)}</code></pre></div><script>let code = {}function getBeautifyCode(el) {if (!el || !el.innerHTML) return ''var code = el.innerHTML || ''let className = el.classList ? el.classList.value || '' : ''if (className.indexOf('html') !== -1) {code = html_beautify(code).replace(/</g, '<').replace(/>/g, '>')}if (className.indexOf('css') !== -1) {code = css_beautify(code)}if (className.indexOf('javascript') !== -1) {code = js_beautify(code)}return code}code.install = function(Vue) {Vue.directive('code', {// 被綁定元素插入父節(jié)點(diǎn)時(shí)調(diào)用inserted: function(el) {el.innerHTML = getBeautifyCode(el)hljs.highlightBlock(el)},// 指令所在組件的 VNode 及其子 VNode 全部更新后調(diào)用componentUpdated: function(el) {el.innerHTML = getBeautifyCode(el)hljs.highlightBlock(el)}})}Vue.use(code)new Vue({el: '#app'})</script></body> </html>關(guān)于文章開(kāi)頭的編輯器
在上訴的步驟都完成了之后,并不能在編輯器這么使用,因?yàn)榫庉嬈骱?vue 并沒(méi)有什么特定的 dom 節(jié)點(diǎn)的關(guān)系(在編輯器加載后,vue 上的數(shù)據(jù)并不會(huì)影響編輯器的內(nèi)容,只能通過(guò)編輯器的 onchange 來(lái)給 vue 同步數(shù)據(jù))
所以先用指令,生成一段 html 代碼,拿到 v-code 渲染后的 innerHtml,在插入到編輯器中,注意編輯器中也要用 pre 包裹著要插入的 html 代碼,由于各個(gè)富文本編輯器都不太一樣,也就不好展開(kāi)~
獲取的代碼再次格式化格式亂了
如果你也有編輯器的這種需求,在進(jìn)行一系列改動(dòng)后執(zhí)行保存操作(getContent)。拿到改動(dòng)后的 html 代碼,提交給接口,刷新列表,把新的數(shù)據(jù)重新賦值到編輯器的時(shí)候發(fā)現(xiàn) js-beautify 不生效了?!
這是因?yàn)檫M(jìn)過(guò)我們格式化和代碼高亮過(guò)后的代碼,已經(jīng)存在了很多空格和換行符,其實(shí)這些空格(或者稱為縮進(jìn))是我們不想保存的,保存了這部分縮進(jìn)后下次進(jìn)行代碼格式化的時(shí)候js-beautify會(huì)認(rèn)為這是故意留下的回車(chē)/空格符,導(dǎo)致一系列的問(wèn)題
所以在我們?cè)俅潍@取到 html 代碼的時(shí)候執(zhí)行一個(gè)操作:
html = html.replace(/[\r\n]/g, '').replace(/>\s*?</g, '><')把換行符和 2 個(gè)尖括號(hào)中間的內(nèi)容的非字符,都替換掉,就可以了
總結(jié)
以上是生活随笔為你收集整理的js显示格式化代码并高亮(vue中实现代码高亮)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: SQL截取字符串合辑
- 下一篇: html5倒计时秒杀怎么做,vue 设