此次接到一個需求,要在瀏覽器的IDE
中支持自定義提示功能,以下所示:php
能夠看到,它能夠根據用戶輸入的內容來一項一項排除,只顯示徹底匹配的那一項。
項目的框架是Vue
,編輯器用的是Monaco Editor
。java
Monaco Editor
vscode
是咱們常常在用的編輯器,它的前身是微軟的一個叫Monaco Workbench
的項目,而Monaco Editor
就是從這個項目中成長出來的一個web
編輯器,他們很大一部分的代碼都是共用的,因此Monaco Editor
和VSCode
在編輯代碼,交互及UI
上幾乎是一摸同樣的。不一樣的是,二者的平臺不同,Monaco Editor
基於瀏覽器,而VSCode
基於electron
,因此功能上VSCode
更加健全,性能比較強大。react
安裝web
npm install monaco-editor --save
使用sql
<div id="monaco" class="monaco-editor"></div>
import * as monaco from 'monaco-editor'; this.fileEditor = this.monaco.editor.create(document.getElementById('monaco'), { value: null, language: 'sql' // 這裏以sql爲例 }) this.fileEditor.dispose(); // 使用完後銷燬
這裏引入monaco
要注意,在react
中如下面方式引入:npm
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
查看了資料後,發如今monaco
中有提供一個提示功能的方法registerCompletionItemProvider
,具體實現以下:json
this.monaco.languages.registerCompletionItemProvider('sql', { // 這裏以sql語言爲例 provideCompletionItems () { return [{ label: '${_DB', // 顯示的提示內容 kind: this.monaco.languages.CompletionItemKind['Function'], // 用來顯示提示內容後的不一樣的圖標 insertText: '{_DB', // 選擇後粘貼到編輯器中的文字 detail: '' // 提示內容後的說明 }]; }, triggerCharacters: ['$'] // 觸發提示的字符,能夠寫多個 });
以上的用法,我試了一下以後發現,雖然triggerCharacters
的值是數組,能夠有多個,可是裏面的字符串只能識別一個字符。一開始的需求是輸入${_
以後提示${_DB
,可是因爲不能識別多個字符,只能作到出現$
就提示。api
還有一個問題就是registerCompletionItemProvider
的第一個參數只能是字符串,若是有多種語言只能疊加劇複寫,恰巧個人需求是有多種語言,因此只能以下解決,也就是每種語言都寫了一遍:數組
['json', 'yaml', 'php', 'go', 'sql', 'java', 'markdown', 'plaintext'].map(item => { this.monaco.languages.registerCompletionItemProvider(item, { provideCompletionItems () { return [{ label: '${_DB', kind: this.monaco.languages.CompletionItemKind['Function'], insertText: '{_DB', detail: '' }]; }, triggerCharacters: ['$'] }); });
需求是${_DB:key:value
,也就是說在輸入${_DB
後,再輸入一個:
提示出key
,在key
以後輸入:
提示value
。瀏覽器
這裏又碰到一個問題,須要知道當前輸入的內容來判斷是$
仍是:
,並且後面兩個觸發提示的符號同是:
,沒法區分,只能經過識別:
的位置來判斷是提示key
仍是value
,因此還要知道當前輸入的:
以前的內容。
那麼只有在provideCompletionItems
這一步判斷,可是查遍了資料沒有發現這樣的參數,provideCompletionItems
只有model
、position
、token
這幾個參數,後來發現model
中的getLineContent
方法能夠獲取指定行的全部內容,而position
能夠獲取當前輸入行的行數和列數,因而就有了如下解決方法:
this.monaco.languages.registerCompletionItemProvider(item, { provideCompletionItems (model, position) { // 獲取當前行數 const line = position.lineNumber // 獲取當前列數 const column = position.column // 獲取當前輸入行的全部內容 const content = model.getLineContent(line) // 經過下標來獲取當前光標後一個內容,即爲剛輸入的內容 const sym = content[column - 2] if (sym === '$') { return [{ label: '${_DB', kind: this.monaco.languages.CompletionItemKind['Function'], insertText: '{_DB', detail: '' }]; } return [{ label: ':abb', kind: this.monaco.languages.CompletionItemKind['Function'], insertText: 'abb', detail: '' }, { label: ':bc', kind: this.monaco.languages.CompletionItemKind['Function'], insertText: 'bc', detail: '' }]; }, triggerCharacters: ['$', ':'] });
能獲取光標後的第一個內容,後面的內容就都能獲取啦,若是識別到前面的內容是${_DB
就提示key
,不然提示value
。
最後總結下來就是必定要多看文檔,勤於測試就能解決問題啦~
啦啦啦~ 交差去啦~