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


Posted in Javascript onAugust 24, 2017

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'])
}

简单来说就是给选中的文字加一些 class (上面是 fs-xx 之类的),其中需要引一个鼠标选中的库 rangy,挺烦人的也是,然后在 text-editor 中这样用:

先实例化

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
}

再放到 editor 上

this.editor = new MediumEditor(this.$el, Object.assign({}, editorOptions, this.options))

当然上面实例化的步骤不一定要写到这个组件里面,配置 options 也可以从组件外传入

0x04 细节和坑

1、这里用到了 v-model 的自定义实现,详见官方文档:v-model

简单来说呢就是 props: value ,和 this.$emit('input', model) 就可以实现在组件中模拟 v-model 啦

2、多个 editor 使用的自定义button 实例的问题。由于我自己应用的时候有两个挨着的 <text-editor>,用的上面的代码会导致两个 editor 实例用的是同一个 button 实例,这会导致一个很严重的问题:即编辑下面编辑器的内容,可能会修改的上面的编辑器!!

要解决这个也很简单,修改这一行:

this.editor = new MediumEditor(this.$el, Object.assign({}, _.cloneDeep(editorOptions), this.options))

将自定义的 options 深复制一下,这里借助了 lodash 的函数。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
json 入门基础教程 推荐
Oct 31 Javascript
js 上传图片预览问题
Dec 06 Javascript
js控制滚动条缓慢滚动到顶部实现代码
Mar 20 Javascript
js 判断上传文件大小及格式代码
Nov 13 Javascript
用JavaScript来美化HTML的select标签的下拉列表效果
Nov 17 Javascript
BootStrap table表格插件自适应固定表头(超好用)
Aug 24 Javascript
jQuery 特性操作详解及实例代码
Sep 29 Javascript
vue自定义过滤器创建和使用方法详解
Nov 06 Javascript
express 项目分层实践详解
Dec 10 Javascript
javascript判断一个变量是数组还是对象
Apr 10 Javascript
element-plus一个vue3.xUI框架(element-ui的3.x 版初体验)
Dec 02 Vue.js
Vue 事件的$event参数=事件的值案例
Jan 29 Vue.js
JS实现电商放大镜效果
Aug 24 #Javascript
weui框架实现上传、预览和删除图片功能代码
Aug 24 #Javascript
jQuery Datatable 多个查询条件自定义提交事件(推荐)
Aug 24 #jQuery
详解webpack2+node+react+babel实现热加载(hmr)
Aug 24 #Javascript
Vue网页html转换PDF(最低兼容ie10)的思路详解
Aug 24 #Javascript
JS对象序列化成json数据和json数据转化为JS对象的代码
Aug 23 #Javascript
Angular 2 利用Router事件和Title实现动态页面标题的方法
Aug 23 #Javascript
You might like
openPNE常用方法分享
2011/11/29 PHP
dhtmlxTree目录树增加右键菜单以及拖拽排序的实现方法
2013/04/26 PHP
如何在smarty中增加类似foreach的功能自动加载数据
2013/06/26 PHP
限制ckeditor上传图片文件大小的方法
2013/11/15 PHP
CI(CodeIgniter)框架配置
2014/06/10 PHP
PHP实现获取域名的方法小结
2014/11/05 PHP
Yii框架获取当前controlle和action对应id的方法
2014/12/03 PHP
PHP基于GD2函数库实现验证码功能示例
2019/01/27 PHP
php遍历目录下文件并按修改时间排序操作示例
2019/07/12 PHP
Thinkphp页面跳转设置跳转等待时间的操作
2019/10/16 PHP
jquery动画4.升级版遮罩效果的图片走廊--带自动运行效果
2012/08/24 Javascript
如何书写高质量jQuery代码(使用jquery性能问题)
2014/06/30 Javascript
node.js中的buffer.fill方法使用说明
2014/12/14 Javascript
百度UEditor编辑器如何关闭抓取远程图片功能
2015/03/03 Javascript
javascript中attachEvent用法实例分析
2015/05/14 Javascript
javascript实现点击单选按钮链接转向对应网址的方法
2015/08/12 Javascript
浅谈Javascript中Object与Function对象
2015/09/26 Javascript
JavaScript实现的Tween算法及缓冲特效实例代码
2015/11/03 Javascript
jquery拖动层效果插件用法实例分析(附demo源码)
2016/04/28 Javascript
jQuery处理XML文件的几种方法
2016/06/14 Javascript
NodeJS实现不可逆加密与密码密文保存的方法
2018/03/16 NodeJs
如何从头实现一个node.js的koa框架
2019/06/17 Javascript
使用python实现strcmp函数功能示例
2014/03/25 Python
Python 比较两个数组的元素的异同方法
2017/08/17 Python
Python之ReportLab绘制条形码和二维码的实例
2018/01/15 Python
利用python绘制正态分布曲线
2021/01/04 Python
html5 css3 动态气泡按钮实例演示
2012/12/02 HTML / CSS
详解Html5中video标签那些属性和方法
2019/07/01 HTML / CSS
Html5获取高德地图定位天气的方法
2019/12/26 HTML / CSS
应届毕业生就业自荐信
2013/10/26 职场文书
和平主题的演讲稿
2014/01/12 职场文书
幼儿教育感言
2014/02/05 职场文书
团结演讲稿范文
2014/05/23 职场文书
单方离婚协议书范本(2014版)
2014/09/30 职场文书
农民工工资支付承诺书
2015/05/04 职场文书
CSS 实现角标效果的完整代码
2022/06/28 HTML / CSS