1.挑個富文本編輯器
首先針對自己專案的型別,確定自己要用啥編輯器,
1.1 wangeditor
如果一般類似博客這種專案不需要花里胡哨的,功能也不要求賊多的,推薦一下wangeditor(點擊跳轉),能覆寫基本上所有的常見操作,輕量化,開源,有中文檔案,
▽wangeditor效果圖

1.2 tinyMCE
如果需要復雜的編輯器,推薦tinyMCE(點擊跳轉),同樣也非常簡單和優雅,但是檔案是英文的,配合chrome的翻譯,基本上能看懂,而且tinyMCE有另外一個好處,word上的東西基本上都可以保存格式復制到編輯器里,可以比較方便的轉移,
▽tinyMCE效果圖

剩下的很多編輯器,但是大多沒接觸過,推薦的這兩個,一個簡潔夠用,一個功能齊全,能覆寫90%以上的場景了,所以就不推薦別的了,另外本文主要講wangeditor,
2.專案準備(wangeditor)
本文選用框架的是nuxt.js,和vue-cli基本一致,都0202年了,如果不是模塊化的專案請參考下wangeditor的檔案,
既然談到模塊化專案,那么將編輯器設為組件那就是非常必要的了,
但是有一個問題,vue自帶的資料雙向系結是不支持組件內外之間的雙向傳遞的(其實支持的,就是我不知道),也就是說,如果你將富文本編輯器封裝在組件B中,你在A頁面用組件B去寫入資料C,這個C資料只能在B的組件頁面中獲取,無法直接在A頁面中取到,但是專案邏輯不可能在組件的B頁面上去執行,一定是在A頁面去完成邏輯,所以一定要在A中獲取到資料,
為了解決這個問題,我們需要回顧一下vue的v-model和父子組件的傳值方式,如果你了解組件資料的雙向系結和它的原理,可以忽略下面,直接到最后的代碼處就行了,
2.1 v-model
這個很基礎了,就簡單放個例子好了,
1 <input type="text" v-model="message"> 2 <p>{{message}}</p>
這個例子其實等價于
1 <input type="text" :value="message" @input="message = $event.target.value">
挺好理解的,① v-bind:"message" 等于給input賦值,② @input="message = $event.target.value" 等于給message賦值,所以這樣才實作了雙向系結,也就是修改message時會觸發v-bind讓Input變換值,在Input輸入時能觸發input事件來改變message的值,
2.2實作組件v-model
那現在我搞一個組件,給他設上v-bind ,然后順便監聽他的input,這兩步可以化為一步v-model="price",也可以看非組件時候的"② @input="message = $event.target.value" 等于給message賦值,",因為監聽了input會將資料賦給price,然后通過v-bind會將price的值賦給組件內部的props中的value屬性,
1 <div id="app"> 2 <price-input :value="price" @input="onInput"></price-input> 3 </div>
1 var app = new Vue({ 2 el: '#app', 3 data(){ 4 price: '' 5 }, 6 methods: { 7 onInput(val){ 8 this.price = val; 9 } 10 } 11 })
我們現在已經完成第二步,現在只需要完成第一步就行了,第一步體現在組件上就是接收第二步傳進來的資訊,然后通過$emit再將它傳出去,即完成了組件上的資料雙向系結,組件內部代碼如下:
1 Vue.component('custom-input',{ 2 template: `<input :https://www.cnblogs.com/wangzirui98/p/value='value' @input='updateVal($event.target.value)' type='text'></input>`, 3 props: ['value'], 4 methods: { 5 updateVal(val){ 6 this.$emit('input', val); 7 } 8 } 9 });
ps:現在$emit('input',val)中的input方法是指組件外的@input="oninput"而不是指組件內部的@input='updateVal($event.target.value)'
2.3 model
但是現在還有一個問題,默認情況下,組件上的 v-model 會把 value 用作 prop 且把 input 用作 event,所以當我們在一個自定義組件上使用v-model并不能實作雙向系結,因為自定的組件并沒有默認的value和input事件,在使用時,我們需要按照上面那樣顯式的去宣告定義這些東西,這時,model選項就派上用場了,在定義組件的時候,指定prop的值和監聽的事件,
1 Vue.component('my-input',{
template: `<input type="text" :value=https://www.cnblogs.com/wangzirui98/p/"uname" @input="updateVal($event.target.value)">`, 2 props: { 3 // 如果你想在組件上使用v-model的話,此處的uname應該叫value 4 uname: { 5 type: String, 6 default: 'tom' 7 } 8 }, 9 methods: { 10 updateVal(val){ 11 // 如果你想在組件上使用v-model的話,此處的changeXXX應該叫input 12 this.$emit('changeXXX',val) 13 } 14 } 15 })
1 <my-input v-model="name" value='https://www.cnblogs.com/wangzirui98/p/some value'></my-input>
△ 在這種情況下,v-model的系結是失效的,所以只能改成拆解寫法:
1 <my-input :uname='name' @changeXXX='val => {foo = val}' value='https://www.cnblogs.com/wangzirui98/p/some value'></my-input>
要想使用v-model這時候只能在vue.component的引數物件里加一個Model物件,指出你想要value叫uname, input叫changeXXX,然后快樂的使用v-model就可以了,代碼如下:
1 Vue.component('my-input',{ 2 model: { 3 prop: 'uname', 4 event: 'changeXXX' 5 }, 6 props: { 7 uname: { 8 type: String, 9 default: 'tom' 10 } 11 }, 12 methods: { 13 updateVal(val){ 14 this.$emit('changeXXX',val) 15 } 16 } 17 })
這樣v-model 就可以生效了,另外如果你用v-model的話,event的名字沒有什么特殊要求,你填什么都可以,
3.實戰
3.1 安裝和匯入
直接npm安裝, $ npm install wangeditor
安裝好了在components/public下新建editor.vue檔案下匯入檔案,如果直接require會出現navigator is not defined 的錯誤,搜了一下可能是因為nuxt.js服務端渲染的問題,那時候還沒有navigator這個物件,所以導致出現這個錯誤,所以參考時要加個判斷, const E = process.browser ? require("wangeditor") : undefined;
3.2 專案代碼
代碼整體如下:
1 <template lang="html"> 2 <div > 3 <div ref="toolbar" ></div> 4 <div ref="editor" ></div> 5 </div> 6 </template> 7 8 <script> 9 // import E from "wangeditor"; 10 const E = process.browser ? require("wangeditor") : undefined; 11 export default { 12 data() { 13 return { 14 // uploadPath, 15 editor: null, 16 info_: null 17 }; 18 }, 19 model: { 20 prop: "value", 21 event: "change" 22 }, 23 props: { 24 value: { 25 type: String, 26 default: "" 27 }, 28 isClear: { 29 type: Boolean, 30 default: false 31 } 32 }, 33 watch: { 34 isClear(val) { 35 // 觸發清除文本域內容 36 if (val) { 37 this.editor.txt.clear(); 38 this.info_ = null; 39 } 40 }, 41 value: function(value) { 42 if (value !== this.editor.txt.html()) { 43 this.editor.txt.html(this.value); 44 } 45 } 46 }, 47 mounted() { 48 this.seteditor(); 49 this.editor.txt.html(this.value); 50 }, 51 methods: { 52 seteditor() { 53 // http://192.168.2.125:8080/admin/storage/create 54 this.editor = new E(this.$refs.toolbar, this.$refs.editor); 55 this.editor.customConfig.uploadImgShowBase64 = true; // base 64 存盤圖片 56 // this.editor.customConfig.uploadImgServer = 57 // ""; // 配置服務器端地址 58 // this.editor.customConfig.uploadImgHeaders = {}; // 自定義 header 59 // this.editor.customConfig.uploadFileName = "file"; // 后端接受上傳檔案的引數名 60 // this.editor.customConfig.uploadImgMaxSize = 2 * 1024 * 1024; // 將圖片大小限制為 2M 61 // this.editor.customConfig.uploadImgMaxLength = 6; // 限制一次最多上傳 3 張圖片 62 // this.editor.customConfig.uploadImgTimeout = 3 * 60 * 1000; // 設定超時時間 63 64 // 配置選單 65 this.editor.customConfig.menus = [ 66 "head", // 標題 67 "bold", // 粗體 68 "fontSize", // 字號 69 "fontName", // 字體 70 "italic", // 斜體 71 "underline", // 下劃線 72 "strikeThrough", // 洗掉線 73 "foreColor", // 文字顏色 74 "backColor", // 背景顏色 75 "link", // 插入鏈接 76 "list", // 串列 77 "justify", // 對齊方式 78 "quote", // 參考 79 "emoticon", // 表情 80 "image", // 插入圖片 81 "table", // 表格 82 "video", // 插入視頻 83 "code", // 插入代碼 84 "undo", // 撤銷 85 "redo", // 重復 86 "fullscreen" // 全屏 87 ]; 88 89 this.editor.customConfig.uploadImgHooks = { 90 fail: (xhr, editor, result) => { 91 // 插入圖片失敗回呼 92 }, 93 success: (xhr, editor, result) => { 94 // 圖片上傳成功回呼 95 }, 96 timeout: (xhr, editor) => { 97 // 網路超時的回呼 98 }, 99 error: (xhr, editor) => { 100 // 圖片上傳錯誤的回呼 101 }, 102 customInsert: (insertImg, result, editor) => { 103 // 圖片上傳成功,插入圖片的回呼 104 } 105 }; 106 this.editor.customConfig.onchange = html => { 107 this.info_ = html; // 系結當前逐漸地值 108 this.$emit("change", this.info_); // 將內容同步到父組件中 109 }; 110 // 創建富文本編輯器 111 this.editor.create(); 112 } 113 } 114 }; 115 </script> 116 117 <style lang="css"> 118 .editor { 119 width: 100%; 120 margin: 0 auto; 121 position: relative; 122 z-index: 0; 123 } 124 .toolbar { 125 border: 1px solid #ccc; 126 } 127 .text { 128 border: 1px solid #ccc; 129 min-height: 500px; 130 } 131 </style>
頁面代碼 :
1 <template> 2 <div> 3 <editor-bar 4 v-model="detail" 5 :isClear="isClear" 6 @change="change" 7 ></editor-bar> 8 9 <button @click="send">點我!</button> 10 </div> 11 </template> 12 <script> 13 import EditorBar from "../components/public/editor"; 14 15 export default { 16 components: { EditorBar }, 17 data() { 18 return { 19 isClear: false, 20 detail: "" 21 }; 22 }, 23 methods: { 24 change(val) { 25 console.log(val); 26 }, 27 send() { 28 alert(this.detail); 29 } 30 } 31 }; 32 </script> 33 34 <style></style>
直接復制就可以用了,更多功能可以參考檔案(點我!),
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/153821.html
標籤:JavaScript
上一篇:依賴注入、遞回組件的用法
下一篇:Vue開發環境跨域訪問
