當咱們看到這個編輯器的時候,你有沒有好奇這是這麼作出來的?若是是讓你來作,你會怎麼作?javascript
學無止境,咱們如今的技術都是基於前一代人之上作出來的,要想成爲一個高級/資深的前端,重點不是你能創造多少東西,而是你知道多少東西。有沒有解決問題的能力。遇到問題能不能找到最優解,爲公司減小成本的同時提高效率。系統性的解決問題,提升代碼的維護性、穩定性、可擴展行等等。因此現代社會是一個認知的社會,只有不斷的突破本身的認知,纔可以成爲更優秀的人。css
最近在搞公衆號,雖然公衆號已經寫了快兩年了,可是一直沒有推廣過。最近打算推廣,加了好多大佬的微信,我感受我以前作的事情就是小巫見大巫,根本不值一提,前方還有好長的路要走,我隱隱感受有點興奮,由於只有迎難而上、才能迎刃而解。關注我公衆號,前路漫漫,一塊兒修行!前端
當咱們想作一個事情的時候,每每最難的不是作,而是不知道從哪作起,怎麼作?個人每篇文章都會講我是如何去一點點解決問題的,但願可以盡個人綿薄之力幫助有心之人。vue
咱們找到了一個很可疑的單詞 CodeMirrorjava
接下來去 github 上搜索一下 CodeMirrorgit
果真被咱們找到了,點進去查看他的用法。接下來你應該知道怎麼作了~github
上面講解的是我如何找工具的方法,我如今使用的不是 CodeMirror,可是我也是經過這種方法找到的。 我接下來用 monacoEditor 來說解個人作法。typescript
這是一段加載 monaco 的js。主要邏輯就是 load 一段 js,將 monaco 註冊到 window 上api
export default {
// https://as.alipayobjects.com/g/cicada/monaco-editor-mirror/0.6.1/min/vs/loader.js
load(srcPath = 'https://as.alipayobjects.com/g/cicada/monaco-editor-mirror/0.6.1/min', callback) {
if (window.monaco) {
callback();
return;
}
const config = {
paths: {
vs: srcPath + '/vs'
}
};
const loaderUrl = `${config.paths.vs}/loader.js`;
const onGotAmdLoader = () => {
if (window.LOADER_PENDING) {
window.require.config(config);
}
window.require(['vs/editor/editor.main'], () => {
callback();
});
// 當AMD加載器已被加載時調用延遲的回調
if (window.LOADER_PENDING) {
window.LOADER_PENDING = false;
const loaderCallbacks = window.LOADER_CALLBACKS;
if (loaderCallbacks && loaderCallbacks.length) {
let currentCallback = loaderCallbacks.shift();
while (currentCallback) {
currentCallback.fn.call(currentCallback.window);
currentCallback = loaderCallbacks.shift();
}
}
}
};
if (window.LOADER_PENDING) {
// 咱們須要避免加載多個loader.js時
// 有多個編輯器同時加載延遲調用回調除了第一個
window.LOADER_CALLBACKS = window.LOADER_CALLBACKS || [];
window.LOADER_CALLBACKS.push({
window: this,
fn: onGotAmdLoader
});
} else {
if (typeof window.require === 'undefined') {
const loaderScript = window.document.createElement('script');
loaderScript.type = 'text/javascript';
loaderScript.src = loaderUrl;
loaderScript.addEventListener('load', onGotAmdLoader);
window.document.body.appendChild(loaderScript);
window.LOADER_PENDING = true;
} else {
onGotAmdLoader();
}
}
}
}
複製代碼
寫一個組件將加載執行的邏輯封裝在這個組件裏,暴露出一些 api,提供給調用者使用bash
<template>
<div :style="style"></div>
</template>
<script>
import monacoLoader from './MonacoLoader'
const debounce = require('lodash.debounce');
export default {
props: {
// 編輯器的寬,默認 100%
width: { type: [String, Number], default: '100%' },
// 編輯器的高,默認 100%
height: { type: [String, Number], default: '100%' },
// 傳進來的代碼,一段字符串
code: { type: String, default: '// code \n' },
// 資源路徑
srcPath: { type: String },
// 默認使用 js
language: { type: String, default: 'javascript' },
// 主題 默認 vs-dark
theme: { type: String, default: 'vs-dark' }, // vs, hc-black
// 一些 monaco 配置參數
options: { type: Object, default: () => {} },
// 截流
changeThrottle: { type: Number, default: 0 }
},
// 加載資源
created() {
this.fetchEditor();
},
// 銷燬
destroyed() {
this.destroyMonaco();
},
computed: {
style() {
const { width, height } = this;
const fixedWidth = width.toString().indexOf('%') !== -1 ? width : `${width}px`;
const fixedHeight = height.toString().indexOf('%') !== -1 ? height : `${height}px`;
return {
width: fixedWidth,
height: fixedHeight,
};
},
editorOptions() {
return Object.assign({}, this.defaults, this.options, {
value: this.code,
language: this.language,
theme: this.theme
});
}
},
data() {
return {
defaults: {
selectOnLineNumbers: true,
roundedSelection: false,
readOnly: false,
cursorStyle: 'line',
automaticLayout: false,
glyphMargin: true
}
}
},
methods: {
editorHasLoaded(editor, monaco) {
this.editor = editor;
this.monaco = monaco;
this.editor.onDidChangeModelContent(event =>
this.codeChangeHandler(editor, event)
);
this.$emit('mounted', editor);
},
codeChangeHandler: function(editor) {
if (this.codeChangeEmitter) {
this.codeChangeEmitter(editor);
} else {
this.codeChangeEmitter = debounce(
function(editor) {
this.$emit('codeChange', editor);
},
this.changeThrottle
);
this.codeChangeEmitter(editor);
}
},
fetchEditor() {
monacoLoader.load(this.srcPath, this.createMonaco);
},
createMonaco() {
this.editor = window.monaco.editor.create(this.$el, this.editorOptions);
this.editorHasLoaded(this.editor, window.monaco);
},
destroyMonaco() {
if (typeof this.editor !== 'undefined') {
this.editor.dispose();
}
}
}
};
</script>
複製代碼
使用組件,將組件顯示在頁面上。並將 console.log 收集起來,執行完代碼以後將其打印在屏幕上。
<template>
<div>
<MonacoEditor
height="300"
language="typescript"
:code="code"
:editorOptions="options"
@codeChange="onCodeChange"
></MonacoEditor>
<div class="console">{{ res }}</div>
</div>
</template>
<script>
import MonacoEditor from '../../components/vue-monaco-editor';
let logStore = [];
export default {
components: {
MonacoEditor
},
data() {
return {
result: 'noop',
// 默認 code
code:
`const noop = () => {
console.log('noop')
}
noop()
`,
options: {}
};
},
methods: {
clear() {
this.result = '';
logStore = [];
},
// 重寫consolelog,並儲存在logStore內
overwriteConsoleLog() {
console.log = function(...arg) {
logStore.push(arg);
};
},
// 抽象出一層修飾層
modify(e) {
if (typeof e === 'object') e = JSON.stringify(e);
return e;
},
// 輸出
printf(oriConsole) {
const _this = this
logStore.forEach(item => {
function str() {
return item.map(_this.modify);;
}
oriConsole(str(item));
this.result +=
str(item)
.join(' ') + '\n';
});
console.log = oriConsole;
},
onCodeChange(code) {
// 保存 console.log 對象
const oriConsole = console.log;
// 清空反作用
this.clear();
// 重寫 console.log,爲了將控制檯打印值輸出在頁面上
this.overwriteConsoleLog();
// 獲取代碼的片斷字符串
const v = code.getValue();
try {
// 執行代碼
eval(v);
// 將控制檯打印值輸出在頁面上
this.printf(oriConsole)
} catch (error) {
console.error(error)
}
}
}
};
</script>
<style lang="scss">
.editor {
width: 100%;
height: 100vh;
margin-top: 50px;
}
.console {
height: 500px;
background: orange;
font-size: 40px;
white-space: pre-wrap;
}
</style>
複製代碼
又到了小結時刻,當咱們看見一個很厲害的東西的時候,不要懼怕,其實你也能夠,大部分的功能其實已經被別人封裝好了,咱們都是站在巨人的肩膀上。
我會常常分享一些本身工做經驗、技術體會、作的小玩意等等。更你們一塊兒學習。
看別人十遍,不如本身動手寫一遍,個人這些源碼和文章都在這裏,能夠本身下載下來運行一下試試。
https://github.com/luoxue-victor/source-code/tree/master/src/views/monacoEditor
有想入羣的學習前端進階的加我微信 luoxue2479 回覆加羣便可
個人公衆號 【前端技匠】,歡迎來關注
個人 github 地址,全部個人文章及源碼都在這裏,歡迎來star
https://github.com/luoxue-victor/source-code
https://github.com/luoxue-victor/source-code/issues