VueJS 集成 Medium Editor的示例代碼 (自定義編輯器按鈕)
0x00 前言
VueJS 社區(qū)里面關(guān)于富文本編輯器的集成也不少了,但是之前小調(diào)研了一下,基本上就是 quill,medium-editor,因?yàn)橹坝?AngularJS 用過 medium-editor,并且需要自定義某些按鈕,而且最好還是選中彈出式的,所以就決定用 medium-editor。
社區(qū)里面 star 較多的就是這個(gè)了:vue-medium-editor,但是打開它官網(wǎng),看了看文檔,越看越別扭,來看看它用法:
<!-- index.html --> <medium-editor :text='myText' :options='options' custom-tag='h2' v-on:edit='applyTextEdit'>
gosh,傳這么多參數(shù),我只想要一個(gè)簡單的 editor 啊
打開源碼一看,就 62 行,所以決定自己動(dòng)手來一個(gè)簡單點(diǎn)的
0x01 最簡版
最簡版,其實(shí)就在 vue 組件中實(shí)例化一下 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 的光標(biāo)跳到行首的問題
this.$el.innerHTML = newVal || ''
}
}
},
methods: {
handleInput (e) {
this.$emit('input', e.target.innerHTML)
}
},
mounted () {
// 處理初始值的情況
this.$el.innerHTML = this.value
// 這里當(dāng)然可以自定義 options 啦
this.editor = new MediumEditor(this.$el, Object.assign({}, this.options))
// medium-editor 的 api,監(jiān)聽內(nèi)容改變化
this.editor.subscribe('editableInput', this.handleInput)
},
beforeDestroy () {
this.editor.unsubscribe('editableInput', this.handleInput)
this.editor.destroy()
}
}
</script>
完成~,是不是很簡單~~哈哈,最簡版是一個(gè) v-html 控制的,但是會(huì)有自動(dòng)跳轉(zhuǎn)到首行的問題,所以這里是最終版,細(xì)節(jié)問題看注釋啦
0x02 用法
咋用呢?很簡單,在其他組件中這樣:
<text-editor v-model="vm.richText"></text-editor>
當(dāng)然 你首先得安裝 medium-editor的 js 和 css了
0x03 自定義 button
下面是我項(xiàng)目中用到的自定義 button 的相關(guān)代碼,是一個(gè) 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 之類的),其中需要引一個(gè)鼠標(biāo)選中的庫 rangy,挺煩人的也是,然后在 text-editor 中這樣用:
先實(shí)例化
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))
當(dāng)然上面實(shí)例化的步驟不一定要寫到這個(gè)組件里面,配置 options 也可以從組件外傳入
0x04 細(xì)節(jié)和坑
1、這里用到了 v-model 的自定義實(shí)現(xiàn),詳見官方文檔:v-model
簡單來說呢就是 props: value ,和 this.$emit('input', model) 就可以實(shí)現(xiàn)在組件中模擬 v-model 啦
2、多個(gè) editor 使用的自定義button 實(shí)例的問題。由于我自己應(yīng)用的時(shí)候有兩個(gè)挨著的 <text-editor>,用的上面的代碼會(huì)導(dǎo)致兩個(gè) editor 實(shí)例用的是同一個(gè) button 實(shí)例,這會(huì)導(dǎo)致一個(gè)很嚴(yán)重的問題:即編輯下面編輯器的內(nèi)容,可能會(huì)修改的上面的編輯器?。?br />
要解決這個(gè)也很簡單,修改這一行:
this.editor = new MediumEditor(this.$el, Object.assign({}, _.cloneDeep(editorOptions), this.options))
將自定義的 options 深復(fù)制一下,這里借助了 lodash 的函數(shù)。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- vue項(xiàng)目中應(yīng)用ueditor自定義上傳按鈕功能
- Vue寫一個(gè)簡單的倒計(jì)時(shí)按鈕功能
- vue實(shí)現(xiàn)驗(yàn)證碼按鈕倒計(jì)時(shí)功能
- vue 開發(fā)一個(gè)按鈕組件的示例代碼
- Vue.js 點(diǎn)擊按鈕顯示/隱藏內(nèi)容的實(shí)例代碼
- Vue.js表單標(biāo)簽中的單選按鈕、復(fù)選按鈕和下拉列表的取值問題
- 詳解vue + vuex + directives實(shí)現(xiàn)權(quán)限按鈕的思路
- Vue.js實(shí)現(xiàn)按鈕的動(dòng)態(tài)綁定效果及實(shí)現(xiàn)代碼
- vue組件中點(diǎn)擊按鈕后修改輸入框的狀態(tài)實(shí)例代碼
- 使用vue實(shí)現(xiàn)點(diǎn)擊按鈕滑出面板的實(shí)現(xiàn)代碼
- Vue波紋按鈕組件制作
相關(guān)文章
vue中watch的實(shí)際開發(fā)學(xué)習(xí)筆記
watch是Vue實(shí)例的一個(gè)屬性是用來響應(yīng)數(shù)據(jù)的變化,需要在數(shù)據(jù)變化時(shí)執(zhí)行異步或開銷較大的操作時(shí),這個(gè)方式是最有用的,下面這篇文章主要給大家介紹了關(guān)于vue中watch的實(shí)際開發(fā)筆記,需要的朋友可以參考下2022-11-11
vue使用腳手架vue-cli創(chuàng)建并引入自定義組件
這篇文章介紹了vue使用腳手架vue-cli創(chuàng)建并引入自定義組件的方法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-03-03
vue實(shí)現(xiàn)數(shù)字變換動(dòng)畫的示例代碼
本文主要介紹了vue實(shí)現(xiàn)數(shù)字變換動(dòng)畫的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04
vue項(xiàng)目實(shí)現(xiàn)圖片上傳功能
這篇文章主要為大家詳細(xì)介紹了vue項(xiàng)目實(shí)現(xiàn)圖片上傳功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-12-12
Vite中使用Ant?Design?Vue3.x框架教程示例
這篇文章主要為大家介紹了Vite中使用Ant?Design?Vue3.x框架教程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06
關(guān)于Element?table組件滾動(dòng)條不顯示的踩坑記錄
這篇文章主要介紹了關(guān)于Element?table組件滾動(dòng)條不顯示的踩坑記錄,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08

