ps:老早之前写了一个simditor富文本,但是在实际的使用中bug很多,故重新寻觅了新的富文本,使用效果有待考量,但是功能自己感觉比simditor要好很多,可以自定义的内容比较开放。
###效果图
###1.js文件 npm i quill 本文使用的版本是"quill": “^1.3.7”
import React, { Component } from 'react';
import Quill from "quill";
import $ from "jquery";
import config from '../../config.js';
import { Button, Upload } from 'antd';
require("quill/dist/quill.snow.css");
import styles from './QuillRichText.less';
import request from '../../utils/request';
import { getUid } from '../../utils/auth';
import moment from 'moment';
/**
* 取值 let goods_desc = $(".detailContainer").find(".simditor-body").html();
*/
let ossConfig;
class QuillRichText extends Component {
state = {
textContent:''
}
componentDidMount = () => {
this.initEditor();
};
//初始化编辑器
initEditor = () => {
let that = this;
// Add fonts to whitelist
/*----自定义字体 ----*/
//1.需先引入需要展示的字体样式 然后加入到字体白名单里
const Font = Quill.import('formats/font');
// We do not add Aref Ruqaa since it is the default
let fonts = [
'SimSun',
'SimHei',
'Microsoft-YaHei',
'KaiTi',
'FangSong',
'Arial',
'Times-New-Roman',
'monospace',
'serif',
'consolas'
];
Font.whitelist = fonts; //将字体加入到白名单
Quill.register(Font, true);
let toolbarOptions = [
['bold', 'italic', 'underline'], // toggled buttons
[{ 'list': 'bullet' }],
["link","image"], // custom button values
[{ 'size': ['small', false, 'large', 'huge'] }], // custom dropdown
[{ 'header': [1, 2, 3, 4, 5, 6, false] }],
[{ 'color': [] }, { 'background': [] }], // dropdown with defaults from theme
[{ 'font': fonts},'video']
];
// "SimSun","SimHei","Microsoft-YaHei","KaiTi","FangSong","Arial","Times New Roman","sans-serif"
let config = {
debug: 'info',
modules: {
toolbar: toolbarOptions
},
placeholder: '请输入内容...',
readOnly: false,
theme: 'snow'
};
this.editor = new Quill('#editor', config);// 初始化编辑器
Quill.debug("error");//只开启error提示 默认的console还是会打印 没有找到更好的解决办法
let toolbar = this.editor.getModule('toolbar');
// console.log(this.props)
this.editor.container.firstChild.innerHTML = this.props.value; //赋值富文本 此处用于父组件传值给子组件quill(主要用于编辑页面,只做添加页面此处可忽略)
//点击quill的上传图片转接到oss上传的图标上
toolbar.addHandler('image', () => {
$('.editUpload .ant-upload').click()
});
};
//富文本图片上传至oss上
beforeGoodsUpload=(file)=> {
let files = [];
this.setState({
fileList: [...files]
})
return false;
}
//图片oss上传 此处大致讲解 不明白的看我之前发布的关于oss上传的文章
uploadGoodsPic(index,file){
const UID = getUid();
const isJPG = file.file.type === 'image/jpeg';
const isPNG = file.file.type === 'image/png';
const isLt2M = file.file.size / 1024 / 1024 < 5;
if (!isJPG && !isPNG) {
message.error('只能上传jpg|png|jpeg');
return;
}else{
if (!isLt2M) {
message.error('图片尺寸必须小于 5MB!');
return;
}
}
let param_first = {
uid:UID
};
/**** oss上传****/
request(`*********`, { //获取oss上传所需的参数接口 后端提供
method: 'POST',
headers: config.headers,
body:config.parseJson(param_first)
}).then((res) => {
ossConfig = {
policy:res.data.policy,
OSSAccessKeyId:res.data.accessid,
callback:res.data.callback,
signature:res.data.signature,
url:res.data.host,
dir:res.data.dir,
};
const photo = file.fileList[0].originFileObj; // 获取图片对象
let pointIndex = photo.name.lastIndexOf('.');
let suffixName = photo['name'].substring(pointIndex);//后缀名
const photoName = moment().format('YYYYMMDDHHmmss') + (Math.floor(Math.random() * 3665668)) + suffixName; // 原图片的名称
// const photoName = photo.name; // 原图片的名称
const key = ossConfig.dir + UID + photoName; // 存储到oss的图片名称 自己定,必须确保唯一性,不然会覆盖oss中原有的文件
const policy = ossConfig.policy; // 服务器端同事调oss的API,通过接口返回给前端的 policy
const OSSAccessKeyId = ossConfig.OSSAccessKeyId; // 服务器端同事调oss的API,通过接口返回给前端的 OSSAccessKeyId
const callback = ossConfig.callback; // 服务器端同事调oss的API,通过接口返回给前端的 callback。这个是需要 oss 触发这个回调来通知服务器操作结果。
const signature = ossConfig.signature; // 服务器端同事调oss的API,通过接口返回给前端的 signature。这个就是签名,最关键的。
const url = ossConfig.url;
const dir = ossConfig.dir;
// biu一下,提交给oss
let param = {
name:photoName,
key,
policy:policy,
OSSAccessKeyId:OSSAccessKeyId,
success_action_status:'200',
callback:callback,
signature:signature,
file:photo
};
const formData = new FormData();
Object.keys(param).forEach((key) => {
formData.append(key, param[key]);
});
request(url, {
method: 'POST',
headers: {
},
body: formData,
}).then((res) => {
//把上传到oss上的图片赋值给quill编辑器
let quill = this.editor;
let range = quill.selection.savedRange.index;
if(range || range == 0){
quill.insertEmbed(range,'image',res.data.data.full_url);
}
quill.setSelection(quill.getSelection().index+1);
})
});
}
render() {
let placeholder = ''
const { value,pla } = this.props;
// pla ? placeholder = pla : placeholder = '请输入内容'
return (
<div className="quillRich">
<div id="editor" ref="editor">
</div>
{/* 此处上传隐藏 只做上传使用 */}
<Upload
name="goods"
listType="picture-card"
showUploadList="false"
className="editUpload"
action=""
beforeUpload={this.beforeGoodsUpload}
onChange={this.uploadGoodsPic.bind(this,0)}
headers={config.headerAuth}
showUploadList={false}
accept=".png,.jpg,.jpeg"
>
</Upload>
</div>
);
}
}
export default QuillRichText;
###2.less文件 覆盖quill一些自带的样式
.ql-toolbar{
width: 100%!important;
border: none!important;
border-bottom:1px solid #E4E4E4!important;
}
#editor,.ql-editor{
border: none!important;
max-height: 440px!important;
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=SimSun]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=SimSun]::before {
content: "宋体";
font-family: "SimSun";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=SimHei]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=SimHei]::before {
content: "黑体";
font-family: "SimHei";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=Microsoft-YaHei]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=Microsoft-YaHei]::before {
content: "微软雅黑";
font-family: "Microsoft YaHei";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=KaiTi]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=KaiTi]::before {
content: "楷体";
font-family: "KaiTi";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=FangSong]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=FangSong]::before {
content: "仿宋";
font-family: "FangSong";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=Arial]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=Arial]::before {
content: "Arial";
font-family: "Arial";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=Times-New-Roman]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=Times-New-Roman]::before {
content: "Times New Roman";
font-family: "Times New Roman";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=sans-serif]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=sans-serif]::before {
content: "sans-serif";
font-family: "sans-serif";
}
.ql-font-SimSun {
font-family: "SimSun";
}
.ql-font-SimHei {
font-family: "SimHei";
}
.ql-font-Microsoft-YaHei {
font-family: "Microsoft YaHei";
}
.ql-font-KaiTi {
font-family: "KaiTi";
}
.ql-font-FangSong {
font-family: "FangSong";
}
.ql-font-Arial {
font-family: "Arial";
}
.ql-font-Times-New-Roman {
font-family: "Times New Roman";
}
.ql-font-sans-serif {
font-family: "sans-serif";
}
.ql-snow .ql-tooltip[data-mode=link]::before{
content: "\94FE\63A5";
}
.ql-snow .ql-tooltip.ql-editing a.ql-action::after{
content: "\786E\5B9A";
}
.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: "\5C0F\53F7\5B57\4F53";
}
.ql-snow .ql-picker.ql-size .ql-picker-label::before,
.ql-snow .ql-picker.ql-size .ql-picker-item::before{
content: "\6B63\5E38\5927\5C0F";
}
.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: "\5927\53F7\5B57\4F53";
}
.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: "\8D85\5927\5B57\4F53";
}
.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: "\6807\9898\0020\0031";
}
.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: "\6807\9898\0020\0032";
}
.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: "\6807\9898\0020\0033";
}
.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: "\6807\9898\0020\0034";
}
.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: "\6807\9898\0020\0035";
}
.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: "\6807\9898\0020\0036";
}
.ql-snow .ql-picker.ql-header .ql-picker-label::before,
.ql-snow .ql-picker.ql-header .ql-picker-item::before{
content: "\666E\901A\6587\672C";
}
.ql-snow .ql-tooltip::before{
content: "\8BBF\95EE\94FE\63A5";
}
.ql-snow .ql-tooltip a.ql-action::after{
content: "\7F16\8F91";
}
.ql-snow .ql-tooltip a.ql-remove::before{
content: "\79FB\9664\000A";
}
.ql-snow .ql-tooltip[data-mode=video]::before{
content: "\89C6\9891\94FE\63A5";
}
}
###3.自定义字体 font.less文件
/*font汉化*/
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=SimSun]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=SimSun]::before {
content: "宋体";
font-family: "SimSun";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=SimHei]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=SimHei]::before {
content: "黑体";
font-family: "SimHei";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=Microsoft-YaHei]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=Microsoft-YaHei]::before {
content: "微软雅黑";
font-family: "Microsoft YaHei";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=KaiTi]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=KaiTi]::before {
content: "楷体";
font-family: "KaiTi";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=FangSong]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=FangSong]::before {
content: "仿宋";
font-family: "FangSong";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=Arial]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=Arial]::before {
content: "Arial";
font-family: "Arial";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=Times-New-Roman]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=Times-New-Roman]::before {
content: "Times New Roman";
font-family: "Times New Roman";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=sans-serif]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=sans-serif]::before {
content: "sans-serif";
font-family: "sans-serif";
}
.ql-font-SimSun {
font-family: "SimSun";
}
.ql-font-SimHei {
font-family: "SimHei";
}
.ql-font-Microsoft-YaHei {
font-family: "Microsoft YaHei";
}
.ql-font-KaiTi {
font-family: "KaiTi";
}
.ql-font-FangSong {
font-family: "FangSong";
}
.ql-font-Arial {
font-family: "Arial";
}
.ql-font-Times-New-Roman {
font-family: "Times New Roman";
}
.ql-font-sans-serif {
font-family: "sans-serif";
}