Search code examples
javascripthtmlvue.jsvue-componentcodemirror

Vue dynamic load components and highlight code preview and preserve HTML structure


Im trying to dynamic load vue components and when the component is visibile it should show the HTML of the component as a code preview.

This is successful and is working but is showing one big string because i use the $el.innnerHTML. What i want is that the structure of the component/html should be mirrored in the code preview.

This is the result now:

enter image description here

What i want:

enter image description here

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  <title>Document</title>
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
    integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous" />
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.14.0/themes/prism.min.css" />
</head>

<body>
  <div id="app" class="container mt-5">
    <div class="row">
      <div class="col-12">

        <select v-model="selected" @change="onChange">
          <option disabled value="">Please select one</option>
          <option value="componentOne">A</option>
          <option value="componentTwo">B</option>
        </select>

        <component :is="selected" :ref="mychildcomponent"></component>
        <code-highlight :code="codeHighlight"></code-highlight>

      </div>
    </div>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.14.0/prism.min.js"></script>

  <script>
    Vue.component("componentOne", {
      template: `
        <div>
          <div>
            <p>Home component</p>
          </div>
        </div>
        `
    });

    Vue.component("componentTwo", {
      template: `
        <div>
          <div>
            <p>Posts component</p>
          </div>
        </div>
      `
    });

    Vue.component("code-highlight", {
      props: ["code"],
      template: "<pre class='language-markup'><code class='language-markup' v-html='highlightedCode'></code></pre>",
      computed: {
        highlightedCode: function () {
          return Prism.highlight(this.code, Prism.languages.javascript);
        }
      },
    });

    new Vue({
      el: "#app",
      data: {
        selected: "",
        mychildcomponent: "mychildcomponent",
        codeHighlight: ""
      },
      methods: {
        onChange() {
          setTimeout(() => {
            this.codeHighlight = this.$refs.mychildcomponent.$el.innerHTML;
          })
        }
      }
    });
  </script>
</body>

</html>

Example

Here is a JSFiddle


Solution

  • You can use <pre> tag like:

    Vue.component("componentOne", {
          template: `
            <pre>
              <div>
                <p>Home component</p>
              </div>
            </pre>
            `
        });
    

    <PRE> tag will show text on web page as it is.