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 相关文章推荐
JS array 数组详解
Mar 22 Javascript
JQuery,Extjs,YUI,Prototype,Dojo 等JS框架的区别和应用场景简述
Apr 15 Javascript
javascript数组去掉重复
May 12 Javascript
浅析Node在构建超媒体API中的作用
Jul 30 Javascript
JavaScript中的Math.sin()方法使用详解
Jun 15 Javascript
jQuery实现两款有动画功能的导航菜单代码
Sep 16 Javascript
jquery实现表格隔行换色效果
Nov 19 Javascript
javascript实现的猜数小游戏完整实例代码
May 10 Javascript
常用js,css文件统一加载方法(推荐) 并在加载之后调用回调函数
Sep 23 Javascript
原生js实现轮播图的示例代码
Feb 20 Javascript
layui的面包屑或者表单不显示的解决方法
Sep 05 Javascript
借助云开发实现小程序短信验证码的发送
Jan 06 Javascript
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
基于PHP Web开发MVC框架的Smarty使用说明
2013/04/19 PHP
php 批量替换html标签的实例代码
2013/11/26 PHP
通过curl模拟post和get方式提交的表单类
2014/04/23 PHP
php实现文本数据导入SQL SERVER
2015/05/17 PHP
Thinkphp实现自动验证和自动完成
2015/12/19 PHP
DWZ刷新dialog解决方法
2013/03/03 Javascript
js 文本滚动效果的实例代码
2013/08/17 Javascript
Node.js入门教程:在windows和Linux上安装配置Node.js图文教程
2014/08/14 Javascript
javascript等号运算符使用详解
2015/04/16 Javascript
BetterScroll 在移动端滚动场景的应用
2017/09/18 Javascript
如何解决vue2.0下IE浏览器白屏问题
2018/09/13 Javascript
详解React 的几种条件渲染以及选择
2018/10/23 Javascript
利用layer实现表单完美验证的方法
2019/09/26 Javascript
JavaScript数组及常见操作方法小结
2019/11/13 Javascript
JS document对象简单用法完整示例
2020/01/14 Javascript
js实现页面图片消除效果
2020/03/24 Javascript
微信小程序 wx:for 与 wx:for-items 与 wx:key的正确用法
2020/05/19 Javascript
JavaScript实现图片合成下载的示例
2020/11/19 Javascript
python备份文件的脚本
2008/08/11 Python
python list语法学习(带例子)
2013/11/01 Python
Python程序设计入门(5)类的使用简介
2014/06/16 Python
python通过exifread模块获得图片exif信息的方法
2015/03/16 Python
Python lxml模块安装教程
2015/06/02 Python
详解Python判定IP地址合法性的三种方法
2018/03/06 Python
python 使用值来排序一个字典的方法
2018/11/16 Python
使用Pycharm(Python工具)新建项目及创建Python文件的教程
2020/04/26 Python
Python定时任务框架APScheduler原理及常用代码
2020/10/05 Python
英国家庭珠宝商:T. H. Baker
2018/02/08 全球购物
小学生自我评价范例
2013/09/24 职场文书
水产养殖学应届生求职信
2013/09/29 职场文书
大学生应聘推荐信范文
2013/11/19 职场文书
运动会跳远广播稿
2014/02/04 职场文书
个人校本研修方案
2014/05/26 职场文书
五四青年节比赛演讲稿
2015/03/18 职场文书
美丽人生观后感
2015/06/03 职场文书
Python实现的扫码工具居然这么好用!
2021/06/07 Python