安裝
npm install vue-quill-editor --save
引入
全局引用
// main.js
import VueQuillEditor from 'vue-quill-editor'
// require styles
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'
Vue.use(VueQuillEditor)
封裝組件
import Cookies from 'vue-cookies' // cookies用于存放token
import apis from '../http/apis/common/index' // 引入存放上傳圖片接口的路徑
let base = process.env.VUE_APP_BASE_URL + process.env.VUE_APP_MAPPING // 域名
let url = base + apis.upload.url // 上傳圖片接口
/* 富文本編輯圖片上傳配置 */
const uploadConfig = {
action: url, // 必填參數(shù) 圖片上傳地址
methods: 'POST', // 必填參數(shù) 圖片上傳方式
token: Cookies.get('token'), // 可選參數(shù) 如果需要token驗(yàn)證荧琼,假設(shè)你的token有存放在sessionStorage
name: 'file', // 必填參數(shù) 文件的參數(shù)名
size: 500, // 可選參數(shù) 圖片大小,單位為Kb, 1M = 1024Kb
accept: 'image/png, image/gif, image/jpeg, image/bmp, image/x-icon' // 可選 可上傳的圖片格式
}
// toolbar工具欄的工具選項(xiàng)(默認(rèn)展示全部)
const toolOptions = [
['bold', 'italic', 'underline', 'strike'],
['blockquote', 'code-block'],
[{ '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', 'video'],
// 自己添加編輯源碼方法
['sourceEditor']
// ['image']
]
const handlers = {
shadeBox: null,
// 添加編輯源碼方法
sourceEditor: function() {
const container = this.container;
const firstChild = container.nextElementSibling.firstChild;
// 在第一次點(diǎn)擊源碼編輯的時(shí)候懊悯,會(huì)在整個(gè)工具條上加一個(gè)div,層級(jí)比工具條高,再次點(diǎn)擊工具條任意位置沮翔,就會(huì)退出源碼編輯焰望∩б冢可以在下面cssText里面加個(gè)背景顏色看看效果。
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
}
},
image: function image() {
var self = this
var fileInput = this.container.querySelector('input.ql-image[type=file]')
if (fileInput === null) {
fileInput = document.createElement('input')
fileInput.setAttribute('type', 'file')
// 設(shè)置圖片參數(shù)名
if (uploadConfig.name) {
fileInput.setAttribute('name', uploadConfig.name)
}
// 可設(shè)置上傳圖片的格式
fileInput.setAttribute('accept', uploadConfig.accept)
fileInput.classList.add('ql-image')
// 監(jiān)聽選擇文件
fileInput.addEventListener('change', function() {
// 創(chuàng)建formData
var formData = new FormData()
formData.append(uploadConfig.name, fileInput.files[0])
formData.append('object', 'product')
// 如果需要token且存在token
if (uploadConfig.token) {
formData.append('token', uploadConfig.token)
}
// 圖片上傳
var xhr = new XMLHttpRequest()
xhr.open(uploadConfig.methods, uploadConfig.action, true)
// 上傳數(shù)據(jù)成功熊赖,會(huì)觸發(fā)
xhr.onload = function(e) {
if (xhr.status === 200) {
var res = JSON.parse(xhr.responseText)
let length = self.quill.getSelection(true).index
// 這里很重要来屠,你圖片上傳成功后,img的src需要在這里添加,res.data.path就是你服務(wù)器返回的圖片鏈接俱笛。
self.quill.insertEmbed(length, 'image', res.data.path)
self.quill.setSelection(length + 1)
}
fileInput.value = ''
}
// 開始上傳數(shù)據(jù)
xhr.upload.onloadstart = function(e) {
fileInput.value = ''
}
// 當(dāng)發(fā)生網(wǎng)絡(luò)異常的時(shí)候會(huì)觸發(fā)捆姜,如果上傳數(shù)據(jù)的過程還未結(jié)束
xhr.upload.onerror = function(e) {
}
// 上傳數(shù)據(jù)完成(成功或者失敗)時(shí)會(huì)觸發(fā)
xhr.upload.onloadend = function(e) {
// console.log('上傳結(jié)束')
}
xhr.send(formData)
})
this.container.appendChild(fileInput)
}
fileInput.click()
}
}
export default {
placeholder: '請(qǐng)輸入內(nèi)容',
theme: 'snow', // 主題
modules: {
toolbar: {
container: toolOptions, // 工具欄選項(xiàng)
handlers: handlers // 事件重寫
}
}
}
使用組件
<template>
<div>
<quill-editor class="quill-editor" v-model="editorInfo" :options="option">
</quill-editor>
</div>
</template>
<script>
// script
import quillConfig from '@/utils/quill-config'
data(){
return {
option:quillConfig,
}
}
// 根據(jù)后端需求要求轉(zhuǎn)換editor
// 傳參時(shí):encodeURI(editorInfo)
// 接受參數(shù)時(shí):decodeURI(res.data.editorInfo)
</script>
<style lang="scss">
// editor 源碼編輯按鈕
.ql-sourceEditor {
background: url("https://i.loli.net/2021/03/25/MC5puJHoaxjTbBz.jpg") no-repeat !important;
background-size: contain !important;
width: 18px !important;
height: 18px !important;
}
</style>
局部使用
<template>
<div>
<quill-editor ref="myTextEditor" v-model="editorInfo" :options="editorOption" style="height:500px;"></quill-editor>
</div>
</template>
<script>
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'
import { quillEditor } from 'vue-quill-editor'
export default {
data(){
return{
editorInfo: '',
editorOption: {
placeholder: '編輯文章內(nèi)容'
}
}
},
components: {
quillEditor
},
methods:{
onEditorChange({ editor, html, text }) {
this.editorInfo= html
}
}
}
</script>