從這裏進入官網. 能找到這個NB的編輯器是由於公司項目須要一個可視化的cms編輯器,相似微信公衆號編輯文章。能夠插入各類卡片,模塊,問題,圖片等等。而後插入的內容還須要能刪除,拖拽等等。因此採用vue開發,兼容vue併兼容拖拽的文本編輯器並很少,因此在github上一番搜索找到了quill這款文本編輯器神器。
先從官方例子裏面扒一個圖瞅瞅:
PS:和大多數文本編輯器長得都差很少,若是功能都同樣,那也不用介紹了。 他NB,強大的地方就是全部能看到的,不能看到的功能通通都是一個一個獨立的模塊。所有都是能夠替換的。不得不對這段文字進行重點標記。固然其餘編輯器的一些幾本功能也通通都有且不只如此。好比文本的樣式,多媒體文件的上傳,響應鍵盤事件,操做歷史,公式支持等等。點擊查看詳情. 各類自定義的使用說明
好比上圖中的菜單欄能夠自定義,對已有的菜單欄定義:繼續從官方例子裏面扒圖:
固然,若是插件自帶的功能沒有,好比你要作一個動畫在菜單欄上加一個圖標、選項或者什麼的。能夠對整個菜單欄進行定義和重寫
下面從項目中的擴展點找2個說明一下這個NB的編輯器,固然他的更多可擴展功能也沒有用上,因此只有看到的官方文檔,才能理解他的可擴展性和靈活性。css
自帶的字體大小編輯有2個以下。可是顯然不太能支持咱們的用法。一開始吧size擴展成了px。可是後來通過測試發現手機端使用的是rem,so。最後改爲使用rem。html
[{ 'size': ['small', false, 'large', 'huge'] }] [{ 'header': [1, 2, 3, 4, 5, 6, false] }], //擴展後的字體選擇 [{ // 'size': ['10px', '12px', '14px', '16px', '18px', '20px'] //1/75 *2 //1px =0.026rem //1rem=36px 'size': ['0.26rem', '0.31rem', '0.37rem', '0.41rem', '0.47rem', '0.52rem'] }]
爲了在菜單欄中顯示對應的字體大小。加入css。差很少長這樣,有多少個選項,就加多少個。前端
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="10px"]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="10px"]::before { content: '10px'; font-size: 10px; } .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="20px"]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="20px"]::before { content: '20px'; font-size: 20px; } //默認的樣式 .ql-snow .ql-picker.ql-size .ql-picker-label::before, .ql-snow .ql-picker.ql-size .ql-picker-item::before { content: '14px'; font-size: 14px; } //rem:須要說明一下,在編輯的時候仍是顯示px單位,但最終生成的源代碼使用rem,由於編輯是在pc上,而且運營人員也只熟悉px這個單位,對rem沒有概念。 .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="0.26rem"]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="0.26rem"]::before { content: '10px'; font-size: 10px; }
在而後在初始化quill的地方加上下面的js代碼vue
import Quill from 'quill' var Size = Quill.import('attributors/style/size'); // Size.whitelist = ['10px', '12px', '14px', '16px', '18px', '20px']; Size.whitelist = ['0.26rem', '0.31rem', '0.37rem', '0.41rem', '0.47rem', '0.52rem']; Quill.register(Size, true);
如此以後,對咱們字體大小的選擇就算擴展完畢了,讓咱們檢驗一下成果:
固然爲了在pc上rem字體能生效,還必須得加上一行。node
html { font-size: 36px; }
值得說明的是,樣式的設置等,幾本都有多套策略能夠選擇。舉個栗子,官方源代碼。
這是官方的字體方向設置的源代碼。咱們能夠看到他就有3種方式設置:經過attribute(algin:'right'),經過class(class='ql-align-right'),經過style(style='text-align:right');是否是很靈活,很強大,任君選擇有木有git
import Parchment from 'parchment'; let config = { scope: Parchment.Scope.BLOCK, whitelist: ['right', 'center', 'justify'] }; let AlignAttribute = new Parchment.Attributor.Attribute('align', 'align', config); let AlignClass = new Parchment.Attributor.Class('align', 'ql-align', config); let AlignStyle = new Parchment.Attributor.Style('align', 'text-align', config); export { AlignAttribute, AlignClass, AlignStyle };
那如何指定使用其餘的一種呢?像下面的代碼同樣,若是使用style。則使用 Quill.import('attributors/style/align');替換默認的,若是使用class:則使用 Quill.import('attributors/class/align');github
var Align = Quill.import('attributors/style/align'); Align.whitelist = ['right', 'center', 'justify']; Quill.register(Align, true);
檢驗一下成果:
瀏覽器
quill默認使用的是strong或者b標籤方式。其實這也是沒有問題的,可是架不住公司的"高級"前端對手機端的全部html標籤都reset了。全部的hx標籤,em,strong等語義標籤所有reset了。因此沒辦法只能使用style的方式來實現。微信
import Inline from '../blots/inline'; class Bold extends Inline { static create() { return super.create(); } static formats() { return true; } optimize() { super.optimize(); if (this.domNode.tagName !== this.statics.tagName[0]) { this.replaceWith(this.statics.blotName); } } } Bold.blotName = 'bold'; Bold.tagName = ['STRONG', 'B']; export default Bold;
import Quill from 'quill' let Parchment = Quill.import('parchment') class BoldStyleAttributor extends Parchment.Attributor.Style { value(domNode) { let value = super.value(domNode); return value; } add(node, value) { $(node).css('font-weight', 'bold'); return true; } remove(node) { $(node).css('font-weight', 'normal'); } } let BoldStyle = new BoldStyleAttributor('bold', 'font-weight', { scope: Parchment.Scope.INLINE, whitelist: [true, false] }); export default BoldStyle;`
初始化quill的地方加上下面的代碼
./NodeEditText/TextBold」或者「./NodeEditText/TextBold.js」就是上面幾行代碼的js文件路徑。app
import MyBold from './NodeEditText/TextBold' Quill.register("formats/bold", MyBold, true);
檢驗一下成果:
諸如文字的字體啦,斜體啦,都相似寫法。就不一一展開了。官方文檔雖然是英文的,可是耐着性子看,仍是能比較方便看懂的,
寫在最後:
可以快速的自定義這個組件的前提是須要懂他的設計思想,我也只是粗淺的瞭解使用了一下這個組件,就不作什麼總結了
回答一下 @48詹澤娟 的問題,集成到vue,大約是這樣子.
<template> <div id="quillWrapper"> <div ref="quillContainer" :id="$data.elmId" class="quill-container"></div> <button v-if="useSaveButton" class="save-button" @click="saveContent"> {{ buttonText ? buttonText : 'Save Content' }} </button> <div v-if="showPreview" ref="livePreview" class="ql-editor"></div> </div> </template> <script> import Quill from 'quill' import Parchment from 'parchment'; import MyBold from './NodeEditText/TextBold' import MyItalic from './NodeEditText/TextItalic' var defaultToolbar = [ ['bold', 'italic'], [{ 'color': [] }], [{ // 'size': ['10px', '12px', '14px', '16px', '18px', '20px'] //1/75 *2 //1px =0.026rem //1rem=36px 'size': ['0.26rem', '0.31rem', '0.37rem', '0.41rem', '0.47rem', '0.52rem'] }], [{ 'align': [] }], ['clean'], ]; export default { name: 'VueEditor', props: { editorContent: String, placeholder: String, buttonText: String, useSaveButton: { type: Boolean, default () { return true } }, showPreview: { type: Boolean, default () { return false } } }, data: function() { return { quill: null, editor: null, toolbar: defaultToolbar, elmId: 'quill-container' + (new Date()).getTime() } }, mounted: function() { const vm = this var Size = Quill.import('attributors/style/size'); // Size.whitelist = ['10px', '12px', '14px', '16px', '18px', '20px']; Size.whitelist = ['0.26rem', '0.31rem', '0.37rem', '0.41rem', '0.47rem', '0.52rem']; Quill.register(Size, true); var Align = Quill.import('attributors/style/align'); Align.whitelist = ['right', 'center', 'justify']; Quill.register(Align, true); // Quill.register(MyBold, true); Quill.register("formats/bold", MyBold, true); Quill.register("formats/italic", MyItalic, true); vm.quill = new Quill(vm.$refs.quillContainer, { modules: { toolbar: { 'container': this.toolbar, } }, placeholder: this.placeholder ? this.placeholder : '', theme: 'snow' }); vm.editor = $(this.$el).find('.ql-editor')[0]; vm.editor.innerHTML = this.editorContent; if (vm.$refs.livePreview !== undefined || false) { vm.quill.on('text-change', function() { vm.$refs.livePreview.innerHTML = vm.editor.innerHTML vm.$emit('editor-updated', vm.editor.innerHTML) }); } else { vm.quill.on('text-change', function() { vm.$emit('editor-updated', vm.editor.innerHTML) }); } var replaceReg = /<(\S*?) [^>]*>.*?<\/\1>|<.*?\/>/gm; $(vm.editor).on('paste', function(e) { var text = null; if (window.clipboardData && clipboardData.setData) { // IE text = window.clipboardData.getData('text'); } else { text = (e.originalEvent || e).clipboardData.getData('text/plain') || prompt('在這裏輸入文本'); } console.log(text); if (document.body.createTextRange) { if (document.selection) { textRange = document.selection.createRange(); } else if (window.getSelection) { sel = window.getSelection(); var range = sel.getRangeAt(0); // 建立臨時元素,使得TextRange能夠移動到正確的位置 var tempEl = document.createElement("span"); tempEl.innerHTML = "&#FEFF;"; range.deleteContents(); range.insertNode(tempEl); textRange = document.body.createTextRange(); textRange.moveToElementText(tempEl); tempEl.parentNode.removeChild(tempEl); } textRange.text = text; textRange.collapse(false); textRange.select(); } else { // Chrome之類瀏覽器 document.execCommand("insertText", false, text); } e.preventDefault(); console.log('paste:' + text); }); try { document.execCommand("AutoUrlDetect", false, false); } catch (e) {} }, watch: { editorContent: function() { if (this.editor.innerHTML != this.editorContent) { console.log('set inner html'); this.editor.innerHTML = this.editorContent; } } }, methods: { saveContent: function(value) { this.$emit('save-content', this.editor.innerHTML) } } } </script>