js显示格式化代码并高亮(vue中实现代码高亮)
文章目錄
- js 實現代碼格式化
- 調用 api
- 實現代碼高亮
- 引入
- 用法
- highlight.js 高亮代碼不換行
- innerText 和 innerHTML 有什么區別
- 解決 innerHTML 渲染為真實節點的問題
- 上色后都是 span 標簽,是怎么做到換行的?
- vue 中使用 highlight.js
- 用指令使用 js_beautify
- 關于文章開頭的編輯器
- 獲取的代碼再次格式化格式亂了
實現一個簡易版的網頁編輯器,沒有智能提示,也不會自動高亮標簽(需要手動高亮)
用的是 vue+ Highlight.js + js-beautify
效果如下圖
js 實現代碼格式化
首先我們會用到 <pre></pre>和 <code></code> 標簽,包裹我們要展示的 html 代碼,因為只有這樣他們才能保持換行/縮進等
格式化代碼用到的是 js-beautify
js-beautify 是分別為 js,css,html 提供了 3 個 JS,不必一次性引入那么多不需要的內容,比如我要實現的效果只需要引入 html 的即可
- cdn 方式:
- npm 方式
調用 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>配置項的參數有很多,具體可以參照 GitHub 提供的參數配出相應的格式 注意 pre 標簽后,不要有空格和回車,不然也會渲染出來,也一定要有 pre 標簽,不然代碼縮進的空格也渲染不出來
小小吐槽一下 html_beautify,感覺這個 api 有點雞肋,還不如 innerHtml 來得快,比如
<pre><code id="html_template_code"></code></pre><div style="display: none;" id="html_template"><div><h1>標簽格式化</h1><div>html格式化</div></div> </div><script>document.querySelector('#html_template_code').innerText = document.querySelector('#html_template').innerHTML </script>也能達到一樣的效果,并且還少引入了一個庫~
實現代碼高亮
用到的就是 highlight.js
highlight.js 中文網、highlight.js 官網
引入
- cdn 模式
- npm 模式
用法
在對應的 code/pre 標簽上,標注上對應的語言,比如:
<pre><code class="language-html"></code></pre> <pre><code class="language-javascript"></code></pre> <pre><code class="language-css"></code></pre>在頁面渲染好了之后,執行下面的方法,就可以高亮代碼了
hljs.highlightAll()如果節點是往后渲染,或者你只想更新某個代碼塊,可以用下面的方法
hljs.highlightBlock(document.querySelector('#html_code'))更多的還有 hljs.config 等 api,可以翻一下文檔
highlight.js 高亮代碼不換行
如下圖,剛才用 js-beautify 還搞的好好的,高亮后換行都沒了
有文章說是 pre 的 css 問題,其實研究一下高亮后的 html,其實和 pre 沒多大關系,如果你沒寫pre標簽那就真的有關系
看下正確示范:
怎么做到的?把 innerText,改為 innerHTML。下面仔細說說
innerText 和 innerHTML 有什么區別
渲染后界面看上去確實是一樣的,改換行的換行,改空格的空格,不過內部的 html 就很不一一樣。
- innerText 方法顯然把代碼塊有換行的地方幫我們替換了<br>標簽
- innerHtml 方法則是把 html 代碼給渲染了出來
highlight.js 執行高亮的時候是針對 dom 節點,然后改變 dom 節點插入標簽進行高亮的,顯然把代碼中的 <br> 標簽給過濾了(因為看到文檔有一個是否使用<br>標簽的配置,所以自身的 br 標簽就和他沖突了,純屬個人猜測)
解決 innerHTML 渲染為真實節點的問題
html = html.replace(/</g, '<').replace(/>/g, '>') html = html.replace(/</g, '<').replace(/>/g, '>')也是 innerHTML 和 innerText 的區別,innerHTML 時會進行編碼重新轉換,把 <> 重新渲染為字符,innerText 則是字符原樣輸出
別看第一段代碼塊沒換行,其實中間的空格符隱藏了 \n。所以這也是為啥強調要用 pre 和 code 標簽的原因,普通的div或者其他標簽都會把\n和連續的空格給過濾掉。
上色后都是 span 標簽,是怎么做到換行的?
明白了上面的內容后,再來看一邊上色效果
代碼塊如下:
再怎么看,這都是 span 標簽,那 span 標簽是怎么控制什么時候換行,什么時候不換行,純 css 是做不到的,答案還是 \n
所以明白為什么 br 無效 \n 有效,為啥要用 innerHTML 了把
vue 中使用 highlight.js
使用方式有很多種,可以用上面的 hljs 的 api 進行。也可以用 vue 的特性(自定義指令)來完成這一系列的東西
import Hljs from 'highlight.js'let Highlight = {} // 自定義插件 Highlight.install = function(Vue) {// 自定義指令 v-highlightVue.directive('highlight', {// 被綁定元素插入父節點時調用inserted: function(el) {Hljs.highlightBlock(el)},// 指令所在組件的 VNode 及其子 VNode 全部更新后調用componentUpdated: function(el) {Hljs.highlightBlock(el)}}) }export default Highlight指令寫好后記得要用 Vue 注冊一下:
import Vue from 'Vue' import Highlight from '上面那段代碼的對應目錄' Vue.use(Highlight)// 使用的時候 <code v-highlight>這里寫代碼</code>用指令使用 js_beautify
結合上面的指令,直接封裝一個,先格式化代碼,在高亮代碼的指令!
貪圖方便我就不用項目了,直接建了個 html,用 cdn 引入對應的庫實現了一個
核心的要點上面也都說過了,當然代碼還有更好的實現方式和更多的拓展性,剩下的就多看文檔了~
<!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', {// 被綁定元素插入父節點時調用inserted: function(el) {el.innerHTML = getBeautifyCode(el)hljs.highlightBlock(el)},// 指令所在組件的 VNode 及其子 VNode 全部更新后調用componentUpdated: function(el) {el.innerHTML = getBeautifyCode(el)hljs.highlightBlock(el)}})}Vue.use(code)new Vue({el: '#app'})</script></body> </html>關于文章開頭的編輯器
在上訴的步驟都完成了之后,并不能在編輯器這么使用,因為編輯器和 vue 并沒有什么特定的 dom 節點的關系(在編輯器加載后,vue 上的數據并不會影響編輯器的內容,只能通過編輯器的 onchange 來給 vue 同步數據)
所以先用指令,生成一段 html 代碼,拿到 v-code 渲染后的 innerHtml,在插入到編輯器中,注意編輯器中也要用 pre 包裹著要插入的 html 代碼,由于各個富文本編輯器都不太一樣,也就不好展開~
獲取的代碼再次格式化格式亂了
如果你也有編輯器的這種需求,在進行一系列改動后執行保存操作(getContent)。拿到改動后的 html 代碼,提交給接口,刷新列表,把新的數據重新賦值到編輯器的時候發現 js-beautify 不生效了?!
這是因為進過我們格式化和代碼高亮過后的代碼,已經存在了很多空格和換行符,其實這些空格(或者稱為縮進)是我們不想保存的,保存了這部分縮進后下次進行代碼格式化的時候js-beautify會認為這是故意留下的回車/空格符,導致一系列的問題
所以在我們再次獲取到 html 代碼的時候執行一個操作:
html = html.replace(/[\r\n]/g, '').replace(/>\s*?</g, '><')把換行符和 2 個尖括號中間的內容的非字符,都替換掉,就可以了
總結
以上是生活随笔為你收集整理的js显示格式化代码并高亮(vue中实现代码高亮)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SQL截取字符串合辑
- 下一篇: vue2.5+在vue-cli3.0中使