1.安裝
vue-quill-editor github地址:https://github.com/surmon-china/vue-quill-editor
官方文檔地址:https://www.npmjs.com/package/vue-quill-editor
基於Quill、適用於Vue2的富文本編輯器,支持服務端渲染和單頁應用
npm install vue-quill-editor --save
安裝圖片拖動和變化大小的插件,需要在vue.config.js引入webpack中配置 不配置會出錯,具體鏈接(https://github.com/kensnyder/quill-image-resize-module/issues/54)
plugins: [
new webpack.ProvidePlugin({
'window.Quill': 'quill/dist/quill.js',
'Quill': 'quill/dist/quill.js',
}),
]
2.局部引入
import Vue from 'vue'
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'
import { quillEditor } from 'vue-quill-editor'
import Quill from 'quill'
import { ImageDrop } from 'quill-image-drop-module' // 圖片拖動插件
import ImageResize from 'quill-image-resize-module' // 圖片設置大小插件
Quill.register('modules/imageDrop', ImageDrop) // 圖片拖動插件
Quill.register('modules/imageResize', ImageResize) // 圖片設置大小插件
// 鼠標移入顯示title文字
import { addQuillTitle } from '@/assets/quill-title.js'
Vue.use(quillEditor)
// 圖片上傳接口
import { richTextImgUpload } from '@/api/uploadFIle'
3.工具欄配置
// 工具欄配置
const toolbarOptions = [
['bold', 'italic', 'underline', 'strike'], // 加粗,斜體,下划線,刪除線
['blockquote', 'code-block'], // 引用,代碼塊
[{ header: 1 }, { header: 2 }], // 標題,鍵值對的形式;1、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'], // 清除字體樣式
['image', 'video'] // 上傳圖片、上傳視頻
]
/* 富文本編輯圖片上傳配置*/
const uploadConfig = {
action: '', // 必填參數 圖片上傳地址
methods: 'POST', // 必填參數 圖片上傳方式
token: '', // 可選參數 如果需要token驗證,假設你的token有存放在sessionStorage
name: 'img', // 必填參數 文件的參數名
size: 500, // 可選參數 圖片大小,單位為Kb, 1M = 1024Kb
accept: 'image/png, image/gif, image/jpeg, image/bmp, image/x-icon' // 可選 可上傳的圖片格式
}
4.data中初始化配置
data() {
return {
content: '',
videoOrimg:true,
editorOption: {
placeholder: '請輸入...',
modules: {
imageResize: {}, //圖片拖動設置大小
imageDrop: true, // 圖片拖動
toolbar: {
container: toolbarOptions, //工具欄
handlers: {
image: (value) => {
if (value) {
// 這是是為了獲取你當前點擊的那個富文本框
this.videoOrimg = true
document.querySelectorAll('.upload-demo input')[0].click()
} else {
this.quill.format('image', false)
}
},
video: (value) => {
if (value) {
// 這是是為了獲取你當前點擊的那個富文本框
this.videoOrimg = false
document.querySelectorAll('.upload-demo input')[0].click()
} else {
this.quill.format('image', false)
}
}
}
}
},
theme: 'snow'
}
}
},
5.模板中使用
<template>
<div>
<el-upload
class="upload-demo"
action="#"
name="file"
:http-request="requestUpload"
:before-upload="beforeAvatarUpload"
:on-success="handleSuccess"
multiple
/>
<quill-editor ref="toref" v-model="content" :options="editorOption" />
</div>
</template>
6.圖片上傳(視頻上傳同理)
因為是前后端分離的,富文本上傳圖片要單獨上傳,在content中替換為后端返回圖片地址。
methods: {
// 覆蓋默認的上傳行為
requestUpload(params) {
const formData = new FormData()
formData.append('img', params.file)
// 圖片
if(this.videoOrimg){
richTextImgUpload(formData).then((res) => {
params.onSuccess(res)
})
}else{
richTextVideoUpload(formData).then((res) => {
params.onSuccess(res)
})
}
},
// 判斷圖片后綴
beforeAvatarUpload(file) {
console.log(file,'dasda')
const isJPG = file.type === 'image/jpeg' || 'image/png'
const isVideo = file.type === 'video/mp4'
const isLt2M = file.size / 1024 / 1024 < 10
// 圖片
if(this.videoOrimg){
if (!isJPG) {
this.$message.error('上傳圖片只能是 JPG , PNG格式!')
}
if (!isLt2M) {
this.$message.error('上傳圖片大小不能超過 10MB!')
}
return isJPG && isLt2M
}else{
if(!isVideo){
this.$message.error('上傳視頻只能是 MP4格式!')
}
return isVideo
}
},
// 上傳成功
handleSuccess(res, file) {
if (res.error == 0) {
// 動態添加 ref 通過 eval () 去執行
const toeval = this.$refs.toref.quill
// eval() 函數可計算某個字符串,並執行其中的的 JavaScript 代碼。
// 獲取光標所在位置
const length = toeval.selection.savedRange.index
// 插入圖片,res為服務器返回的圖片鏈接地址
// 圖片
if(this.videoOrimg){
toeval.insertEmbed(
length,
'image',
process.env.VUE_APP_BASE_API_ORIGIN + res.data.imgscr
)
}else{
toeval.insertEmbed(
length,
'video',
process.env.VUE_APP_BASE_API_ORIGIN + res.data.imgscr
)
}
// 調整光標到最后
toeval.setSelection(length + 1)
}
},
// 將內容上傳給父組件
postContent() {
this.$emit('getContent', this.content)
},
},
7.quill-title.js內容
const titleConfig = {
'ql-bold':'加粗',
'ql-color':'顏色',
'ql-font':'字體',
'ql-code':'插入代碼',
'ql-italic':'斜體',
'ql-link':'添加鏈接',
'ql-background':'背景顏色',
'ql-size':'字體大小',
'ql-strike':'刪除線',
'ql-script':'上標/下標',
'ql-underline':'下划線',
'ql-blockquote':'引用',
'ql-header':'標題',
'ql-indent':'縮進',
'ql-list':'列表',
'ql-align':'文本對齊',
'ql-direction':'文本方向',
'ql-code-block':'代碼塊',
'ql-formula':'公式',
'ql-image':'圖片',
'ql-video':'視頻',
'ql-clean':'清除字體樣式'
};
export function addQuillTitle(){
const oToolBar = document.querySelector('.ql-toolbar'),
aButton = oToolBar.querySelectorAll('button'),
aSelect = oToolBar.querySelectorAll('select');
aButton.forEach(function(item){
if(item.className === 'ql-script'){
item.value === 'sub' ? item.title = '下標': item.title = '上標';
}else if(item.className === 'ql-indent'){
item.value === '+1' ? item.title ='向右縮進': item.title ='向左縮進';
}else{
item.title = titleConfig[item.classList[0]];
}
});
aSelect.forEach(function(item){
item.parentNode.title = titleConfig[item.classList[0]];
});
}
8.完整代碼
<template>
<div>
<el-upload
class="upload-demo"
action="#"
name="file"
:http-request="requestUpload"
:before-upload="beforeAvatarUpload"
:on-success="handleSuccess"
multiple
/>
<quill-editor ref="toref" v-model="content" :options="editorOption" />
</div>
</template>
<script>
import Vue from 'vue'
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'
import { quillEditor } from 'vue-quill-editor'
import Quill from 'quill'
import { ImageDrop } from 'quill-image-drop-module' // 圖片拖動插件
import ImageResize from 'quill-image-resize-module' // 圖片設置大小插件
Quill.register('modules/imageDrop', ImageDrop) // 圖片拖動插件
Quill.register('modules/imageResize', ImageResize) // 圖片設置大小插件
// 鼠標移入顯示title文字
import { addQuillTitle } from '@/assets/quill-title.js'
Vue.use(quillEditor)
// 圖片上傳接口
import { richTextImgUpload, richTextVideoUpload } from '@/api/uploadFIle'
// 工具欄配置
const toolbarOptions = [
['bold', 'italic', 'underline', 'strike'], // 加粗,斜體,下划線,刪除線
['blockquote', 'code-block'], // 引用,代碼塊
[{ header: 1 }, { header: 2 }], // 標題,鍵值對的形式;1、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'], // 清除字體樣式
['image', 'video'] // 上傳圖片、上傳視頻
]
/* 富文本編輯圖片上傳配置*/
const uploadConfig = {
action: '', // 必填參數 圖片上傳地址
methods: 'POST', // 必填參數 圖片上傳方式
token: '', // 可選參數 如果需要token驗證,假設你的token有存放在sessionStorage
name: 'img', // 必填參數 文件的參數名
size: 500, // 可選參數 圖片大小,單位為Kb, 1M = 1024Kb
accept: 'image/png, image/gif, image/jpeg, image/bmp, image/x-icon' // 可選 可上傳的圖片格式
}
export default {
components: {
quillEditor
},
props: {
contents:String,
default:''
},
data() {
return {
content: '',
videoOrimg:true,
editorOption: {
placeholder: '請輸入...',
modules: {
imageResize: {}, //圖片拖動設置大小
imageDrop: true, // 圖片拖動
toolbar: {
container: toolbarOptions, //工具欄
handlers: {
image: (value) => {
if (value) {
// 這是是為了獲取你當前點擊的那個富文本框
this.videoOrimg = true
document.querySelectorAll('.upload-demo input')[0].click()
} else {
this.quill.format('image', false)
}
},
video: (value) => {
if (value) {
// 這是是為了獲取你當前點擊的那個富文本框
this.videoOrimg = false
document.querySelectorAll('.upload-demo input')[0].click()
} else {
this.quill.format('image', false)
}
}
}
}
},
theme: 'snow'
}
}
},
mounted() {
addQuillTitle()
},
methods: {
// 覆蓋默認的上傳行為
requestUpload(params) {
const formData = new FormData()
formData.append('img', params.file)
// 圖片
if(this.videoOrimg){
richTextImgUpload(formData).then((res) => {
params.onSuccess(res)
})
}else{
richTextVideoUpload(formData).then((res) => {
params.onSuccess(res)
})
}
},
// 判斷圖片后綴
beforeAvatarUpload(file) {
console.log(file,'dasda')
const isJPG = file.type === 'image/jpeg' || 'image/png'
const isVideo = file.type === 'video/mp4'
const isLt2M = file.size / 1024 / 1024 < 10
// 圖片
if(this.videoOrimg){
if (!isJPG) {
this.$message.error('上傳圖片只能是 JPG , PNG格式!')
}
if (!isLt2M) {
this.$message.error('上傳圖片大小不能超過 10MB!')
}
return isJPG && isLt2M
}else{
if(!isVideo){
this.$message.error('上傳視頻只能是 MP4格式!')
}
return isVideo
}
},
// 上傳成功
handleSuccess(res, file) {
if (res.error == 0) {
// 動態添加 ref 通過 eval () 去執行
const toeval = this.$refs.toref.quill
// eval() 函數可計算某個字符串,並執行其中的的 JavaScript 代碼。
// 獲取光標所在位置
const length = toeval.selection.savedRange.index
// 插入圖片,res為服務器返回的圖片鏈接地址
// 圖片
if(this.videoOrimg){
toeval.insertEmbed(
length,
'image',
process.env.VUE_APP_BASE_API_ORIGIN + res.data.imgscr
)
}else{
toeval.insertEmbed(
length,
'video',
process.env.VUE_APP_BASE_API_ORIGIN + res.data.imgscr
)
}
// 調整光標到最后
toeval.setSelection(length + 1)
}
},
// 將內容上傳給父組件
postContent() {
this.$emit('getContent', this.content)
},
},
watch: {
contents:{
immediate: true, // 這句重要
handler (val) {
this.content = this.contents
}
}
}
}
</script>
<style scoped>
.upload-demo {
display: none;
}
</style>
9.預覽
