vue項目中用到了富文本編輯器,網上找了一些,以爲vue-quill-editor最好用,css
ui簡潔,功能也好配,夠用了,文檔很差讀,有些小細節須要本身注意,我懶得分析,就封裝成了組件html
你們用的時候直接cope組件,可是不要cope文章呀~~~vue
須要注意的是編輯器保存的格式,咱們在用div展現的時候,有些格式無效,因此我也一樣封裝了供頁面展現的組件npm
首先安裝包服務器
這是編輯器效果圖:編輯器
這是編輯器的組件代碼:ide
代碼比較多,我摺疊起來了工具
1 <template> 2 <div class="editor_wrap"> 3 <!-- 圖片上傳組件輔助--> 4 <el-upload 5 class="avatar-uploader" 6 :action="serverUrl" 7 name="image" 8 :headers="header" 9 multiple 10 :show-file-list="false" 11 :on-success="uploadSuccess" 12 :on-error="uploadError" 13 :before-upload="beforeUpload" 14 ></el-upload> 15 <quill-editor 16 v-loading="quillUpdateImg" 17 class="editor" 18 v-model="content" 19 ref="myQuillEditor" 20 :options="editorOption" 21 @blur="onEditorBlur($event)" 22 @focus="onEditorFocus($event)" 23 @change="onEditorChange($event)" 24 ></quill-editor> 25 </div> 26 </template> 27 <script> 28 import { quillEditor } from "vue-quill-editor"; 29 import "quill/dist/quill.core.css"; 30 import "quill/dist/quill.snow.css"; 31 import "quill/dist/quill.bubble.css"; 32 // 工具欄配置 33 const toolbarOptions = [ 34 ["bold", "italic", "underline", "strike"], // 加粗 斜體 下劃線 刪除線 35 ["blockquote", "code-block"], // 引用 代碼塊 36 // [{ header: 1 }, { header: 2 }], // 一、2 級標題 37 [{ list: "ordered" }, { list: "bullet" }], // 有序、無序列表 38 [{ script: "sub" }, { script: "super" }], // 上標/下標 39 [{ indent: "-1" }, { indent: "+1" }], // 縮進 2 40 [{ color: [ 41 '#ffffff', '#ffd7d5', '#ffdaa9', '#fffed5', '#d4fa00', '#73fcd6', '#a5c8ff', '#ffacd5', '#ff7faa', 42 '#d6d6d6', '#ffacaa', '#ffb995', '#fffb00', '#73fa79', '#00fcff', '#78acfe', '#d84fa9', '#ff4f79', 43 '#b2b2b2', '#d7aba9', '#ff6827', '#ffda51', '#00d100', '#00d5ff', '#0080ff', '#ac39ff', '#ff2941', 44 '#888888', '#7a4442', '#ff4c00', '#ffa900', '#3da742', '#3daad6', '#0052ff', '#7a4fd6', '#d92142', 45 '#000000', '#7b0c00', '#ff0000', '#d6a841', '#407600', '#007aaa', '#021eaa', '#797baa', '#ab1942' 46 ] }, { background: [ 47 '#ffffff', '#ffd7d5', '#ffdaa9', '#fffed5', '#d4fa00', '#73fcd6', '#a5c8ff', '#ffacd5', '#ff7faa', 48 '#d6d6d6', '#ffacaa', '#ffb995', '#fffb00', '#73fa79', '#00fcff', '#78acfe', '#d84fa9', '#ff4f79', 49 '#b2b2b2', '#d7aba9', '#ff6827', '#ffda51', '#00d100', '#00d5ff', '#0080ff', '#ac39ff', '#ff2941', 50 '#888888', '#7a4442', '#ff4c00', '#ffa900', '#3da742', '#3daad6', '#0052ff', '#7a4fd6', '#d92142', 51 '#000000', '#7b0c00', '#ff0000', '#d6a841', '#407600', '#007aaa', '#021eaa', '#797baa', '#ab1942' 52 ] }], // 字體顏色、字體背景顏色 53 [{ size: ["small", false, "large", "huge"] }], // 字體大小 2 54 [{ header: [1, 2, 3, 4, 5, 6, false] }], // 標題 55 [{ font: [] }], // 字體種類 2 56 [{'direction': 'rtl'}], // 文本方向 2 57 [{ align: [] }], // 對齊方式 2 58 ["clean"], // 清除文本格式 59 ["link", "image", "video"] // 連接、圖片、視頻 60 ]; 61 export default { 62 props: { 63 /*編輯器的內容*/ 64 value: null, 65 /*圖片大小*/ 66 maxSize: { 67 type: Number, 68 default: 4000 //kb 69 } 70 }, 71 72 components: { 73 quillEditor 74 }, 75 watch: { 76 value(val) { 77 this.content = this.value 78 } 79 }, 80 81 data() { 82 return { 83 content: this.value, 84 quillUpdateImg: false, // 根據圖片上傳狀態來肯定是否顯示loading動畫,剛開始是false,不顯示 85 editorOption: { 86 theme: "snow", // or 'bubble' 87 placeholder: "您想說點什麼?", 88 modules: { 89 toolbar: { 90 container: toolbarOptions, 91 handlers: { 92 image: function(value) { 93 if (value) { 94 // 觸發input框選擇圖片文件 95 document.querySelector(".avatar-uploader input").click(); 96 } else { 97 this.quill.format("image", false); 98 } 99 }, 100 // link: function(value) { 101 // if (value) { 102 // var href = prompt('請輸入url'); 103 // this.quill.format("link", href); 104 // } else { 105 // this.quill.format("link", false); 106 // } 107 // }, 108 } 109 } 110 } 111 }, 112 serverUrl: process.env.VUE_APP_API_URL + "config/upload", // 這裏寫你要上傳的圖片服務器地址 113 header: { 114 token: localStorage.getItem("token") 115 } 116 }; 117 }, 118 119 methods: { 120 onEditorBlur() { 121 //失去焦點事件 122 }, 123 onEditorFocus() { 124 //得到焦點事件 125 }, 126 onEditorChange({ editor, html, text }) { 127 this.content = html; 128 //內容改變事件 129 this.$emit("textareaData", this.content); 130 }, 131 132 // 富文本圖片上傳前 133 beforeUpload() { 134 // 顯示loading動畫 135 this.quillUpdateImg = true; 136 }, 137 138 uploadSuccess(res, file) { 139 // res爲圖片服務器返回的數據 140 // 獲取富文本組件實例 141 let quill = this.$refs.myQuillEditor.quill; 142 // 若是上傳成功 143 if (res.error == 0) { 144 // 獲取光標所在位置 145 let length = quill.getSelection().index; 146 // 插入圖片 res.url爲服務器返回的圖片地址 147 quill.insertEmbed(length, "image", res.info.img_url); 148 // 調整光標到最後 149 quill.setSelection(length + 1); 150 } else { 151 this.$message.error("圖片插入失敗"); 152 } 153 // loading動畫消失 154 this.quillUpdateImg = false; 155 }, 156 // 富文本圖片上傳失敗 157 uploadError() { 158 // loading動畫消失 159 this.quillUpdateImg = false; 160 this.$message.error("圖片插入失敗"); 161 } 162 } 163 }; 164 </script> 165 166 <style scoped> 167 .editor_wrap /deep/ .avatar-uploader { 168 display: none; 169 } 170 .editor_wrap /deep/ .editor { 171 line-height: normal !important; 172 height: 270px; 173 margin-bottom: 60px; 174 } 175 .editor_wrap /deep/ .editor .ql-bubble .ql-editor a { 176 color: #136ec2; 177 } 178 .editor_wrap /deep/ .editor img { 179 max-width: 720px; 180 margin:10px; 181 } 182 .editor_wrap /deep/ .ql-snow .ql-color-picker .ql-picker-options { 183 padding: 3px 5px; 184 width: 192px; 185 } 186 .editor_wrap /deep/ .ql-snow .ql-tooltip[data-mode="link"]::before { 187 content: "請輸入連接地址:"; 188 } 189 .editor_wrap /deep/ .ql-snow .ql-tooltip.ql-editing a.ql-action::after { 190 border-right: 0px; 191 content: "保存"; 192 padding-right: 0px; 193 } 194 195 .editor_wrap /deep/ .ql-snow .ql-tooltip[data-mode="video"]::before { 196 content: "請輸入視頻地址:"; 197 } 198 199 .editor_wrap /deep/ .ql-snow .ql-picker.ql-size .ql-picker-label::before, 200 .editor_wrap /deep/ .ql-snow .ql-picker.ql-size .ql-picker-item::before { 201 content: "14px"; 202 } 203 .editor_wrap /deep/ .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"]::before, 204 .editor_wrap /deep/ .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before { 205 content: "10px"; 206 } 207 .editor_wrap /deep/ .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before, 208 .editor_wrap /deep/ .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before { 209 content: "18px"; 210 } 211 .editor_wrap /deep/ .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before, 212 .editor_wrap /deep/ .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before { 213 content: "32px"; 214 } 215 216 .editor_wrap /deep/ .ql-snow .ql-picker.ql-header .ql-picker-label::before, 217 .editor_wrap /deep/ .ql-snow .ql-picker.ql-header .ql-picker-item::before { 218 content: "文本"; 219 } 220 .editor_wrap /deep/ .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before, 221 .editor_wrap /deep/ .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before { 222 content: "標題1"; 223 } 224 .editor_wrap /deep/ .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before, 225 .editor_wrap /deep/ .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before { 226 content: "標題2"; 227 } 228 .editor_wrap /deep/ .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before, 229 .editor_wrap /deep/ .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before { 230 content: "標題3"; 231 } 232 .editor_wrap /deep/ .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before, 233 .editor_wrap /deep/ .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before { 234 content: "標題4"; 235 } 236 .editor_wrap /deep/ .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before, 237 .editor_wrap /deep/ .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before { 238 content: "標題5"; 239 } 240 .editor_wrap /deep/ .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before, 241 .editor_wrap /deep/ .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before { 242 content: "標題6"; 243 } 244 245 .editor_wrap /deep/ .ql-snow .ql-picker.ql-font .ql-picker-label::before, 246 .editor_wrap /deep/ .ql-snow .ql-picker.ql-font .ql-picker-item::before { 247 content: "標準字體"; 248 } 249 .editor_wrap /deep/ .ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"]::before, 250 .editor_wrap /deep/ .ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before { 251 content: "襯線字體"; 252 } 253 .editor_wrap /deep/ .ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"]::before, 254 .editor_wrap /deep/ .ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before { 255 content: "等寬字體"; 256 } 257 </style>
這是供頁面展現的效果圖:字體
這是供頁面展現的組件代碼:動畫
代碼比較多,一樣我摺疊起來了
1 <template> 2 <div class="editor_wrap"> 3 <quill-editor 4 class="editor" 5 v-model="content" 6 ref="myQuillEditor" 7 :options="editorOption" 8 @focus="onEditorFocus($event)" 9 ></quill-editor> 10 </div> 11 </template> 12 <script> 13 // 工具欄配置 14 const toolbarOptions = []; 15 16 import { quillEditor } from "vue-quill-editor"; 17 import "quill/dist/quill.core.css"; 18 import "quill/dist/quill.snow.css"; 19 import "quill/dist/quill.bubble.css"; 20 21 export default { 22 props: { 23 /*編輯器的內容*/ 24 value: null 25 }, 26 components: { 27 quillEditor 28 }, 29 watch: { 30 value(val) { 31 this.content = this.value; 32 } 33 }, 34 computed: { 35 editor() { 36 return this.$refs.myQuillEditor.quill; 37 } 38 }, 39 data() { 40 return { 41 content: this.value, 42 editorOption: { 43 theme: "bubble", // or 'bubble' 44 placeholder: "您想說點什麼?", 45 modules: { 46 toolbar: { 47 container: toolbarOptions, 48 handlers: {} 49 } 50 } 51 } 52 }; 53 }, 54 methods: { 55 onEditorFocus(editor) { 56 // 富文本得到焦點時的事件 57 editor.enable(false); // 在獲取焦點的時候禁用 58 } 59 } 60 }; 61 </script> 62 63 <style scoped> 64 .editor_wrap /deep/ .editor img { 65 max-width: 720px; 66 margin:10px; 67 } 68 .editor_wrap /deep/ .editor .ql-bubble .ql-editor a { 69 color: #136ec2; 70 } 71 </style>
值得注意的是頁面展現的時候,會有一個鼠標光標出現,目前我沒有處理,歡迎大神們留言指導