实现一个 Element UI 在线演练场

816 阅读1分钟

有时候想在 Vue 单文件组件里试一试 Element UI 组件的用法,但每次都要启动运行环境,挺麻烦的,遂自己实现一个简易便捷的能在线写 Vue 单文件组件代码、使用 Element UI 组件、在线运行的网页。

为了方便使用,放到码上掘金了。

代码如下,一个 HTML 文件搞定,随处可用,核心就是利用 vue-template-compiler 解析 Vue 单文件组件代码。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>Element UI Playground</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/element-ui/lib/theme-chalk/index.css">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/codemirror/lib/codemirror.css">
  <style>
    *,
    *::before,
    *::after {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    body {
      height: 100vh;
      display: flex;
    }
    .code-area {
      /* flex: 1; */
      width: 50%;
      resize: horizontal;
      overflow: hidden;
      flex-shrink: 0;
      border-right: 1px solid #ccc;
    }
    .preview-area {
      flex: 1;
      overflow: auto;
    }
    #code {
      display: none;
    }
    .run {
      position: fixed;
      top: 0;
      right: calc(50% + 20px);
      padding: 3px 10px;
      color: #fff;
      background-color: #5078ff;
      border-bottom-left-radius: 5px;
      border-bottom-right-radius: 5px;
      z-index: 2;
      cursor: pointer;
    }
    .CodeMirror {
      font-family: consolas;
      font-size: 14px;
      height: 100%;
    }
  </style>
</head>
<body>
  <div class="code-area">
    <textarea id="code"><template>
  <div class="page">
    <el-button @click="visible = true">Button</el-button>
    <el-dialog :visible.sync="visible" title="Hello world">
      <p>Try Element UI</p>
    </el-dialog>
  </div>
</template>

<script>
export default {
  data() {
    return {
      visible: false
    }
  }
}
</script>

<style>
.page {
  padding: 20px;
}
</style></textarea>
  </div>
  <span class="run" onclick="run()">运行</span>
  <div id="app" class="preview-area"></div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
  <script src="https://cdn.jsdelivr.net/npm/vue-template-compiler"></script>
  <script src="https://cdn.jsdelivr.net/npm/element-ui/lib/index.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/codemirror/lib/codemirror.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/codemirror/addon/mode/overlay.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/codemirror/addon/edit/matchbrackets.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/codemirror/addon/edit/closebrackets.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/codemirror/addon/edit/closetag.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/codemirror/mode/xml/xml.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/codemirror/mode/javascript/javascript.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/codemirror/mode/css/css.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/codemirror/mode/htmlmixed/htmlmixed.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/codemirror/mode/vue/vue.js"></script>
  <script>
    const code = document.getElementById('code')
    const app = document.getElementById('app')
    const editor = CodeMirror.fromTextArea(code, {
      lineNumbers: true,
      matchBrackets: true,
      autoCloseBrackets: true,
      autoCloseTags: true,
      mode: { name: 'vue' }
    })

    function run() {
      const compiler = VueTemplateCompiler.parseComponent(editor.getValue())

      const option = new Function(
        compiler.script.content.replace('export default', 'return')
      )()
      option.template = compiler.template.content

      const vueStyle = document.getElementById('vue-style')
      if (vueStyle) document.getElementsByTagName('head')[0].removeChild(vueStyle)
      if (compiler.styles[0]) {
        const style = document.createElement('style')
        style.id = 'vue-style'
        style.innerHTML = compiler.styles[0].content
        document.getElementsByTagName('head')[0].appendChild(style)
      }

      const component = new Vue(option).$mount()
      app.innerHTML = ''
      app.appendChild(component.$el)
    }
  </script>
</body>
</html>