ACE ,Code Mirror, monaco 三款代码编辑器,整体引用都差不多,monaco 是微软出品vscode也是采用的这个.它的智能提示会很方便,如果在nodejs环境下可以添加其它 type.d.ts 文件可以直接智能提示.
下面我是用vue搭的,有三种不同的模式,初始化直接设置就会自动加载,但是编辑器的资源需要你自己事先引入到页面中
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title></title>
<meta charset="utf-8" />
<!--基础库-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.4/ace.js"></script>
<!--提示-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.4/snippets/html.js"></script>
<script src="editor.js"></script>
<style>
</style>
</head>
<body>
<script>
// codeMirror,monaco
initEditor('ace',{
data:{
theme:'ace/theme/chrome',
themes:['ace/theme/chrome','ace/theme/monokai','ace/theme/solarized_dark']
},
mountedCallback:function(view){
if (window.top !== window && window.top.registerEditor) {
window.top.registerEditor({
view: view
})
}
}
})
</script>
</body>
</html>
codemirror:

monaco:

公共js:
(function(){
function loadStyle(css){
var style=document.createElement('style');
try{
style.appendChild(document.createTextNode(css));
}catch(e){
style.styleSheet.cssText=css;
}
document.getElementsByTagName('head')[0].appendChild(style);
}
function loadResource(url,resolve,reject){
var type = url.match(/\.css$/) ? 'link' : 'script';
var r = false;
var h = document.getElementsByTagName('head')[0];
var s = document.createElement(type);
if (type === 'script') {
s.type = 'text/javascript';
s.src = url;
s.async = true;
s.onload = s.onreadystatechange = function onReadyStateChange() {
// eslint-disable-line
if (!r && (!s.readyState || s.readyState === 'complete')) {
r = true;
resolve(s);
}
};
s.onerror = s.onabort = reject; // eslint-disable-line
} else {
s.setAttribute('rel', 'stylesheet');
s.setAttribute('href', url);
s.onload = function onLinkLoad() {
// eslint-disable-line
r = true;
resolve(s);
};
}
h.appendChild(s);
}
function createModules(modules){
var loaded={};
return function load(name,callback){
var dependenciesStack=[];
var set={};
var mods=[];
if(typeof name==='string'){
name=[name];
}
for(var i=0;i<name.length;i++){
add(name[i]);
mods.push({
name:name[i],
dependenciesStack:dependenciesStack.slice(1)
});
dependenciesStack.length=0;
set={};
}
function add(name){
var m=modules[name];
if(m&&!set.hasOwnProperty(name)){
var dependencies=m.dependencies||[];
set[name]=true;
dependenciesStack.push(name)
if(typeof dependencies=='string'){
dependencies=[dependencies];
}
for(var i=0;i<dependencies.length;i++){
add(dependencies[i]);
}
}
}
function loadResourceQueue(name,callback){
var m=modules[name];
if(loaded[name]===true){
callback();
return;
}
loaded[name]=true;
var len=0,completeCount=0;
function complete(){
completeCount++;
if(completeCount>=len&&callback){
callback()
}
}
if(m.js){
len++;
loadResource(m.js,complete,complete);
}
if(m.css){
len++;
loadResource(m.css,complete,complete);
}
}
function load(m){
var name=m.name,dependenciesStack=m.dependenciesStack;
function complete(){
loadResourceQueue(name,finish)
}
function runLoad(){
var len=dependenciesStack.length;
if(len<=0){
complete();
return;
}
loadResourceQueue(dependenciesStack.pop(),runLoad)
}
runLoad();
}
var loadCount=0;
function finish(){
loadCount++;
if(loadCount>=mods.length){
callback&&callback();
}
}
for(var i=0;i<mods.length;i++){
load(mods[i])
}
}
}
var loadModule=createModules({
datgui:{
js:"https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.6/dat.gui.js"
},
localforage:{
js:"https://cdnjs.cloudflare.com/ajax/libs/localforage/1.7.3/localforage.js"
},
vconsole:{
js:'https://cdnjs.cloudflare.com/ajax/libs/vConsole/3.3.0/vconsole.min.js'
},
logLevel:{
js:'https://cdnjs.cloudflare.com/ajax/libs/loglevel/1.6.3/loglevel.min.js'
},
console:{
js:'https://cdn.jsdelivr.net/npm/consola@2.9.0/dist/consola.browser.min.js'
},
store:{
js:'https://cdnjs.cloudflare.com/ajax/libs/store.js/1.3.20/store.min.js'
},
jquery:{
js:'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.js'
},
vue:{
js:'https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.js',
dependencies:[]
},
iview:{
js:'https://cdnjs.cloudflare.com/ajax/libs/iview/3.4.1/iview.min.js',
css:'https://cdnjs.cloudflare.com/ajax/libs/iview/3.4.1/styles/iview.css',
dependencies:['vue','jquery']
},
})
let template=`<div id="app">
<Layout>
<Layout>
<Header class="header" :class="{'fixed-header':isFixed}">
<Card>
<Row type="flex" justify="end" align="middle" v-bind:style="{height:'40px',marginRight:'20px'}" v-bind:gutter="5">
<i-col>
<i-button @click="onClear">清空</i-button>
</i-col>
<i-col>
<i-button @click="onAddResources">添加资源</i-button>
</i-col>
<i-col>
<i-button @click="onRun">运行</i-button>
</i-col>
<i-col>
<i-select v-model="theme" @on-change="onThemeChange">
<i-option v-for="name in themes" :key="name" :value="name">{{name | themeName}}</i-option>
</i-select>
</i-col>
</Row>
</Card>
</Header>
<Content :class="['content',isFixed?'fixed-content':'']">
<Row >
<i-col :xl="12" >
<d-preview v-bind:resources="resources" ref="preview" v-bind:js="js" v-bind:css="css" v-bind:html="html"></d-preview>
</i-col>
<i-col :xl="12" >
<Card>
<Tabs v-bind:value="editorTab">
<tab-pane label="html" name="html">
<d-editor v-model="html" v-on:on-change="onHtmlChange" v-bind:mode="htmlMode" v-bind:theme="theme"/>
</tab-pane>
<tab-pane label="javascript" name="javascript">
<d-editor v-model="js" v-on:on-change="onJsChange" v-bind:mode="jsMode" v-bind:theme="theme" />
</tab-pane>
<tab-pane label="css" name="css">
<d-editor v-model="css" v-on:on-change="onCssChange" v-bind:mode="cssMode" v-bind:theme="theme" />
</tab-pane>
</Tabs>
</Card>
</i-col>
</Row>
</Content>
<Footer>
</Footer>
</Layout>
</Layout>
<page-resource v-model="visibleResouce" @on-change="onResourcesChange" v-bind:value="resources" />
</div>
`;
function ShowAutocompletion(obj) {
// Disable default autocompletion for javascript
// monaco.languages.typescript.javascriptDefaults.setCompilerOptions({ noLib: true });
// Helper function to return the monaco completion item type of a thing
function getType(thing, isMember) {
isMember = (isMember == undefined) ? (typeof isMember == "boolean") ? isMember : false : false; // Give isMember a default value of false
switch ((typeof thing).toLowerCase()) {
case "object":
return monaco.languages.CompletionItemKind.Class;
case "function":
return (isMember) ? monaco.languages.CompletionItemKind.Method : monaco.languages.CompletionItemKind.Function;
default:
return (isMember) ? monaco.languages.CompletionItemKind.Property : monaco.languages.CompletionItemKind.Variable;
}
}
// Register object that will return autocomplete items
monaco.languages.registerCompletionItemProvider('javascript', {
// Run this function when the period or open parenthesis is typed (and anything after a space)
triggerCharacters: ['.', '('],
// Function to generate autocompletion results
provideCompletionItems: function(model, position, token) {
// Split everything the user has typed on the current line up at each space, and only look at the last word
var last_chars = model.getValueInRange({startLineNumber: position.lineNumber, startColumn: 0, endLineNumber: position.lineNumber, endColumn: position.column});
var words = last_chars.replace("\t", "").split(" ");
var active_typing = words[words.length - 1]; // What the user is currently typing (everything after the last space)
// If the last character typed is a period then we need to look at member objects of the obj object
var is_member = active_typing.charAt(active_typing.length - 1) == ".";
// Array of autocompletion results
var result = [];
// Used for generic handling between member and non-member objects
var last_token = obj;
var prefix = '';
if (is_member) {
// Is a member, get a list of all members, and the prefix
var parents = active_typing.substring(0, active_typing.length - 1).split(".");
last_token = obj[parents[0]];
prefix = parents[0];
// Loop through all the parents the current one will have (to generate prefix)
for (var i = 1; i < parents.length; i++) {
if (last_token.hasOwnProperty(parents[i])) {
prefix += '.' + parents[i];
last_token = last_token[parents[i]];
} else {
// Not valid
return result;
}
}
prefix += '.';
}
// Get all the child properties of the last token
for (var prop in last_token) {
// Do not show properites that begin with "__"
if (last_token.hasOwnProperty(prop) && !prop.startsWith("__")) {
// Get the detail type (try-catch) incase object does not have prototype
var details = '';
try {
details = last_token[prop].__proto__.constructor.name;
} catch (e) {
details = typeof last_token[prop];
}
// Create completion object
var to_push = {
label: prefix + prop,
kind: getType(last_token[prop], is_member),
detail: details,
insertText: prop
};
// Change insertText and documentation for functions
if (to_push.detail.toLowerCase() == 'function') {
to_push.insertText += "(";
to_push.documentation = (last_token[prop].toString()).split("{")[0]; // Show function prototype in the documentation popup
}
// Add to final results
result.push(to_push);
}
}
return {
suggestions:result
};
}
});
}
function EditorBase(el){
this.el=el;
this.event=$({});
this.theme='';
this.mode='';
this.value='';
}
EditorBase.prototype={
constructor:EditorBase,
setTheme:function(value){},
setMode:function(value){},
setValue:function(value){},
getValue:function(){ return this.value;},
clear:function(){},
on:function(type,handler){
this.event.on(type,function(e){
handler.apply(this,Array.prototype.slice.call(arguments,1))
})
},
emit:function(type){
var args=Array.prototype.slice.call(arguments,1);
this.event.triggerHandler(type,args)
}
}
function inherits(childCtor, parentCtor) {
childCtor.prototype = Object.create(parentCtor.prototype);
childCtor.prototype.constructor = childCtor;
}
function extendClass(superClss,subProperties){
function subClass(){
superClss.apply(this,arguments);
this.init&&this.init.apply(this,arguments)
}
inherits(subClass,superClss);
Object.assign(subClass.prototype,subProperties);
// for (let nextKey in nextSource) {
// // Avoid bugs when hasOwnProperty is shadowed
// if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
// to[nextKey] = nextSource[nextKey];
// }
// }
return subClass;
}
var AceEditor=extendClass(EditorBase,{
init:function(){
var that=this;
that.editor= ace.edit(this.el);
this.editor.clearSelection();
this.editor.on('change',function(a,editor){
that.emit('change',that.editor.getValue())
});
ace.config.loadModule("ace/ext/language_tools", function() {
that.editor.setOptions({
autoScrollEditorIntoView: true,
enableBasicAutocompletion: true,
enableSnippets: true,
enableLiveAutocompletion: true
});
});
},
setTheme:function(value){
this.theme=value;
this.editor.setTheme(value)
},
setMode:function(value){
// console.log(value)
var mode= this.mode=value;
switch(this.mode){
case "js":
mode='ace/mode/javascript';
break;
case "css":
mode='ace/mode/css';
break;
case "html":
mode= 'ace/mode/html';
break;
}
this.editor.session.setMode(mode);
},
setValue:function(value){
this.value=value;
this.editor.setValue(value);
},
clear:function(){
this.setValue('')
}
});
var MonacoEditor=extendClass(EditorBase,{
init:function(){
var that=this;
that.editor= monaco.editor.create(this.el,{
// model:monaco.editor.createModel("","javascript")
});
this.editor.onDidChangeModelContent(function(a,editor){
that.emit('change',that.editor.getValue())
});
},
setTheme:function(value){
this.theme=value;
//this.editor.setTheme(value);
monaco.editor.setTheme(value);
},
setMode:function(value){
// console.log(value)
var mode =this.mode=value;
switch(this.mode){
case "js":
mode='javascript';
break;
case "css":
mode='css';
break;
case "html":
mode= 'html';
break;
}
monaco.editor.setModelLanguage(this.editor.getModel(),mode)
//this.editor.setModel(monaco.editor.createModel('',mode));
},
setValue:function(value){
this.value=value;
this.editor.setValue(value);
},
clear:function(){
this.setValue('')
}
})
var CodeMirrorEditor=extendClass(EditorBase,{
init:function(){
var that=this;
var editor=this.editor=CodeMirror(that.el,{
extraKeys: {"Ctrl-.": "autocomplete"},
showHint:{
// extraKeys:{".": "autocomplete"},
},
lineNumbers: true,
mode:"text/html"
});
this.editor.on('change',function(a,editor){
that.emit('change',that.editor.getValue())
});
},
setTheme:function(value){
this.theme=value;
//this.editor.setTheme(value);
var theme=value.split(/\s+/)[0];
if(!$('link[data-theme="'+theme+'"]').length&&this.theme!='default'){
var link= $('<link>',{
rel:"stylesheet",
href:"https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.46.0/theme/"+theme+".css"
})
$('head:first').append(link)
}
this.editor.setOption('theme',this.theme);
},
setMode:function(value){
// console.log(value)
var mode=this.mode=value;
switch(this.mode){
case "js":
mode='text/javascript';
break;
case "css":
mode='text/css';
break;
case "html":
mode= 'text/html';
break;
}
this.editor.setOption('mode',mode);
},
setValue:function(value){
this.value=value;
this.editor.setValue(value);
},
clear:function(){
this.setValue('')
}
})
var scriptRources=[];
var codeEditorTypes={
ace:AceEditor,
monaco:MonacoEditor,
codeMirror:CodeMirrorEditor
}
window.initEditor=initEditor;
function initEditorStyle(){
loadStyle(`
.exmaple{
width:100%;
height:80vh;
}
.exmaple iframe {
width: 100%;
height: 100%;
border:0;
}
.dx-editor{
height:80vh;
}
.header{
}
.header .ivu-card-body{
padding:5px;
}
.fixed-header{
position:fixed;
width:100%;
z-index:2;
}
.content{
margin:10px;
}
.fixed-content{
margin-top:65px;
}
`);
}
function initEditor(type,options){
loadModule(['jquery','iview','localforage'],function(){
if(options&&options.onload){
options.onload();
}
initEditorStyle();
initEditor.init(type,options)
})
}
initEditor.init=function _initEditor(type,options){
options=options||{};
Vue.use(iview);
var root=$(template).appendTo(options.container?options.container:'body');
var CodeEditor=codeEditorTypes[type];
var Editor=Vue.extend({
template:'<div ref="editor" class="dx-editor"></div>',
props:{
value:{
type:String,
default:""
},
mode:{
type:String,
default:"js",
// validator:function(val){
// return ['js','html','css'].includes(val);
// }
},
theme:{
type:String,
default:""
}
},
data:function(){
return {
currentValue:'',
currentTheme:'',
currentMode:''
}
},
watch:{
mode:{
immediate:false,
handler:function(v){
this.setMode(v)
}
},
theme:{
immediate:false,
handler:function(v){
this.setTheme(v);
}
},
value:function(v){
this.setValue(v);
}
},
methods:{
setTheme:function(theme){
if(!theme||theme===this.currentTheme){
return;
}
this.currentTheme=theme;
this.editor.setTheme(theme)
},
setMode:function(mode){
if(mode==this.currentMode){
return;
}
this.currentMode=mode;
this.editor.setMode(mode)
},
init:function(){
this.setMode(this.mode);
this.setTheme(this.theme);
this.setValue(this.value);
var that=this;
this.editor.on('change',function(value){
that.onChange(value);
});
},
setValue:function(value){
if(value==this.currentValue){
return;
}
this.currentValue=value;
this.editor.setValue(value);
},
onChange:function(v){
this.currentValue=v;
this.$emit('input',v);
this.$emit('on-change',v,this.editor);
},
clear:function(){
this.editor.setValue('');
this.onChange('');
}
},
beforeCreate:function(){
},
mounted:function(){
this.editor = new CodeEditor(this.$refs.editor);
this.init();
}
})
Vue.component('PageResource',function(resolve){
resolve({
template:`<Drawer width="80vw" title="添加资源" :closable="true" :value="visible" @on-visible-change="onVisibleChange">
<i-form ref="form" :model="resourceForm" :rules="validateRules">
<FormItem label="资源" prop="url">
<i-input v-model="resourceForm.url"/>
</FormItem>
<FormItem>
<i-button @click="onAdd">添加</i-button>
</FormItem>
</i-form>
<Card :bordered="true" :dis-hover="false" :shadow="true">
<p slot="title">依赖资源</p>
<i-table :data="tableData" :columns="columns"></i-table>
</Card>
</Drawer>`,
model: {
prop: 'visible',
event: 'change'
},
props:{
visible:{
type:Boolean,
default:false
},
value:{
type:Array,
default:function(){
/**
version:"",
name:"",
url:"",
type:"js|css"
*/
return [];
}
}
},
data:function(){
var that=this;
return {
resourceForm:{
url:""
},
validateRules:{
url:[{
required:true,
message:"请添加资源引用路径"
},{
pattern:/\.(?:js|css)$/i,
message:"你的路径格式不正确"
}]
},
columns:[{
title:"名称",
key:"name"
},{
title:"版本",
key:"version"
}
,{
title:"类型",
key:"type"
},{
title:"操作",
render:function(h,params){
return h('div', [
h('Button', {
props: {
type: 'primary',
size: 'small'
},
style: {
marginRight: '5px'
},
on: {
click:function(){
this.show(params.index)
}
}
}, 'view'),
h('Button', {
props: {
type: 'error',
size: 'small'
},
on: {
click: function(){
console.log('ff')
that.remove(params.index)
}
}
}, 'del')
]);
}
}],
tableData:this.value
};
},
watch:{
value:function(v){
this.setCurrentValue(v)
}
},
methods:{
normalFile:function(url){
if(typeof url!='string'){
return url
}
var m=url.match(/((?:\d+\.)+\d+)|([^/]+)(?:(\.js|\.css)$)/g);
if(m){
var fileName=m.length>1?m[1]:m[0];
var fileNames=fileName.split('.');
return {
version:m.length>1?m[0]:"",
name:fileNames[0],
url:url,
type:fileNames[fileNames.length-1].toLowerCase()
}
}
},
remove:function(index){
this.tableData.splice(index,1)
this.onChange();
},
onAdd:function(){
var that=this;
this.$refs.form.validate(function(vali){
if(!vali){
return;
}
var file=that.normalFile(that.resourceForm.url);
if(file&&!that.tableData.some(function(d){
return d.name==file.name;
})){
that.tableData.push(file)
that.onChange();
}
})
},
onChange:function(){
this.$emit('on-change',this.tableData);
},
setCurrentValue:function(v){
if(v===this.tableData){
return;
}
this.tableData=v;
},
onVisibleChange:function(v){
this.$emit('change',v);
},
toResources:function(){
return [].concat(this.tableData.map(function(file){
if(file.type=="js"){
return `<script src="${file.url}" ><\/script>`;
}else{
return `<link rel="stylesheet" href="${file.url}" />`;
}
})).join('\n')
}
},
/*beforeCreate
created
beforeMount
mounted
beforeUpdate
updated
activated
deactivated
beforeDestroy
destroyed
errorCaptured*/
created:function(){
},
mounted:function(){
// this.update();
},
beforeDestroy:function(){
}
});
})
var DPreview=Vue.extend({
template:`<Card>
<p slot="title">
<Icon type="ios-film-outline"></Icon>
Exmaple
</p>
<template slot="extra" >
<i-switch v-model="realTime" size="large" >
<span slot="open">实时</span>
<span slot="close">关闭</span>
</i-switch>
</template>
<div class="exmaple"><iframe ref="previewFrame"></iframe></div>
</Card>`,
props:{
inline:{
type:Boolean,
default:false
},
js:String,
css:String,
html:String,
resources:{
type:Array,
default:function(){
return [];
}
}
},
data:function(){
return {
realTime:false
};
},
watch:{
resources:function(v){
this.update('resources');
},
js:function(){
this.update('js');
},
css:function(){
this.update('css');
},
html:function(){
this.update('html');
}
},
methods:{
init:function(){
var previewFrame=this.$refs.previewFrame;
var preview = previewFrame.contentDocument || previewFrame.contentWindow.document;
if(this.inline){
var elStyle=preview.createElement('style');
var elHtmlPlaceholder=preview.createComment('html-start');
preview.getElementsByTagName('head')[0].appendChild(elStyle);
preview.body.appendChild(elHtmlPlaceholder)
this.elHtmlPlaceholder=elHtmlPlaceholder;
this.elStyle=elStyle;
this.htmls=[];
}
this.previewDoc=preview;
},
write:function(code){
var previewFrame=this.$refs.previewFrame;
var preview = previewFrame.contentDocument || previewFrame.contentWindow.document;
// preview.open();
preview.write(code);
preview.close();
},
update:function(type){
type=type||"*";
if(this.inline&&(type!="*"&&this.realTime||type=="*")){
if(type=="*"||type==='css'){
this.updateCss(this.css);
}
if(type=="*"||type==='resources'){
this.updateResources(this.resources);
}
if(type=="*"||type==='html'){
this.updateHtml(this.html);
}
if(type=="*"||type==='js'){
this.updateJs(this.js);
}
}else if(!this.inline&&this.realTime){
this.preview();
}
},
updateJs:function(value){
try{
var elScript=this.previewDoc.createElement('script');
elScript.text=value;
if(this.elScript){
this.previewDoc.body.replaceChild(elScript,this.elScript);
}else{
this.previewDoc.body.appendChild(elScript);
}
this.elScript=elScript;
}catch(e){
throw e;
}
},
updateCss:function(value){
try{
this.elStyle.innerHTML=value;
}catch(e){
throw e;
}
},
updateHtml:function(value){
try{
// var d=new DOMParser().parseFromString(value,'text/html')
// var m=d.body;
var d=this.previewDoc.createElement('div');
d.innerHTML=value;
var m=d;
var node;
var that=this,i=-1,len=that.htmls.length;
while(++i<len){
that.previewDoc.body.removeChild(that.htmls[i]);
}
that.htmls.length=0;
while((node=m.firstChild)){
that.htmls.push(node);
that.previewDoc.body.insertBefore(node,that.elHtmlPlaceholder);
}
}catch(e){
throw e;
}
},
updateResources:function(resources){
var that=this,previewDoc=that.previewDoc,
resourcesList=that.resourcesList,
cloneResourcesList=resourcesList.slice();
var alreadMap=new Map();
var resourcesMap=resources.reduce(function(map,s){
map.set(s.name,s);
return map;
},new Map())
cloneResourcesList.forEach(function(r,index){
if(!resourcesMap.has(r.name)){
resourcesList.splice(index,1);
previewDoc.removeChild(r.el);
}else{
alreadMap.set(r.name,r);
}
});
resources.forEach(function(r){
if(!alreadMap.has(r.name)){
var el;
if(r.type=="js"){
el=previewDoc.createElement('script');
el.src=r.url;
}else if(r,type=='css'){
el=previewDoc.createElement('style');
el.setAttribute('rel','stylesheet');
el.href=r.url;
}
previewDoc.getElementsByTagName('head')[0].appendChild(el);
resourcesList.push({
name:r.name,
el:el
})
}
})
},
toResources:function(){
return this.resources.map(function(file){
if(file.type=="js"){
return `<script src="${file.url}" ><\/script>`;
}else{
return `<link rel="stylesheet" href="${file.url}" />`;
}
}).join('\n')
},
preview:function(){
if(this.inline){
this.update();
}else{
this.write(this.template(this.html,this.css,this.js));
}
},
template:function(html,style,js){
return `
<!DOCTYPE html>
<html>
<head>
<title></title>
${this.toResources()}
<style>${style}</style>
</head>
<body>
${html}
<script>
${js}
<\/script>
</body>
</html>
`;
}
},
created:function(){
this.resourcesList=[];
},
mounted:function(){
this.init();
},
beforeDestroy:function(){
}
})
var initData=$.extend({
isFixed:true,// 是否固定头部
css:'',
js:'',
html:'',
htmlMode:'html',
jsMode:'js',
cssMode:'css',
themes:[],
theme:"",
editorTab:"html",
visibleResouce:false,
resources:[]
},options.data||{});
var defaultResources=[{
type:"js",
name:"jquery",
version:'3.4.1',
url:'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.js'
}]
// initData.resources.unshift({
// type:"js",
// name:"consola",
// version:'2.9.0',
// url:'https://cdn.jsdelivr.net/npm/consola@2.9.0/dist/consola.browser.min.js'
// })
initData.resources=defaultResources.concat(initData.resources);
var currentStore = localforage.createInstance({
name: window.top.location.pathname
});
var view=new Vue({
el:"#app",
components:{
'd-editor':Editor,
'd-preview':DPreview
},
data:initData,
computed:{
allResources:function(){
return defaultResources.concat(this.resources)
}
},
watch:{
resources:{
immediate:false,
handler:function(v){
// console.log(v);
}
}
},
filters:{
themeName:function(value){
var name=value.split('/')
return name[name.length-1];
}
},
methods:{
onResourcesChange:function(data){
this.setResources(data);
currentStore.setItem('resources',data)
},
switchTab:function(tab){
this.editorTab=tab;
},
onThemeChange:function(){
},
setResources:function(resources){
if(resources==this.resources){
return;
}
this.resources=resources;
},
setJs:function(value){
this.js=value;
},
setCss:function(value){
this.css=value;
},
setHtml:function(value){
this.html=value;
},
onRun:function(){
this.$refs.preview.preview();
},
onAddResources:function(){
this.visibleResouce=!this.visibleResouce;
},
onClear:function(){
this.js='';
this.css='';
this.html='';
//console.log('ff')
},
onHtmlChange:function(value){
currentStore.setItem('html',value)
},
onJsChange:function(value){
currentStore.setItem('js',value)
},
onCssChange:function(value){
currentStore.setItem('css',value)
}
},
created:function(){
var that=this,js=this.js,css=this.css,html=this.html,resources=this.resources;
currentStore.getItem('js').then(function(value){
if(js===''){
that.setJs(value)
}
});
currentStore.getItem('html').then(function(value){
if(html===''){
that.setHtml(value)
}
})
currentStore.getItem('css').then(function(value){
if(css===''){
that.setCss(value)
}
});
currentStore.getItem('resources').then(function(value){
if(value.length>resources.length){
that.setResources(value)
}
})
},
mounted:function(){
this.onThemeChange();
options.mountedCallback&&options.mountedCallback(this)
}
})
}
window.registerEditor=registerEditor;
function registerEditor(options){
loadModule(['jquery','iview'],function(){
registerEditor.init(options);
})
}
registerEditor.init=function(options){
options=options||{};
var container=options.container||document.body;
var pageUID=options.pageUID||window.location.pathname;
var el=$('<div v-pre>').appendTo(container);
var root=$('<div><d-editor :css="css" :js="js" :html="html" :resources="resources" ></d-editor></div>').appendTo(el);
var view=new Vue({
data:$.extend({
css:"",
js:"",
html:"",
resources:[]
},options.data||{}),
components:{
'd-editor':EmapleEditor(Vue)
}
})
view.$mount(root[0]);
options.callback&&options.callback(view);
}
function EmapleEditor(vue){
return vue.extend({
template:` <iframe frameborder="0" scrolling="auto" ref="iframeAce" width="100%" height="100%" :src="src" :style="styles" @load="onLoadEditor"></iframe>`,
props:{
editorType:{
type:Number,
default:3
},
tab:{
type:String,
default:"html"
},
css:{
type:String,
default:""
},
js:{
type:String,
default:""
},
html:{
type:String,
default:""
},
resources:{
type:Array,
default:function(){
return [];
}
},
autocompletion:{
type:String,
default:''
}
},
computed:{
src:function(){
if(this.editorType===1){
return '/exmaple/userinterface/codeEditor/ace.html';
}else if(this.editorType===2){
return '/exmaple/userinterface/codeEditor/codeMirror.html';
}else if(this.editorType===3){
return '/exmaple/userinterface/codeEditor/monaco-editor.html';
}
return '/exmaple/userinterface/codeEditor/monaco-editor.html';
}
},
data:function(){
return {
styles:{
minHeight:"100vh"
}
};
},
watch:{
resources:{
immediate:false,
handler:function(v){
this.update('resources');
}
},
css:{
immediate:false,
handler:function(v){
this.update('css');
}
},
html:{
immediate:false,
handler:function(v){
this.update('html');
}
},
js:{
immediate:false,
handler:function(v){
this.update('js');
}
},
tab:function(v){
this.switchTab()
}
},
methods:{
update:function(type){
type=type===undefined?"*":type;
var that=this,editorView=that.editorView;
if(!editorView){
return;
}
if(type=="*"||type=="resources"){
editorView.setResources(this.resources)
}
if(type=="*"||type=="css"){
editorView.setCss(this.css)
}
if(type=="*"||type=="js"){
editorView.setJs(this.js)
}
if(type=="*"||type=="html"){
editorView.setHtml(this.html)
}
},
switchTab:function(){
this.editorView.switchTab(this.tab)
},
init:function(){
this.update();
this.switchTab();
},
onLoadEditor:function(){
}
},
created:function(){
var that=this;
that.editorView=null;
window.registerEditor=function registerEditor(d){
that.editorView=d.view;
that.init();
}
},
mounted:function(){
this.update();
}
})
}
if(typeof Vue==='function'){
Vue.component('d-edtior',EmapleEditor(Vue))
}
function createHtmlEditor(el,options){
var editor = ace.edit(el);
editor.session.setMode("ace/mode/html");
return editor;
}
function createCssEditor(el,options){
var editor = ace.edit(el);
editor.session.setMode("ace/mode/css");
return editor;
}
function createJavascriptEditor(el,options){
var editor = ace.edit(el);
editor.session.setMode("ace/mode/javascript");
return editor;
}
function createPreview(wrapper){
var previewFrame =document.createElement('iframe');
wrapper.appendChild(previewFrame);
//<iframe srcdoc="<p>这是HTML<p>" frameborder="0"></iframe>
// <iframe src="data:text/html,<p>这是HTML<p>" frameborder="0"></iframe>
/*
<iframe src="javascript:void(function(){document.open();document.write('<p>这是HTML<p>');document.close();}())" frameborder="0">
</iframe>
*/
function updateView(code){
var preview = previewFrame.contentDocument || previewFrame.contentWindow.document;
preview.open();
preview.write(code);
preview.close();
}
function createScript(){
var script=document.createElement('script');
script.type="text/javascript";
return function(value){
}
}
function createStyle(){
var script=document.createElement('script');
script.type="text/css";
}
function createHtml(){
var script=document.createElement('script');
script.type="text/javascript";
}
updateView.splitValue=function(html,css,js){
var doc=document.implementation.createHTMLDocument();
}
return updateView;
}
function updatePreview() {
var previewFrame =document.getElementById('preview');
var preview = previewFrame.contentDocument || previewFrame.contentWindow.document;
preview.open();
preview.write(editor.getValue());
preview.close();
}
(function(DOMParser) {
"use strict";
var proto = DOMParser.prototype,
nativeParse = proto.parseFromString;
// Firefox/Opera/IE throw errors on unsupported types
try {
// WebKit returns null on unsupported types
if ((new DOMParser()).parseFromString("", "text/html")) {
// text/html parsing is natively supported
return;
}
} catch (ex) {}
proto.parseFromString = function(markup, type) {
if (/^\s*text\/html\s*(?:;|$)/i.test(type)) {
var
doc = document.implementation.createHTMLDocument("")
;
if (markup.toLowerCase().indexOf('<!doctype') > -1) {
doc.documentElement.innerHTML = markup;
}
else {
doc.body.innerHTML = markup;
}
return doc;
} else {
return nativeParse.apply(this, arguments);
}
};
}(DOMParser));
})();
版权声明:本文为long5305350原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。