關(guān)于寫此文的目的:
第一次接觸富文本編輯器街夭,尤其是react-quill這種,百度不到的各種坑,踩了無數(shù)的坑終于搞明白了捎泻。
1.安裝
npm i react-quill --save
需要用到emjo的話還需要npm i quillEmoji --save
安裝完之后頁面引進(jìn)
import ReactQuill, { Quill } from 'react-quill';
import 'react-quill/dist/quill.snow.css';
import quillEmoji from 'quill-emoji';
import "quill-emoji/dist/quill-emoji.css"; //這個不引入的話會出現(xiàn)emoji框一直在輸入框下面的情況
import { ImageDrop } from './plugin/quill-image-drop-module'; //講圖片拖進(jìn)文本框,可以直接安裝quill-image-drop-module诡曙;但由于我的webpack版本過低臀叙,無法兼容es6,所以把插件拿出來了
//注冊ToolbarEmoji价卤,將在工具欄出現(xiàn)emoji劝萤;注冊TextAreaEmoji,將在文本輸入框處出現(xiàn)emoji慎璧。VideoBlot是我自定義的視頻組件床嫌,后面會講,
const { EmojiBlot, ShortNameEmoji, ToolbarEmoji, TextAreaEmoji } = quillEmoji;
Quill.register({
'formats/emoji': EmojiBlot,
'formats/video': VideoBlot,
'modules/emoji-shortname': ShortNameEmoji,
'modules/emoji-toolbar': ToolbarEmoji,
'modules/emoji-textarea': TextAreaEmoji,
// 'modules/ImageExtend': ImageExtend, //拖拽圖片擴(kuò)展組件
'modules/ImageDrop': ImageDrop, //復(fù)制粘貼組件
}, true);
next胸私。
初始化富文本實例厌处,我寫在constructor里,module也是寫在這里邊
constructor(props) { super(props); this.reactQuillRef = null; }
富文本組件react-quill參數(shù)
<ReactQuill
ref={(el) => { this.reactQuillRef = el }}
defaultValue={postRichText}
key="1"
id="textDiv1" theme="snow" modules={this.modules} />
工具欄modules的定義基本屬性如下:
this.modules = {
toolbar: {
container: [
[{ 'size': ['small', false, 'large', 'huge'] }], //字體設(shè)置
// [{ 'header': [1, 2, 3, 4, 5, 6, false] }], //標(biāo)題字號岁疼,不能設(shè)置單個字大小
['bold', 'italic', 'underline', 'strike'],
[{ 'list': 'ordered' }, { 'list': 'bullet' }, { 'indent': '-1' }, { 'indent': '+1' }],
['link', 'image'], // a鏈接和圖片的顯示
[{ 'align': [] }],
[{
'background': ['rgb( 0, 0, 0)', 'rgb(230, 0, 0)', 'rgb(255, 153, 0)',
'rgb(255, 255, 0)', 'rgb( 0, 138, 0)', 'rgb( 0, 102, 204)',
'rgb(153, 51, 255)', 'rgb(255, 255, 255)', 'rgb(250, 204, 204)',
'rgb(255, 235, 204)', 'rgb(255, 255, 204)', 'rgb(204, 232, 204)',
'rgb(204, 224, 245)', 'rgb(235, 214, 255)', 'rgb(187, 187, 187)',
'rgb(240, 102, 102)', 'rgb(255, 194, 102)', 'rgb(255, 255, 102)',
'rgb(102, 185, 102)', 'rgb(102, 163, 224)', 'rgb(194, 133, 255)',
'rgb(136, 136, 136)', 'rgb(161, 0, 0)', 'rgb(178, 107, 0)',
'rgb(178, 178, 0)', 'rgb( 0, 97, 0)', 'rgb( 0, 71, 178)',
'rgb(107, 36, 178)', 'rgb( 68, 68, 68)', 'rgb( 92, 0, 0)',
'rgb(102, 61, 0)', 'rgb(102, 102, 0)', 'rgb( 0, 55, 0)',
'rgb( 0, 41, 102)', 'rgb( 61, 20, 10)']
}],
[{
'color': ['rgb( 0, 0, 0)', 'rgb(230, 0, 0)', 'rgb(255, 153, 0)',
'rgb(255, 255, 0)', 'rgb( 0, 138, 0)', 'rgb( 0, 102, 204)',
'rgb(153, 51, 255)', 'rgb(255, 255, 255)', 'rgb(250, 204, 204)',
'rgb(255, 235, 204)', 'rgb(255, 255, 204)', 'rgb(204, 232, 204)',
'rgb(204, 224, 245)', 'rgb(235, 214, 255)', 'rgb(187, 187, 187)',
'rgb(240, 102, 102)', 'rgb(255, 194, 102)', 'rgb(255, 255, 102)',
'rgb(102, 185, 102)', 'rgb(102, 163, 224)', 'rgb(194, 133, 255)',
'rgb(136, 136, 136)', 'rgb(161, 0, 0)', 'rgb(178, 107, 0)',
'rgb(178, 178, 0)', 'rgb( 0, 97, 0)', 'rgb( 0, 71, 178)',
'rgb(107, 36, 178)', 'rgb( 68, 68, 68)', 'rgb( 92, 0, 0)',
'rgb(102, 61, 0)', 'rgb(102, 102, 0)', 'rgb( 0, 55, 0)',
'rgb( 0, 41, 102)', 'rgb( 61, 20, 10)']
}],
['clean'], //清空
['emoji'], //emoji表情阔涉,設(shè)置了才能顯示
['video2'], //我自定義的視頻圖標(biāo),和插件提供的不一樣捷绒,所以設(shè)置為video2
],
handlers: {
'image': this.imageHandler.bind(this), //點擊圖片標(biāo)志會調(diào)用的方法
'video2': this.showVideoModal.bind(this),
},
},
// ImageExtend: {
// loading: true,
// name: 'img',
// action: RES_URL + "connector?isRelativePath=true",
// response: res => FILE_URL + res.info.url
// },
ImageDrop: true,
'emoji-toolbar': true, //是否展示出來
"emoji-textarea": false, //我不需要emoji展示在文本框所以設(shè)置為false
"emoji-shortname": true,
}
想要的最終效果如下圖:
到這一步洒敏,界面是能正常顯示了,但功能不完善疙驾,next
3.功能的開發(fā)
1.上傳本地圖片到服務(wù)器凶伙,代碼如下:
//這是點擊圖片圖標(biāo)觸發(fā)的事件
imageHandler() {
const input = document.createElement('input')
input.setAttribute('type', 'file')
input.setAttribute('accept', 'image/*')
input.setAttribute('multiple', 'multiple')
input.click()
const that = this;
input.onchange = async () => {
Array.from(input.files).forEach(item => {
//業(yè)務(wù)需求安裝了壓縮圖片的插件,可忽略
new Compressor(item, {
quality: 0.8,
convertSize: 1024 * 1024 * 8,
success(result) {
//很很很很重要的一步
const formData = new FormData();
formData.append('file', result, result.name);
Axios({
method: 'post',
data: formData,
url: config.RES_URL + 'connector?isRelativePath=true'它碎,//圖片上傳的接口
}).then(res => {
if (res.data.success) {
let quill = that.reactQuillRef.getEditor();//獲取到編輯器本身
const cursorPosition = quill.getSelection().index;//獲取當(dāng)前光標(biāo)位置
const link = config.RES_URL + res.data.info.url;
quill.insertEmbed(cursorPosition, "image", link);//插入圖片
quill.setSelection(cursorPosition + 1);//光標(biāo)位置加1
}
})
},
});
})
}
}
到這里已經(jīng)能實現(xiàn)本地圖片上傳到服務(wù)器的需求了
2.視頻自定義
//上傳視頻處理
addVideoItem = (img, url) => {
let quill = this.reactQuillRef.getEditor();//獲取到編輯器本身
let cursorPosition = quill.selection.savedRange.index
quill.insertEmbed(cursorPosition, 'Video', {
url,
controls: 'controls',
poster: img,
width: '100%',
controlslist: 'nodownload noremoteplayback',
oncontextmenu: 'return false'
})
// 光標(biāo)不加1的話視頻刪不掉
quill.setSelection(cursorPosition + 1);//光標(biāo)位置加1
this.setState({
upVideoShow: false
})
}
這段代碼功能實現(xiàn)的前提是函荣,我剛開始引入的自定義視頻組件,創(chuàng)建視頻標(biāo)簽扳肛,代碼如下:
const Quill = require('quill');
const BlockEmbed = Quill.import('blots/block/embed')
export class VideoBlot extends BlockEmbed {
static create(value) {
let node = super.create()
node.setAttribute('src', value.url)
node.setAttribute('controls', value.controls)
node.setAttribute('width', value.width)
node.setAttribute('poster', value.poster)
node.setAttribute('controlslist', 'nodownload noremoteplayback')
node.setAttribute('oncontextmenu', 'return false')
return node;
}
// 富文本初始化取參數(shù)傻挂,如果有編輯富文本的功能的話,這段代碼就需要加上
static value(node) {
return {
url: node.getAttribute('src'),
controls: node.getAttribute('controls'),
width: node.getAttribute('width'),
poster: node.getAttribute('poster'),
controlslist: node.getAttribute('controlslist'),
oncontextmenu: node.getAttribute('oncontextmenu')
};
}
}
VideoBlot.blotName = 'Video';
VideoBlot.tagName = 'video';
VideoBlot.className = 'ql-video';
完結(jié)
踩坑無數(shù)搞了兩個星期才弄的明明白白挖息,隔了一個月再來寫當(dāng)初怎么艱難開始的也都忘了金拒,寫不出來什么了。如有遇到什么問題歡迎留言