iframe+monaco editor 实现在线编辑(vue3)

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>

  • 9
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

此人很懒€

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值