集百家之長,看了不少博客再結合自身狀況,寫了這個小組件功能,僅供參考。 原博客地址: https://finget.github.io/2019...
vue-quill-editor的配置文件:javascript
// toolbar工具欄的工具選項(默認展現所有) const toolOptions = [ // 加粗 斜體 下劃線 刪除線 ['bold', 'italic', 'underline', 'strike'], // 加粗 斜體 下劃線 刪除線 ['blockquote', 'code-block'], // 一、2 級標題 [{header: 1}, {header: 2}], // 有序、無序列表 [{list: 'ordered'}, {list: 'bullet'}], // 上標/下標 [{script: 'sub'}, {script: 'super'}], // 縮進 [{indent: '-1'}, {indent: '+1'}], // 文本方向 [{direction: 'rtl'}], // 字體大小 [{size: ['small', false, 'large', 'huge']}], // 標題 [{header: [1, 2, 3, 4, 5, 6, false]}], // 字體顏色、字體背景顏色 [{color: []}, {background: []}], // 字體種類 [{font: []}], // 對齊方式 [{align: []}], [{clean: '源碼編輯'}], // 這是本身加的 // 連接、圖片、視頻 ['link', 'image'], // 新添加的工具 ['sourceEditor'] ]; const handlers = { shadeBox: null, // 添加工具方法 sourceEditor: function () { // alert('我新添加的工具方法'); const container = this.container; const firstChild = container.nextElementSibling.firstChild; // 在第一次點擊源碼編輯的時候,會在整個工具條上加一個div,層級比工具條高,再次點擊工具條任意位置,就會退出源碼編輯。能夠在下面cssText裏面加個背景顏色看看效果。 if (!this.shadeBox) { let shadeBox = this.shadeBox = document.createElement('div'); shadeBox.style.cssText = 'position:absolute; top:0; left:0; width:100%; height:100%; cursor:pointer'; container.style.position = 'relative'; container.appendChild(shadeBox); firstChild.innerText = firstChild.innerHTML; shadeBox.addEventListener('click', function () { this.style.display = 'none'; firstChild.innerHTML = firstChild.innerText.trim(); }, false); } else { this.shadeBox.style.display = 'block'; firstChild.innerText = firstChild.innerHTML; } } }; export default { placeholder: '', // 主題 theme: 'snow', modules: { toolbar: { // 工具欄選項 container: toolOptions, // 事件重寫 handlers: handlers } }, // 在使用的頁面中初始化按鈕樣式 initButton: function () { // 樣式隨便改 const sourceEditorButton = document.querySelector('.ql-sourceEditor'); sourceEditorButton.style.cssText = 'font-size:18px'; // 加了elementui的icon sourceEditorButton.classList.add('el-icon-edit-outline'); // 鼠標放上去顯示的提示文字 sourceEditorButton.title = '源碼編輯'; } };
工具名,工具方法名,類名:
這裏要注意的是:工具名和工具方法名是同樣的,而且生成的button
工具擁有ql-
工具名的類名。
例如上面代碼中,個人工具名是sourceEditor
,個人方法名也是sourceEditor
,而生成的button
工具的類名就是ql-sourceEditor
了。
vue-quill-editor
自帶的上傳,是把圖片變成了base64的格式,不符合通常的項目需求。我猜它是用的FileReader
的API。css
有興趣的能夠試試這個,拖拽圖片轉base64預覽:html
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <style media="screen"> #div1 {width:400px; height:300px; background:#CCC; border:1px solid black; text-align:center; line-height:300px;} </style> <script> window.onload=function (){ let oDiv=document.getElementById('div1'); let oImg=document.getElementById('img1'); oDiv.addEventListener('dragenter', function (){ oDiv.innerHTML='請鬆手'; }, false); oDiv.addEventListener('dragleave', function (){ oDiv.innerHTML='拖到這裏上傳'; }, false); oDiv.addEventListener('dragover', function (ev){ ev.preventDefault(); }, false); oDiv.addEventListener('drop', function (ev){ ev.preventDefault(); // let oFile=ev.dataTransfer.files[0]; //讀取 let reader=new FileReader(); reader.readAsDataURL(oFile); reader.onload=function (){ //alert('成功'); oImg.src=this.result; }; reader.onerror=function (){ alert('讀取失敗了'); }; console.log(reader); }, false); } </script> </head> <body> <div id="div1">拖到這裏上傳</div> <img src="" id="img1"> </body> </html>
// 自定義vue-quill-editor的主要文件 <template> <div v-loading="imageLoading" element-loading-text="請稍等,圖片上傳中" > <quill-editor ref="myTextEditor" v-model="content" :options="quillOption" @change="onEditorChange($event)" @focus="onEditorFocus($event)" @ready="onEditorReady($event)" > </quill-editor> // 這個是elementui的上傳,把它display:none <el-upload style="display:none;" :class="name" :action="upload" :show-file-list="false" :on-success="handleAvatarSuccess" :before-upload="beforeAvatarUpload" :on-progress="onProgress" > </el-upload> </div> </template> <script> import { quillEditor } from 'vue-quill-editor'; import { upload } from '@/api/upload_api.js'; import Quill from 'quill'; import quillConfig from './quill_config.js'; import 'quill/dist/quill.core.css'; import 'quill/dist/quill.snow.css'; import 'quill/dist/quill.bubble.css'; export default { props: { // 富文本內容 value: String, // 富文本的名字 同一個頁面的多個富文本name不能重複的 name: String, // 圖片類型 imgType: { type: Array, default: () => ['image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/bmp'] }, // 圖片限制大小 單位 M limitSize: { type: Number, default: 1 } }, components: { quillEditor }, mounted() { // quillConfig.initButton(); var vm = this; // 當點擊圖書上傳是,觸發elementui的upload點擊 var imgHandler = async function (image) { vm.addImgRange = vm.$refs.myTextEditor.quill.getSelection(); if (image) { document.querySelector(`.${vm.name} input`).click(); } }; vm.$refs.myTextEditor.quill.getModule('toolbar').addHandler('image', imgHandler); }, model: { props: 'content', // 必須的change事件否則是不會響應的 event: 'change' }, computed: { content: { get: function () { return this.value; }, set: function () {} } }, data() { return { // 配置文件 quillOption: quillConfig, imageLoading: false, upload: upload(), }; }, methods: { onEditorChange(e) { this.$emit('change', e.html); }, onEditorFocus(e) { this.$emit('focus', e); }, onEditorReady(e) { this.$emit('ready', e); }, // 圖片上傳成功 handleAvatarSuccess(res) { // console.log(res, file); if (res.code == 200) { // this.form.custom_logo_url = res.data.url; let url = res.data.url, vm = this; if (url !== null && url.length > 0) { var value = url; // ***主要的東西就是這裏:上傳成功回顯 vm.addImgRange = vm.$refs.myTextEditor.quill.getSelection(); value = value.indexOf('http') != -1 ? value : 'http:' + value; vm.$refs.myTextEditor.quill.insertEmbed(vm.addImgRange !== null ? vm.addImgRange.index : 0, 'image', value, Quill.sources.USER); } else { vm.$message.warning('圖片增長失敗'); } } else { this.$message.error(res.message); } this.imageLoading = false; }, // 圖片上傳前 beforeAvatarUpload(file) { let date = new Date().getTime(); let imgType = this.imgType; const fileType = file.type; const isLt1M = file.size / 1024 / 1024 < this.limitSize; const isAllowType = imgType.indexOf(fileType) != -1; // console.log(fileType); // const isPng = fileType == 'image/jpeg'; if (!isAllowType) { this.$message.error('請上傳符合文件格式的圖片!'); return false; } if (!isLt1M) { this.$message.error('上傳logo圖片大小不能超過 1MB!'); return false; } return isAllowType && isLt1M; }, onProgress() { this.imageLoading = true; } } }; </script>
// 使用方式 <quill-editor v-model="form.content" name="policy"/> // 作了雙向綁定的,也能夠本身監聽change事件
⚠️注意點:
把這段代碼放到你的頁面中就好了。前端
.ql-snow .ql-tooltip[data-mode=link]::before { content: "請輸入連接地址:" !important; } .ql-snow .ql-tooltip.ql-editing a.ql-action::after { border-right: 0px; content: '保存' !important; padding-right: 0px; } .ql-snow .ql-tooltip[data-mode=video]::before { content: "請輸入視頻地址:" !important; } .ql-snow .ql-picker.ql-size .ql-picker-label::before, .ql-snow .ql-picker.ql-size .ql-picker-item::before { content: '14px' !important; } .ql-snow .ql-picker.ql-size .ql-picker-label[data-value=small]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value=small]::before { content: '10px' !important; } .ql-snow .ql-picker.ql-size .ql-picker-label[data-value=large]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value=large]::before { content: '18px' !important; } .ql-snow .ql-picker.ql-size .ql-picker-label[data-value=huge]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value=huge]::before { content: '32px' !important; } .ql-snow .ql-picker.ql-header .ql-picker-label::before, .ql-snow .ql-picker.ql-header .ql-picker-item::before { content: '文本' !important; } .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before, .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before { content: '標題1' !important; } .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before, .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before { content: '標題2' !important; } .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before, .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before { content: '標題3' !important; } .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before, .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before { content: '標題4' !important; } .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before, .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before { content: '標題5' !important; } .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before, .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before { content: '標題6' !important; } .ql-snow .ql-picker.ql-font .ql-picker-label::before, .ql-snow .ql-picker.ql-font .ql-picker-item::before { content: '標準字體' !important; } .ql-snow .ql-picker.ql-font .ql-picker-label[data-value=serif]::before, .ql-snow .ql-picker.ql-font .ql-picker-item[data-value=serif]::before { content: '襯線字體' !important; } .ql-snow .ql-picker.ql-font .ql-picker-label[data-value=monospace]::before, .ql-snow .ql-picker.ql-font .ql-picker-item[data-value=monospace]::before { content: '等寬字體' !important; }
建立了一個前端學習交流羣,感興趣的朋友,一塊兒來嗨呀!
vue