Blog address

The address of my personal blog is 👉👉

Open Source project address

This is my open source favorites url project address 👉👉Click to enter, can be directly set to the browser home page or desktop shortcut for use, I am using, long-term maintenance.

Completely open source, you can research, secondary development. Of course, you are still welcome to click Star⭐⭐⭐ 👉 ⭐ source link (gitee) Source link (github) source link (Github)

How to build a rich text editor for your blog?

  • Technology stack:vue2.x
  • Rich text editor:vue-quill-editor
  • UI framework:elementUI

Because the blog is a learning record website, so it is inevitable to use a text editor, I choose vue-quill-Editor this rich text editor, the following introduction to the use of the editor!

Use of the rich text editor vue-quill-Editor

1. Install vue-quill-Editor and its dependencies first

npm i vue-quill-editor --save
npm i quill --save
Copy the code

2. Since I’m using the entire editor as a component, I can use it internally

import "quill/dist/quill.core.css";
import "quill/dist/quill.snow.css";
import "quill/dist/quill.bubble.css";
// Invoke the rich text editor
import { quillEditor } from "vue-quill-editor";
Copy the code

3. Mount components

// Mount the text editor component
components: {
  quillEditor
},
Copy the code

4. Use the template

<quill-editor ref="myQuillEditor" @change="" v-model="" :options="editorOption">
</quill-editor>
Copy the code

5. Configure the rich text editor

data() {
  return {
    editorOption: {
      placeholder: "Please enter your content here.".modules: {
        toolbar: {
          container: [["bold"."italic"."underline"."strike"].// Bold, italic, underline, strikeout
            ["blockquote"."code-block"].// reference code block
            [{ header: 1 }, { header: 2}].// Title, in the form of key-value pairs; 1 and 2 indicate the font size
            [{ list: "ordered" }, { list: "bullet"}]./ / list
            [{ script: "sub" }, { script: "super"}]./ / the subscript
            [{ indent: "1" }, { indent: "+ 1"}]./ / the indentation
            [{ direction: "rtl"}].// Text direction
            / / [{size: [" small ", false, "large", "huge"]}], / / font size
            / / [{header: [1, 2, 3, 4, 5, 6, false]}], / / a few level title
            [{ color: []}, {background: []}],// Font color, font background color
            // [{font: []}], //
            [{ align: []}],// Alignment
            ["clean"].// Clear the font style
            ["link"."image"] // Upload pictures and videos],}}}}; },Copy the code

6. Add style to style

.quill-editor {
  width: 1000px;
  margin: 0auto; height: 150px; } .editor { line-height: normal ! important; height: 800px; } .ql-snow .ql-tooltip[data-mode='link']::before {
  content: 'Please enter link address :';
}
.ql-snow .ql-tooltip.ql-editing a.ql-action::after {
  border-right: 0px;
  content: 'save';
  padding-right: 0px;
}
.ql-snow .ql-tooltip[data-mode='video']::before {
  content: 'Please enter video address :';
}
.ql-snow .ql-picker.ql-size .ql-picker-label::before,
.ql-snow .ql-picker.ql-size .ql-picker-item::before {
  content: '14px';
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='small']::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='small']::before {
  content: '10px';
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='large']::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='large']::before {
  content: '18px';
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='huge']::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='huge']::before {
  content: '32px';
}
.ql-snow .ql-picker.ql-header .ql-picker-label::before,
.ql-snow .ql-picker.ql-header .ql-picker-item::before {
  content: 'text';
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='1']::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='1']::before {
  content: 'heading 1';
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='2']::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='2']::before {
  content: 'title 2';
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='3']::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='3']::before {
  content: 'title';
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='4']::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='4']::before {
  content: 'title 4';
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='5']::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='5']::before {
  content: 'title 5';
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='6']::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='6']::before {
  content: 'title 6';
}
Copy the code

7. Just like normal input fields, you can use v-Model to bind the text content. Here I submit the content using the change event, but you can use any event type you want.

We’re done here. Look at the results!

Vue-quill-editor echo and code block highlighting

Since we post a lot of code when we write articles, we have to echo back to the page and highlight the code to see them, otherwise the black and white text is a headache and we end up using plug-ins

A. Vue echo – quill – editor

We need to add divs to the page that we want to echo, and then use V-HTML to render the data. In particular, we need to add the qL-editor class name, otherwise it will not work


<div class="ql-editort" v-html=""></div>
Copy the code

Code block highlighting

1. First install PrismJS and its dependencies

/ / prismjs installation
npm i prismjs
// Install the prismJS compiler plug-in
npm i babel-plugin-prismjs -D
Copy the code

2. Locate babel.config.js under the project

Plugins in module.exports append the following configuration, which can be added manually if there are no plugins already

plugins: [
  [
    "prismjs",
    {
      languages: ["javascript"."css"."markup"].plugins: ["line-numbers"].// Configure the display line number plug-in
      theme: "okaidia".// The topic name
      css: true,}]].Copy the code

3. Introduce modules into components

// Introduce code beautification plugins
import Prism from "prismjs";
Copy the code

4. One of the tricky things is that the code structure generated by the text editor only has the Pre tag, and the code highlighting plugin only works with the Pre tag nested code tag. Some class names have to be written on the code tag, so we need to do a global substitution before we save it into the database. Class name line-numbers displays the line number language-xxx Select the programming language, here we select JS: language-js

// The code block generated by the rich text editor only has the pre tag, but no code tag, and the front-end echo needs the code tag, so it needs to be processed
let newContent = blogEditerContent.replace(
  /<pre class="ql-syntax" spellcheck="false">/g.'<pre class="ql-syntax line-numbers language-js" spellcheck="false"><code class="language-js">'
);
newContent = newContent.replace(/<\/pre>/g."</code></pre>");
Copy the code

Add PRISm.highlightall () to Mounted; But it didn’t work very well for me, so I used another method, custom plugins

// Introduce code beautification plugins
import Prism from "prismjs";
let Highlight = {};
// Custom plug-in
Highlight.install = function(Vue) {
  // Custom instruction v-highlight
  Vue.directive("highlight", {
    // call after the component's VNode and its child VNodes are all updated
    componentUpdated: function() {
      // Code beautificationPrism.highlightAll(); }}); };export default Highlight;
Copy the code

6. Reference custom plug-ins in main.js

// Introduce code block highlighting plugins
import Highlight from "./assets/js/Highlight";
Vue.use(Highlight);
Copy the code

7. Then add the command v-highlight to the div in the first step


<div class="ql-editor" v-html="" v-highlight></div>
Copy the code

So this is where we’re done and let’s see what happens

Vue-quill-editor implements image upload with elementUI

You can’t avoid uploading images when writing articles, but the editor is base64 encoded by default. This disadvantage is that when images are large, the parameters in the background are too long. It can cause submission failures and put a lot of pressure on the database if the amount of data is too large, so we use the image upload component of elementUI to upload the image to our own image space and return the URL to the database.

1. Add the Upload component action to the template to fill in the interface address of our upload server

<! -- elementUI upload image component --><el-upload class="avatar-uploader" 
  :action="serverUrl" 
  :show-file-list="false" 
  :on-success="handleAvatarSuccess" 
  :on-error="handleAvatarError" 
  :before-upload="beforeAvatarUpload">
</el-upload>
Copy the code

2. Add the Overwrite upload image method to the Toolbar

data() {
  return {
    editorOption: {
      modules: {
        toolbar: {
          // Rewrite the image upload event
          handlers: {
            'image': function (value) {
              if (value) {
                // Trigger the input box to select the image file
                document.querySelector('.avatar-uploader input').click()
              } else {
                this.quill.format('image'.false); }}}}}}}; },Copy the code

3. Verify and insert the upload success hook function of the Upload component

// Image upload success hook function
handleAvatarSuccess(res) {
  // res is the data returned by the image server
  // Get the rich text component instance
  let quill = this.$refs.myQuillEditor.quill
  // If the upload succeeds
  if(res.sinaPath ! = =null) {
    // Get the cursor position
    let length = quill.selection.savedRange.index;
    // Insert image res.info as the image address returned by the server
    quill.insertEmbed(length, 'image', res.sinaPath)
    // Adjust the cursor to the end
    quill.setSelection(length + 1)}else {
    this.$message.error('Failed to insert picture')}},Copy the code

4. In order to improve interactive experience, loading component is added in the picture uploading process


// Wrap quill-editor with el-row
<el-row v-loading="quillUpdateImg">
  <quill-editor ref="myQuillEditor" @change="submitBlogEditerContent" v-model="blogEditerContent" :options="editorOption">
  </quill-editor>
</el-row>

Copy the code

5. Add loading in the hook function before uploading an image. After the loading result is returned (whether it succeeds or fails), remove loading

// Upload the image before the hook function
beforeAvatarUpload(file) {
  // Display loading animation
  this.quillUpdateImg = true
},
// Failed to upload picture hook function
handleAvatarError() {
  // Loading animation disappears
  this.quillUpdateImg = false
  this.$message.error('Failed to insert picture')}// Image upload success hook function
handleAvatarSuccess(res) {
  // Loading animation disappears
  this.quillUpdateImg = false
},
Copy the code

That’s it. Upload an image and try it

Finally, thank you for your patience to watch, since we are here, click 👍 and then go

Links to integrate

🔊 Project preview address (GitHub Pages):👉👉alanhzw.github. IO

🔊 Project preview alternate address (own server):👉👉warbler.duwanyu.com

🔊 source code address (gitee):👉👉gitee.com/hzw_0174/wa…

🔊 source address (github):👉👉github.com/alanhzw/War…

🔊 My blog :👉👉www.duwanyu.com