Unknown DraftEntity key: null. 插入图片,再输入中文会报错,下面方法可以解决,但是会产生iframe插入会产生问题,💔,待解决
function myBlockRenderer(contentBlock) {
const type = contentBlock.getType();
// 图片类型转换为mediaComponent
if (type === 'atomic') {
return {
component: MediaComponent,
editable: false,
props: {
foo: 'bar',
},
};
}
}
class MediaComponent extends React.Component {
render() {
const { block, contentState } = this.props;
const { foo } = this.props.blockProps;
const data = contentState.getEntity(block.getEntityAt(0)).getData();
const emptyHtml = ' ';
return (
<div>
{emptyHtml}
<img
src={data.src}
alt={data.alt || ''}
style={{height: data.height || 'auto', width: data.width || 'auto'}}
/>
</div>
);
}
}
<Editor blockRendererFn={myBlockRenderer} />
下面是富文本编辑器react-draft-wysiwyg的例子
引入
import { Editor } from 'react-draft-wysiwyg';
import draftToHtml from 'draftjs-to-html';
import { EditorState, convertToRaw, ContentState } from 'draft-js';
// css需要单独引入
import 'react-draft-wysiwyg/dist/react-draft-wysiwyg.css';
<Editor
editorState={editorContent}
wrapperClassName={styles['demo-wrapper']}
editorClassName={styles['demo-editor']}
toolbarClassName={styles['toolbar-class']}
placeholder="请输文章内容"
localization={{
locale: 'zh',
}}
toolbar={{
options: [
'inline',
'blockType',
'fontSize',
'fontFamily',
'list',
'textAlign',
'colorPicker',
'link',
'embedded',
'image',
'remove',
'history',
],
link: { inDropdown: true, linkCallback },
embedded: { embedCallback },
fontFamily: {
options: [
'宋体',
'黑体',
'楷体',
'微软雅黑',
'Arial',
'Georgia',
'Impact',
'Tahoma',
'Times New Roman',
'Verdana',
],
},
image: {
uploadCallback: uploadImageCallBack,
uploadEnabled: true,
alignmentEnabled: true, // 是否显示排列按钮 相当于text-align
previewImage: true,
inputAccept: 'image/*',
alt: { present: false, mandatory: false },
defaultSize: {
height: 'auto',
width: 'auto',
},
},
}}
onEditorStateChange={onEditorStateChange}
/>
样式问题
.demo-editor {
height: 275px !important;
border: 1px solid #f1f1f1 !important;
padding: 5px !important;
border-radius: 2px !important;
}
.toolbar-class div,
.demo-wrapper div,
.demo-editor div {
box-sizing: content-box;
}
内容变化
function onEditorStateChange(editorState) {
console.log(draftToHtml(convertToRaw(editorState.getCurrentContent())));
console.log(editorState);
const oldState = editorContent; // 变更前的editorState
const newState = editorState; // 变更后的editorState
const oldText = oldState.getCurrentContent().getPlainText();
const newText = newState.getCurrentContent().getPlainText();
// if (newText !== oldText) { // 加判断后居中 列表 不生效,所以注释
setEditorContent(editorState);
// }
}
将内容转换为html
draftToHtml(convertToRaw(editorContent.getCurrentContent()))
初始内容
// 最开始editorContent = EditorState.createEmpty();
// 会报错 Unknown DraftEntity key: null
// 就改成了以下写法,完美解决报错问题
const templateContent = `<div>
</div>`;
const blocksFromHtml = convertFromHTML(templateContent);
const editorStateContentInitial = ContentState.createFromBlockArray(
blocksFromHtml.contentBlocks,
blocksFromHtml.entityMap,
);
const [editorContent, setEditorContent] = useState(EditorState.createWithContent(editorStateContentInitial));
校验url合法性
function checkURL(URL = '') {
const str = URL;
const Expression = /http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w- .\/?%&=]*)?/;
const objExp = new RegExp(Expression);
if (objExp.test(str) === true) {
return true;
} else {
return false;
}
}
function linkCallback(url = {}) {
if (checkURL(url.target)) {
return url;
} else {
message.error('请输入正确的链接地址');
return '';
}
}
function embedCallback(url = '') {
if (checkURL(url)) {
return url;
} else {
message.error('请输入正确的网页地址');
return '';
}
}
本地上传及转换为base64压缩
function uploadImageCallBack(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
const img = new Image();
// let url = ''
reader.onload = function(e) {
img.src = this.result;
};
img.onload = function() {
// console.log(img); // 获取图片
// console.log(img.src.length)
// 缩放图片需要的canvas(也可以在DOM中直接定义canvas标签,这样就能把压缩完的图片不转base64也能直接显示出来)
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
// 图片原始尺寸
const originWidth = this.width;
const originHeight = this.height;
// 最大尺寸限制,可通过设置宽高来实现图片压缩程度
const maxWidth = 400;
const maxHeight = 500;
// 目标尺寸
let targetWidth = originWidth;
let targetHeight = originHeight;
// 图片尺寸超过300x300的限制
if (originWidth > maxWidth || originHeight > maxHeight) {
if (originWidth / originHeight > maxWidth / maxHeight) {
// 更宽,按照宽度限定尺寸
targetWidth = maxWidth;
targetHeight = Math.round(maxWidth * (originHeight / originWidth));
} else {
targetHeight = maxHeight;
targetWidth = Math.round(maxHeight * (originWidth / originHeight));
}
}
// canvas对图片进行缩放
canvas.width = targetWidth;
canvas.height = targetHeight;
// 清除画布
context.clearRect(0, 0, targetWidth, targetHeight);
// 图片压缩
context.drawImage(img, 0, 0, targetWidth, targetHeight);
/* 第一个参数是创建的img对象;第二三个参数是左上角坐标,后面两个是画布区域宽高 */
// 压缩后的图片转base64 url
/* canvas.toDataURL(mimeType, qualityArgument),mimeType 默认值是'image/png';
* qualityArgument表示导出的图片质量,只有导出为jpeg和webp格式的时候此参数才有效,默认值是0.92 */
const newUrl = canvas.toDataURL('image/jpeg', 0.92); // base64 格式
resolve({
data: {
link: newUrl,
},
});
// 也可以把压缩后的图片转blob格式用于上传
// canvas.toBlob((blob)=>{
// console.log(blob)
// //把blob作为参数传给后端
// }, 'image/jpeg', 0.92)
};
});
}