Implement a simple version of the web editor, no smart hints, and no automatic highlighting of labels (manual highlighting is required)

Vue + highlight.js + js-beautify

The effect is shown below

Js code formatting

The


and tags are used to wrap the HTML code we want to display, because only then can they keep newlines/indentation, etc

The formatting code uses JS-Beautify

Js-beautify provides three js’s for JS, CSS, and HTML, so you don’t have to introduce a lot of unnecessary content at once. For example, I only need to introduce HTML to achieve the effect I want

  • CDN way:
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.0/beautify.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.0/beautify-css.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.0/beautify-html.min.js"></script>
Copy the code
  • NPM way
npm install js-beautify@next
Copy the code
import { js_beautify, css_beautify, html_beautify } from 'js-beautify'
Copy the code

Call API

<pre><code id="html_code"></code></pre>
<pre><code id="css_code"></code></pre>
<pre><code id="js_code"></code></pre>

<script>
  document.querySelector('#html_code').innerText = html_beautify(
    '
       
HTML format
second line
, { indent_size: 2.space_in_empty_paren: true})document.querySelector('#css_code').innerText = js_beautify('body{background:red; width:100%; } ', { indent_size: 2.space_in_empty_paren: true }) document.querySelector('#js_code').innerText = css_beautify( "var test = 'a'; function(){console.log('test',test)}", { indent_size: 2.space_in_empty_paren: true})
</script> Copy the code

There are many parameters for the configuration item, which can be formatted according to the parameters provided by GitHub. Note that after the pre tag, there must be no space or carriage return, otherwise it will be rendered

Html_beautify is not as fast as innerHtml, for example

<pre><code id="html_template_code"></code></pre>

<div style="display: none;" id="html_template">
  <div>
    <h1>Label formatting</h1>
    <div>HTML formatting</div>
  </div>
</div>

<script>
  document.querySelector('#html_template_code').innerText = document.querySelector('#html_template').innerHTML
</script>
Copy the code

Would have achieved the same effect, and would have introduced one less library

Implementation code highlighting

Highlight. Js

Highlight. Js Chinese website, highlight. Js official website

The introduction of

  • CDN pattern
<! -- Core JS library -->
<script src="https://cdn.bootcdn.net/ajax/libs/highlight.js/11.0.1/highlight.min.js"></script>
<! -- Code highlighting style -->
<link href="https://cdn.bootcss.com/highlight.js/9.12.0/styles/atom-one-dark.min.css" rel="stylesheet" />
Copy the code
  • NPM model
npm install highlight.js

// highlight.js code highlighting instructions
import Hljs from "highlight.js";
import "highlight.js/styles/stackoverflow-light.css"; / / code highlight style, choose more style needs to import node_modules/hightlight js/styles/directory other CSS files
Copy the code

usage

In the corresponding code/pre tag, note the corresponding language, such as:

<pre><code class="language-html"></code></pre>
<pre><code class="language-javascript"></code></pre>
<pre><code class="language-css"></code></pre>
Copy the code

After the page is rendered, execute the following method to highlight the code

hljs.highlightAll()
Copy the code

If the node is rendered later, or you just want to update a block of code, use the following method

hljs.highlightBlock(document.querySelector('#html_code'))
Copy the code

There are more apis such as hljs.config, which can be viewed in the documentation

Highlight.js highlights code without line breaks

In the image below, you’ve just done a good job with js-Beautify, with no line breaks after highlighting

If you look at the highlighted HTML, it doesn’t really matter. It does matter if you don’t have pre tags

Take a look at the correct demonstration:

How did you do that? I’m going to change innerText to innerHTML. Let’s talk more about that

What’s the difference between innerText and innerHTML

The rendered interface does look the same, changing lines to newlines, changing Spaces to whitespace, but the internal HTML is quite different.

  • innerTextMethod obviously replaces the code block with a newline for us<br>The label
  • The innerHtml method renders the HTML code


















Solves the problem of innerHTML rendering to real nodes

html = html.replace(/</g.'< ').replace(/>/g.'> ')
html = html.replace(/</g.'< ').replace(/>/g.'> ')
Copy the code

That’s the difference between innerHTML and innerText. InnerHTML does the encoding and the transformation, and the <> is rerendered as characters, and innerText is the character output

Although the first block of code does not have a newline, in fact, the space in the middle hides \n. So that’s why it’s important to use pre and code tags; normal divs and other tags filter out \n and consecutive Spaces.


It’s a span label. How do you do that?

After understanding the above content, look at the side of the color effect

The code block is as follows:

So how does the span control when to break a line and when not to break a line? You can’t do that with pure CSS. The answer is \n

So why is br invalid and n valid, and innerHTML

Highlight. Js is used in vue

This can be used in a variety of ways, using the HLJS API above. You can also use the vue feature (custom instructions) to accomplish this series of things

import Hljs from 'highlight.js'

let Highlight = {}
// Custom plug-in
Highlight.install = function(Vue) {
  // Customize the v-highlight directive
  Vue.directive('highlight', {
    // Called when the bound element is inserted into the parent node
    inserted: function(el) {
      Hljs.highlightBlock(el)
    },
    // Called after all vnodes and their children of the component where the directive resides have been updated
    componentUpdated: function(el) {
      Hljs.highlightBlock(el)
    }
  })
}

export default Highlight
Copy the code

Remember to register the command with Vue after writing it:

import Vue from 'Vue'
import Highlight from 'Directory corresponding to the above code'
Vue.use(Highlight)

// When using</code>Copy the code

Use js_Beautify with instructions

Combined with the above directive, directly encapsulate a, first format the code, in the highlighted code directive!

Cozily convenient I need not project, directly built an HTML, CDN to introduce the corresponding library to achieve a

Core points have been said above, of course, the code has a better way to implement and more expansion, the rest of the documentation ~

<! DOCTYPEhtml>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0" />
    <title>Document</title>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.0/beautify.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.0/beautify-css.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.0/beautify-html.min.js"></script>

    <script src="https://cdn.bootcdn.net/ajax/libs/highlight.js/11.0.1/highlight.min.js"></script>
    <link href="https://cdn.bootcss.com/highlight.js/9.12.0/styles/atom-one-dark.min.css" rel="stylesheet" />

    <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.9/vue.min.js"></script>
  </head>

  <body>
    <div id="app">
      <pre><code v-code class="language-html">
      <div><div>HTML formatting</div><div>The second line</div></div>
    </code></pre>
      <hr />
      <pre><code v-code class="language-css">body{background:red; width:100%; }</code></pre>
      <hr />
      <pre><code v-code class="language-javascript">var test = 'a'; function(){console.log('test',test)}</code></pre>
    </div>

    <script>
      let code = {}
      function getBeautifyCode(el) {
        if(! el || ! el.innerHTML)return ' '
        var code = el.innerHTML || ' '
        let className = el.classList ? el.classList.value || ' ' : ' '
        if (className.indexOf('html')! = = -1) {
          code = html_beautify(code)
            .replace(/</g.'< ')
            .replace(/>/g.'> ')}if (className.indexOf('css')! = = -1) {
          code = css_beautify(code)
        }
        if (className.indexOf('javascript')! = = -1) {
          code = js_beautify(code)
        }

        return code
      }

      code.install = function(Vue) {
        Vue.directive('code', {
          // Called when the bound element is inserted into the parent node
          inserted: function(el) {
            el.innerHTML = getBeautifyCode(el)
            hljs.highlightBlock(el)
          },
          // Called after all vnodes and their children of the component where the directive resides have been updated
          componentUpdated: function(el) {
            el.innerHTML = getBeautifyCode(el)
            hljs.highlightBlock(el)
          }
        })
      }

      Vue.use(code)

      new Vue({
        el: '#app'
      })
    </script>
  </body>
</html>
Copy the code

About the editor at the beginning of an article

After the append steps are complete, it is not possible to use this in the editor, because the editor and vue do not have a specific DOM node relationship (after the editor is loaded, the data on vue does not affect the editor content, only through the editor onchange synchronization data to vue).

So use the directive to generate a piece of HTML code, get the innerHtml rendered by V-Code, and insert it into the editor. Note that the editor also has to wrap the HTML code around the pre, because each rich text editor is different, so it is not easy to expand

The obtained code is reformatted in a messy format

If you have this editor requirement, perform the save operation (getContent) after making a series of changes. Get the changed HTML code, submit it to the interface, refresh the list, reassign the new data to the editor and find that js-Beautify doesn’t work? !

This is because in our format and code after highlighting code, has been around for a lot of Spaces and line breaks, actually these Spaces (or called the indentation) is what we don’t want to save, save the part of the indentation after next time js code formatting – beautify will think that this is deliberately left the enter/Spaces, cause a series of problems

So when we get the HTML code again, we do one thing:

html = html.replace(/[\r\n]/g.' ').replace(/>\s*? .'> <')
Copy the code

I’m just going to replace all the non-characters between the newline and the two Angle brackets