首页 > 语言 > JavaScript > 正文

VueJS 集成 Medium Editor的示例代码 (自定义编辑器按钮)

2024-05-06 15:12:25
字体:
来源:转载
供稿:网友

0x00 前言

VueJS 社区里面关于富文本编辑器的集成也不少了,但是之前小调研了一下,基本上就是 quill,medium-editor,因为之前用 AngularJS 用过 medium-editor,并且需要自定义某些按钮,而且最好还是选中弹出式的,所以就决定用 medium-editor。

社区里面 star 较多的就是这个了:vue-medium-editor,但是打开它官网,看了看文档,越看越别扭,来看看它用法:

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

gosh,传这么多参数,我只想要一个简单的 editor 啊

打开源码一看,就 62 行,所以决定自己动手来一个简单点的

0x01 最简版

最简版,其实就在 vue 组件中实例化一下 medium-editor 就可以了

<template> <div class="textEditor" @input="handleInput"> </div></template><script>/* eslint-disable no-new */import MediumEditor from 'medium-editor'export default { props: {  value: String,  options: {   type: Object,   default: () => ({})  } }, data () {  return {   editor: null // 用来存放 editor   } }, watch: {  // refer: https://github.com/FranzSkuffka/vue-medium-editor/blob/master/index.js  value (newVal, oldVal) {   if (newVal !== this.$el.innerHTML) { // 用 $el.innerHTML 来解决 v-html 的光标跳到行首的问题    this.$el.innerHTML = newVal || ''   }  } }, methods: {  handleInput (e) {   this.$emit('input', e.target.innerHTML)  } }, mounted () {  // 处理初始值的情况  this.$el.innerHTML = this.value  // 这里当然可以自定义 options 啦  this.editor = new MediumEditor(this.$el, Object.assign({}, this.options))  // medium-editor 的 api,监听内容改变化  this.editor.subscribe('editableInput', this.handleInput) }, beforeDestroy () {  this.editor.unsubscribe('editableInput', this.handleInput)  this.editor.destroy() }}</script>

完成~,是不是很简单~~哈哈,最简版是一个 v-html 控制的,但是会有自动跳转到首行的问题,所以这里是最终版,细节问题看注释啦

0x02 用法

咋用呢?很简单,在其他组件中这样:

<text-editor v-model="vm.richText"></text-editor>

当然 你首先得安装 medium-editor的 js 和 css了

0x03 自定义 button

下面是我项目中用到的自定义 button 的相关代码,是一个 buttonBuilder:

import MediumEditor from 'medium-editor'import rangy from 'rangy/lib/rangy-core.js'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 MediumEditor.Extension.extend({  name: p.name,  init: function () {   this.classApplier = rangy.createClassApplier(p.class, {    elementTagName: 'span',    normalize: false   })   this.button = this.document.createElement('button')   this.button.classList.add('medium-editor-action')   this.button.innerHTML = p.name   this.button.title = p.class   this.on(this.button, 'click', this.handleClick.bind(this))  },  getButton: function () {   return this.button  },  clearFontSize: function () {   MediumEditor.selection.getSelectedElements(this.document).forEach(function (el) {    if (el.nodeName.toLowerCase() === 'span' && el.hasAttribute('class')) {     el.removeAttribute('class')    }   })  },  handleClick: function (event) {   this.clearFontSize()   this.classApplier.toggleSelection()   // Ensure the editor knows about an html change so watchers are notified   // ie: <textarea> elements depend on the editableInput event to stay synchronized   this.base.checkContentChanged()  } })}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'])}            
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

图片精选