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