monaco editor 结合iframe实现在线编辑
主要思路是iframe写入编辑器的代码,编辑器做监听,不断拿到变化的的code值,当点击运行时候,向iframe写入code,这里会出现一个问题,内存中可能已经存在有之前申明的变量,这里要做的是点击运行时候,先销毁原来的iframe,在动态创建新的iframe,再写入新的code,从而实现在线运行的。
仓库:https://gitee.com/chen-sisi00/monaco-editor.git
实现效果:
相关页面布局、monaco组件引入、编辑器与内容展示的拖拉显示功能,下面是全部代码
<template>
<div class="box" ref="box">
<div class="left">
<!--左侧div内容-->
<MonacoEditor :code="codeType == 'HTML' ? html : code" :codeType="codeType" @customEvent="customEvent" :cardName="cardName" @clickHtml="clickHtml">
</MonacoEditor>
</div>
<div class="resize" title="收缩侧边栏">⋮</div>
<div class="right">
<!--右侧div内容-->
<div class="content-box">
<AsyncComponent v-if="cardName != '编辑器运行测试'"></AsyncComponent>
<div id="iframe" style="height: 100%; width: 100%" v-if="cardName == '编辑器运行测试'">
<iframe
src="about:blank#"
unselectable="on"
frameborder="0"
scrolling="no"
style="width: 100%; height: 100%"
ref="myIframe"
id="codeIframe"
allowfullscreen
></iframe>
</div>
</div>
</div>
</div>
</template>
<script>
import { defineComponent, reactive, toRefs, onMounted, ref, computed, defineAsyncComponent } from "vue";
import MonacoEditor from "@/views/home/components/monacoEditor.vue";
import { codeStr } from "@/views/home/config/codeStr"; //编辑代码
import { htmlStr } from "@/views/home/config/htmlStr"; //html编辑代码
import { useRoute } from "vue-router";
export default defineComponent({
components: {
MonacoEditor,
//动态导入来引入组件
AsyncComponent: defineAsyncComponent(() => import(`@/views${useRoute().path}.vue`)),
},
setup() {
const routes = useRoute();
let cardName = ref(routes.query.cardName);
let codeType = ref("Vue");
//vue3代码
let str = codeStr.filter((e) => {
return e.cardName == cardName.value;
})[0]?.code;
let code = ref(str);
const state = reactive({
activeTabs: 1,
});
//html代码
let htmlS = htmlStr.filter((e) => {
return e.cardName == cardName.value;
})[0]?.htmlCode;
let html = ref(htmlS);
// 向iframe空页面写代码
const writeCode = (code) => {
const iframe = document.querySelector("#codeIframe");
iframe.contentWindow.document.open();
iframe.contentWindow.document.write(code);
iframe.contentWindow.document.close();
};
//动态创建
const createIframe = () => {
var iframe = document.createElement("iframe");
iframe.style.width = "100%";
iframe.style.height = "100%";
iframe.style.margin = "0";
iframe.style.padding = "0";
iframe.style.overflow = "hidden";
iframe.style.border = "none";
iframe.id = "codeIframe";
iframe.src = "about:blank#";
document.getElementById("iframe").appendChild(iframe);
return iframe;
};
//销毁 iframe
const destroyIframe = () => {
const thisNode = document.querySelector("#codeIframe");
thisNode.src = "about:blank";
document.getElementById("iframe").removeChild(thisNode);
};
//运行代码
const customEvent = (value) => {
destroyIframe();
createIframe();
writeCode(value);
};
//代码展示切换
const clickHtml = (data) => {
codeType.value = data;
};
onMounted(() => {
dragControllerDiv();
if (cardName.value == "编辑器运行测试") {
writeCode(html.value);
}
});
function dragControllerDiv() {
let resize = document.getElementsByClassName("resize");
let boxDom = document.getElementsByClassName("box");
let leftDom = document.getElementsByClassName("left");
let rightDom = document.getElementsByClassName("right");
for (let i = 0; i < resize.length; i++) {
/*鼠标 按下拖拽区 */
resize[i].onmousedown = function (e) {
// 拖拽区 变色
resize[i].style.background = "#818181";
// 拖拽区 开始的距离
var startX = e.clientX;
// 左边大小 放入 resize
resize[i].left = resize[i].offsetLeft;
/* 鼠标拖拽 */
document.onmousemove = function (ee) {
// 拖拽区 结束的距离
var endX = ee.clientX;
// 移动的距离 (endx-startx)=移动的距离。resize[i].left+移动的距离=左边区域最后的宽度
let leftWidth = resize[i].left + (endX - startX);
// 右边最大宽度
let maxWidth = boxDom[i].clientWidth - resize[i].offsetWidth;
/* 设置 左边 最小值 */
if (leftWidth < 5) leftWidth = 5;
if (leftWidth > maxWidth - 5) leftWidth = maxWidth - 5;
// 设置拖拽条 距离左侧区域的宽度
resize[i].style.left = leftWidth;
// 设置 左边宽度
leftDom[i].style.width = leftWidth + "px";
// 设置右边宽度
rightDom[i].style.width = boxDom[i].clientWidth - leftWidth - 10 + "px";
};
/* 鼠标松开 */
document.onmouseup = function () {
// 取消事件
document.onmousemove = null;
document.onmouseup = null;
// 恢复颜色
resize[i].style.background = "blue";
};
};
return false;
}
}
return {
...toRefs(state),
code,
writeCode,
html,
customEvent,
cardName,
clickHtml,
codeType,
};
},
});
</script>
<style lang="scss" scoped>
.content-box {
height: 100%;
width: 98%;
margin: 0 1%;
border-radius: 20px;
}
.editor {
height: 100%;
width: 100%;
}
.box {
width: 100%;
height: 100%;
display: flex;
background: #000000;
}
.left {
width: 30%;
background: #000000;
height: 100%;
}
.right {
width: 70%;
background: #000000;
height: 100%;
iframe {
width: 100%;
height: 100%;
resize: both;
overflow: auto;
}
}
/*拖拽区div样式*/
.resize {
cursor: col-resize;
float: left;
position: relative;
top: 45%;
background: blue;
border-radius: 5px;
// margin-top: -10px;
width: 10px;
height: 50px;
background-size: cover;
background-position: center;
/*z-index: 99999;*/
font-size: 32px;
color: white;
}
/*拖拽区鼠标悬停样式*/
.resize:hover {
color: #444444;
}
</style>