SoFunction
Updated on 2025-04-09

VueJS Integration Medium Editor Sample Code (Custom Editor Button)

0x00 Preface

There are also a lot of integrations with rich text editors in the VueJS community, but after a little research, it is basically quill,medium-editor. Because I used medium-editor before using AngularJS, and I need to customize certain buttons, and it is best to select pop-ups, so I decided to use medium-editor.

This is the one with more stars in the community:vue-medium-editor, but when I opened its official website, I looked at the document, the more I read it, the more awkward it became. Let’s see how it is used:

<!--  -->
<medium-editor :text='myText' :options='options' custom-tag='h2' v-on:edit='applyTextEdit'>

gosh, pass so many parameters, I just want a simple editor

Open the source code and see it, it's 62 lines, so I decided to do it yourself and do it simple.

0x01 The simplest version

The simplest version is actually just instantiating the medium-editor in the vue component.

&lt;template&gt;
 &lt;div class="textEditor" @input="handleInput"&gt;
 &lt;/div&gt;
&lt;/template&gt;
&lt;script&gt;
/* eslint-disable no-new */
import MediumEditor from 'medium-editor'
export default {
 props: {
  value: String,
  options: {
   type: Object,
   default: () =&gt; ({})
  }
 },
 data () {
  return {
   editor: null // Used to store editor  }
 },
 watch: {
  // refer: /FranzSkuffka/vue-medium-editor/blob/master/
  value (newVal, oldVal) {
   if (newVal !== this.$) { // Use $ to solve the problem of v-html's cursor jumping to the beginning of the line    this.$ = newVal || ''
   }
  }
 },
 methods: {
  handleInput (e) {
   this.$emit('input', )
  }
 },
 mounted () {
  // Handle the initial value  this.$ = 
  // Of course you can customize options here   = new MediumEditor(this.$el, ({}, ))
  // The API of medium-editor, the listening content is changed  ('editableInput', )
 },
 beforeDestroy () {
  ('editableInput', )
  ()
 }
}
&lt;/script&gt;

Complete ~, isn't it very simple ~~ Haha, the simplest version is controlled by v-html, but there will be a problem of automatically jumping to the first line, so here is the final version, please read the comments for details

0x02 Usage

How to use it? It's very simple, in other components like this:

<text-editor v-model=""></text-editor>

Of course, you have to install the js and css of medium-editor first

0x03 Custom button

Here is the relevant code for the custom button used in my project, which is a buttonBuilder:

import MediumEditor from 'medium-editor'
import rangy from 'rangy/lib/'
import 'rangy/lib/rangy-classapplier'
import 'rangy/lib/rangy-highlighter'
import 'rangy/lib/rangy-selectionsaverestore'
import 'rangy/lib/rangy-textrange'
import 'rangy/lib/rangy-serializer'
const pHash = {
 p1: { name: 'p1', class: 'fs-36' },
 p2: { name: 'p2', class: 'fs-30' },
 p3: { name: 'p3', class: 'fs-24' },
 p4: { name: 'p4', class: 'fs-18' },
 p5: { name: 'p5', class: 'fs-14' },
 p6: { name: 'p6', class: 'fs-12' }
}
function pButtonCreator (p) {
 return ({
  name: ,
  init: function () {
    = (, {
    elementTagName: 'span',
    normalize: false
   })
    = ('button')
   ('medium-editor-action')
    = 
    = 
   (, 'click', (this))
  },
  getButton: function () {
   return 
  },
  clearFontSize: function () {
   ().forEach(function (el) {
    if (() === 'span' && ('class')) {
     ('class')
    }
   })
  },
  handleClick: function (event) {
   ()
   ()
   // Ensure the editor knows about an html change so watchers are notified
   // ie: <textarea> elements depend on the editableInput event to stay synchronized
   ()
  }
 })
}
export default {
 P1: pButtonCreator(pHash['p1']),
 P2: pButtonCreator(pHash['p2']),
 P3: pButtonCreator(pHash['p3']),
 P4: pButtonCreator(pHash['p4']),
 P5: pButtonCreator(pHash['p5']),
 P6: pButtonCreator(pHash['p6'])
}

Simply put, add some class to the selected text (the above is fs-xx, etc.), and you need to refer to a library rangy selected by the mouse. It is quite annoying. Then use it in text-editor like this:

Instantiate first

import ButtonBuilder from './buttonBuilder'
var editorOptions = {
 toolbar: {
  buttons: ['bold', 'italic', 'underline', 'removeFormat', 'p3', 'p4', 'p5', 'p6']
 },
 buttonLabels: 'fontawesome', // use font-awesome icons for other buttons
 extensions: {
  p3: new ButtonBuilder.P3(),
  p4: new ButtonBuilder.P4(),
  p5: new ButtonBuilder.P5(),
  p6: new ButtonBuilder.P6()
 },
 placeholder: false
}

Put it on editor

Copy the codeThe code is as follows:

= new MediumEditor(this.$el, ({}, editorOptions, ))

Of course, the above instantiation steps do not have to be written into this component. Configuration options can also be passed in from outside the component.

0x04 Details and pits

1. The custom implementation of v-model is used here. See the official documentation for details:v-model

Simply put, props: value , and this.$emit('input', model) can simulate v-model in the component.

2. Problem with custom button instances used by multiple editors. Since I have two next to <text-editor> when I apply myself, the above code will cause the two editor instances to use the same button instance, which will lead to a very serious problem: that is, edit the content of the following editor, and may modify the above editor! !

It is also very simple to solve this, modify this line:

Copy the codeThe code is as follows:

= new MediumEditor(this.$el, ({}, _.cloneDeep(editorOptions), ))

Copy the customized options deeper, here we use lodash functions.

The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.