• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

手动实现vue在线代码运行,仿Vue SFC Playground

武飞扬头像
海天酱油_htSauce
帮助3

当初vue3发布的时候是被Vue SFC Playground惊艳了一下,自己也跑过,核心是使用@vue/compiler-sfc实现的vue文件编译转换成对应的js代码然后放在页面进行执行,功能很好,但是也比较笨重了。

我最近是自己瞎琢磨一些组件开发,想着是能做到页面可编辑,然后实时可以看到运行结果。其中官方的Vue SFC Playground就很好,但是又觉得如果我页面上面有很多个示例,对于页面运行是否是一种负担呢?

尝试1:直接把代码通过输入的方式展示在页面上

  <textarea class="edit" @input="onchange" v-model="text"></textarea>
  <div v-html="text"></div>

结果显而易见的不行

尝试2:纯原生html

代码方式和上面差不多

查看官方文档,发现构建环境下是运行时的vue包,不包含编译器

然后我就放到了纯html下面写,结果还是不行

尝试3:是不是输入的内容没有编译导致呢

这次方向对了,但是通过刷新key等方式都是不行的,通过F12可以看到,如果是封装的组件在页面上是不会展示组件名称的,而是编译过的html标签。但是通过输入得到的内容

如:

在html中查看依旧是,并不会变成div之类的

所以官方需要把代码编译过才能运行

最终成功

既然如此那么就仿照官方的方式,我差点就放弃用@vue/compiler-sfc去了。最后实现了

首先是test.html文件

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>测试</title>
  <style>
      /*[v-cloak] {*/
      //    display: none;
      //}
  </style>
</head>
<body>
  <div id="app" v-cloak>
    这时候是空数据
  </div>
</body>


<script type="module">
  import { createApp, ref, watch } from './lib/vue.js'
  import MyComponent from './componets/MyComponent.js'
  import RenderComponent from './componets/RenderComponent.js'

  const externalComponents = ref('')
  window.addEventListener('message', (e) => {
    externalComponents.value = e.data
  })
  watch(() => externalComponents.value, (val) => {
    console.log('外部传入的渲染数据',val)
    renderApp()
  })
  let AppExample = null
  function renderApp() {
    if(AppExample) AppExample.unmount()
    const AppTemplate = {
      components: { RenderComponent },
      template: externalComponents.value,
      // setup() {
      //   return {}
      // },
    }
    AppExample = createApp(AppTemplate)

    // 组件不支持大写名称所以需要注意组件多个字母之间用“-”连接方式
    AppExample.component(
      // 注册的名字
      'MyComponent',
      // 组件的实现
      MyComponent
    )
    AppExample.mount('#app')
  }
</script>
</html>

这里的核心在于renderApp这个函数,每次都接收新的postMessage传递过来的数据,然后放入到template当中,形成一个完整的vueOptions的组件。然后重新挂载vue实例,实现重新运行和渲染

test.vue部分代码

采用postMessage给iframe传递数据

<template>
  <button @click="postMessage">发送消息</button>
  <iframe ref="iframeRef" class="iframe" src="/test.html"></iframe>
  <textarea class="edit" @input="onchange" v-model="text"></textarea>
  <div v-html="text"></div>
</template>
<script setup lang="ts">
import { ref } from 'vue'

const iframeRef = ref<HTMLIFrameElement | null>(null)
const text = ref('')
function onchange() {
  console.log(text.value)
}
function postMessage() {
  const iframe = (iframeRef.value as HTMLIFrameElement).contentWindow
  iframe.postMessage(text.value, '*')
}
</script>

<style scoped lang="scss">
.iframe {
  width: 100%;
  height: auto;
}
.edit {
  width: 100%;
  height: 600px;
  background: #41d1ff;
}
</style>

总结

1、vue带编译的文件未压缩的情况下达到400kb,gzip没有测试,参考zip压缩是80kb,还可以的样子

2、只能支持options方式的写法,不是不支持setup,而是没有setup语法糖那种的写法

3、不支持jsx,至少我没有试出来,h()函数的方式是支持的。

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhfffjek
系列文章
更多 icon
同类精品
更多 icon
继续加载