前言
雖然作爲後臺開發,但是前後端都是需要懂一些的~
那麼問題來了,最近在寫前端的過程中有這麼一個需求,需要對網頁中的json進行高亮顯示,考慮到自己手動通過匹配修改dom會花費很多時間,於是靈(準)機(備)一(偷)動(懶),通過直接在網頁內嵌入代碼編輯器實現高亮(順便還提供了許多額外的功能,哈哈)
然而配置過程並沒有想象中那麼順利,這裏記錄配置的過程以及一些遇到的坑,方便以後在遇到時可以愉快的繞過去,前端使用vue,版本2.5.17。
下面開始進入正題~
編輯器的選擇
本人期間一共就調研了2款web代碼編輯器(如果第一個部署成功就沒有第二個了……)
兩款編輯器分別是:
首先,兩款編輯器在本地都是能夠成功配置運行的,由於只有monaco成功部署了,那麼這裏主要講講爲什麼ace部署失敗,以及vue中搭載monaco編輯器的一些編碼配置細節。
想要嘗試vue中使用ace編輯器的小夥伴可以參考這篇文章
ace部署失敗主要原因是不支持webpack打包,ace在本地搭建完成後,會有一個小型的worker幫助我們對內容進行渲染,webpack打包之後就變成完完全全的靜態資源了,動態渲染的效果也就沒了(按找官網的意思是可以支持的,但是我實踐了很多方法,均以失敗告終),而monaco幫助我們解決了這個問題。
網上有很多封裝好的monaco組件,看的頭疼,個人不推薦大家使用那些組件,可維護性不佳。
monaco安裝與使用
npm install monaco-editor -S
等待安裝完畢,現在我們就可以開始正式的配置了
本人傾向於將monaco封裝成組件後在進行使用,在vue項目中新建一個.vue文件,我在這裏直接命名爲MonacoEditor.vue
,html模版內容如下:
<template>
<div class="monaco-container">
<div ref="container" class="monaco-editor"></div>
</div>
</template>
可以看到標籤非常的簡單~
接着,我們繼續在js代碼部分進行編寫
import * as monaco from 'monaco-editor'
MonacoEditor
接受從父組件傳遞下來的數據,在props中配置如下:
props: {
// 編輯器中呈現的內容
codes: {
type: String,
default: function () {
return ''
}
},
readOnly: {
type: Boolean,
default: function () {
return false
}
},
// 主要配置
editorOptions: {
type: Object,
default: function () {
return {
selectOnLineNumbers: true,
roundedSelection: false,
readOnly: this.readOnly, // 只讀
cursorStyle: 'line', // 光標樣式
automaticLayout: false, // 自動佈局
glyphMargin: true, // 字形邊緣
useTabStops: false,
fontSize: 28, // 字體大小
autoIndent: false // 自動佈局
}
}
}
}
選擇在頁面渲染時初始化monaco實例
mounted () {
this.monacoEditor = monaco.editor.create(this.$refs.container, {
value: this.codes, // 見props
language: 'python',
theme: 'vs-dark', // 編輯器主題:vs, hc-black, or vs-dark,更多選擇詳見官網
editorOptions: this.editorOptions // 同codes
})
}
這裏的this.$refs.container
拿到的上html模版中的標記ref
爲container
的dom
節點,不推薦在dom
中使用id
,可能會導致後期打包出現問題。
至此一個簡陋的編輯器組件就完成了: )
註冊調用
這裏選擇將其註冊爲一個全局的組件供項目使用,新建一個install.js
,寫入如下內容:
import Monaco from 'path / of / your / MonacoEditor.vue' // 這裏導入文件名不帶後綴亦可
export default {
install: function (Vue, options) {
Vue.component('monaco', Monaco)
}
}
在main.js
中添加如下代碼:
import componentsInstall from 'path / of / your /install.js'
Vue.use(componentsInstall)
我們在父組件這麼調用它
<monaco
:codes="content"
:readOnly="false"
>
</monaco>
至此,一個簡單的monaco編輯器組件嵌入就完成了。
改進和優化
下面針對一些場景對這個組件做一些優化
- 場景1
當多個組件中嵌入了monaco時,在單頁面應用下進行切換會出現編輯器呈現內容不會跟隨當前組件內容進行變化,這裏有兩種解決方案:
(1)使用updated生命週期函數鉤子(未實踐過)
(2)使用watch監測數據變化,觸發更新函數
這裏採用第二種,在MonacoEditor
中添加偵聽器watch,偵聽數據可以爲codes
,但是不推薦,這裏我向MonacoEditor
傳遞一個變量值current
,當切換組件時,該值產生變化,從而在watch中出觸發更新內容的函數。添加的代碼如下
<!-- 父組件 -->
<monaco
:codes="content"
:current="current"
>
</monaco>
// MonacoEditor.vue
//..
props: {
//...
//...
current: Object // 類型隨意,需要保證不同個組件編輯器切換時current值變化
}
//..
//..
watch: {
current () {
this.monacoEditor.setValue(this.codes)
}
},
其中setValue
是一個較爲重要的函數,顧名思義,他可以根據傳遞進來的參數值設置編輯器中初始呈現的內容。
- 場景2
此時的MonacoEditor在展示方面已經足夠好了,但是光有展示還是不夠的,作爲一個編輯器,監聽用戶的輸入,獲取其值也是一項必不可少的功能。
如何監聽,這裏牽扯到一個重要的函數,onDidChangeModelContent
,他可以用來綁定編輯事件,我們在MonacoEditor.vue
中添加如下代碼:
mounted () {
// ...
this.monacoEditor.onDidChangeModelContent((event) => {
let changeContent = this.monacoEditor.getValue()
this.$emit('update:contentBody', changeContent)
})
},
其中onDidChangeModelContent
爲monaco實例所帶的方法,event
是一個IModelContentChangedEvent
對象,他包含了非常非常詳細的變更信息,包括操作的類型(撤銷、恢復,還是手動輸入引發的文本變更),變更的文本位置,變更的文本內容等。
當用戶在編輯器中輸入內容時,onDidChangeModelContent
監聽到內容變化,通過調用getValue()
方法我們可以獲取當前最新的內容,拿到最新內容後,我們可以對相應的值進行更新(本例中拿到最新內容changeContent
後,傳遞給父組件進行賦值更新或者進行別的操作)
這裏有個小坑,由於無法通過v-model綁定codes值,所以通過上述代碼來更新值。
安裝使用 monaco-editor-webpack-plugin
這個插件幫助我們解決了webpack在打包過程中可能會遇到的很多問題,這些問題在這篇文章中有比較詳細的解釋,本篇中不做過多重複的介紹。
下載安裝monaco-editor-webpack-plugin
npm install monaco-editor-webpack-plugin -S
安裝完成後,在vue.config.js添加如下配置內容(若無此文件,則自己新建一個)
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin')
module.exports = {
//...
//...
configureWebpack: {
plugins: [
new MonacoWebpackPlugin()
]
}
}
本地調試完成以後webpack打包部署,沒有問題~來看看最終的效果:
OK~大功告成~:)