js displays the formatted code and highlights it (code highlighting is implemented in vue)

Posted by CrimsonSoul on Sun, 23 Jan 2022 13:44:30 +0100


Implement a simple version of the web editor, without intelligent prompts, and will not automatically highlight labels (manual highlighting is required)

vue is used+ Highlight.js + js-beautify

The effect is shown in the figure below

js implementation code formatting

First, we will use the < pre > < / pre > and < code > < / code > tags to wrap the html code we want to show, because only in this way can they keep line feed / indentation, etc

The formatting code uses js-beautify

JS beauty provides three JSS for JS, CSS and html respectively. There is no need to introduce so many unnecessary contents at one time. For example, the effect I want to achieve only needs to introduce html

  • cdn mode:
<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>
  • npm mode
npm install js-beautify@next
import { js_beautify, css_beautify, html_beautify } from 'js-beautify'

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(
    '<div><div>html format</div><div>Second line</div></div>',
    {
      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>

There are many parameters of the configuration item. For details, you can configure the corresponding format by referring to the parameters provided by GitHub. Note that after the pre tag, there are no spaces and carriage returns, otherwise it will be rendered, and there must be a pre tag, otherwise the spaces indented in the code will not be rendered

Make complaints about html_ Beautiful, I feel that this api is a bit weak, 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 format</div>
  </div>
</div>

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

The same effect can be achieved, and one library is less introduced~

Implementation code highlighting

What's used is highlight.js

highlight.js Chinese network,highlight.js official website

introduce

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

// highlight.js code highlight instruction
import Hljs from "highlight.js";
import "highlight.js/styles/stackoverflow-light.css"; // Highlight the style of the code. Select more styles and import node_ modules/hightlight. Other css files in the JS / styles / directory

usage

On the corresponding code/pre label, mark 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>

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

hljs.highlightAll()

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

hljs.highlightBlock(document.querySelector('#html_code'))

More hljs Config and other APIs, you can turn to the document

highlight.js highlight code without newline

As shown in the figure below, JS beauty was used well just now, and there was no new line after highlighting

Some articles say it's the css problem of pre. In fact, studying the highlighted html has nothing to do with pre. If you don't write the pre tag, it really has something to do with it

Look at the correct demonstration:

How? Change innerText to innerHTML. Let's talk about it carefully

What is the difference between innerText and innerHTML

After rendering, the interface does look the same. Change the line feed and change the space of the space, but the internal html is very different.

  • The innerText method obviously replaces the < br > tag with a newline in the code block
  • The innerHtml method renders the html code

highlight.js highlights the dom node, and then changes the dom node to insert a tag to highlight it. Obviously, the < br > tag in the code is filtered (because you see a configuration of whether to use the < br > tag in the document, your br tag conflicts with him, which is pure speculation)

Solve the problem of rendering innerHTML as a real node

html = html.replace(/</g, '&lt;').replace(/>/g, '&gt;')
html = html.replace(/</g, '&lt;').replace(/>/g, '&gt;')

It is also the difference between innerHTML and innerText. InnerHTML will be re encoded and re rendered as characters, while innerText will output the characters as they are

Although there is no line break in the first code block, the space character in the middle is hidden. \ n. So this is why we emphasize the use of pre and code tags. Ordinary div or other tags will filter out \ N and continuous spaces.

After coloring, there are span tags. How do you wrap lines?

After understanding the above content, let's look at the coloring effect

The code block is as follows:

No matter how you look at it, these are all span tags. How does the span tag control when to wrap lines and when not to wrap lines? Pure css can't do it. The answer is still \ n

So I understand why br is invalid \ n is valid and why innerHTML should be used

Use highlight in vue js

There are many ways to use it. You can use the hljs api above. You can also use vue's features (custom instructions) to complete this series of things

import Hljs from 'highlight.js'

let Highlight = {}
// Custom plug-ins
Highlight.install = function(Vue) {
  // Custom directive v-highlight
  Vue.directive('highlight', {
    // Called when the bound element is inserted into the parent node
    inserted: function(el) {
      Hljs.highlightBlock(el)
    },
    // The VNode of the instruction component and its sub VNode are updated after all updates.
    componentUpdated: function(el) {
      Hljs.highlightBlock(el)
    }
  })
}

export default Highlight

After the instruction is written, remember to register with Vue:

import Vue from 'Vue'
import Highlight from 'The corresponding directory of the above code'
Vue.use(Highlight)

// When using
<code v-highlight>Write the code here</code>

Using JS with instructions_ beautify

Combined with the above instructions, directly encapsulate one, format the code first, and highlight the instructions of the code!

For convenience, I don't need a project. I directly built an html and introduced the corresponding library with cdn to realize one

The core points have also been mentioned above. Of course, the code has better implementation methods and more expansibility. The rest depends on the documents~

<!DOCTYPE html>
<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 format</div><div>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, '&lt;')
            .replace(/>/g, '&gt;')
        }
        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)
          },
          // The VNode of the instruction component and its sub VNode are updated after all updates.
          componentUpdated: function(el) {
            el.innerHTML = getBeautifyCode(el)
            hljs.highlightBlock(el)
          }
        })
      }

      Vue.use(code)

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

About the editor at the beginning of the article

After the appeal steps are completed, it cannot be used in the editor because there is no specific dom node relationship between the editor and vue (after the editor is loaded, the data on vue will not affect the content of the editor, and can only be synchronized to vue through onchange of the editor)

Therefore, first use the instructions to generate a section of html code, get the innerHtml rendered by v-code, and insert it into the editor. Note that the editor should also wrap the html code to be inserted with pre. Because each rich text editor is different, it is difficult to expand~

When the editor theme comes out, I'll talk about the rich text editor in detail

Topics: Front-end Vue highlight