Unknown DraftEntity key: null. 插入圖片,再輸入中文會報錯,下面方法可以解決,但是會產(chǎn)生iframe插入會產(chǎn)生問題,??,待解決
function myBlockRenderer(contentBlock) {
const type = contentBlock.getType();
// 圖片類型轉(zhuǎn)換為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="請輸文章內(nèi)容"
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;
}
內(nèi)容變化
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);
// }
}
將內(nèi)容轉(zhuǎn)換為html
draftToHtml(convertToRaw(editorContent.getCurrentContent()))
初始內(nèi)容
// 最開始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('請輸入正確的網(wǎng)頁地址');
return '';
}
}
本地上傳及轉(zhuǎn)換為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標簽,這樣就能把壓縮完的圖片不轉(zhuǎn)base64也能直接顯示出來)
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
// 圖片原始尺寸
const originWidth = this.width;
const originHeight = this.height;
// 最大尺寸限制,可通過設置寬高來實現(xiàn)圖片壓縮程度
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);
/* 第一個參數(shù)是創(chuàng)建的img對象;第二三個參數(shù)是左上角坐標,后面兩個是畫布區(qū)域?qū)捀?*/
// 壓縮后的圖片轉(zhuǎn)base64 url
/* canvas.toDataURL(mimeType, qualityArgument),mimeType 默認值是'image/png';
* qualityArgument表示導出的圖片質(zhì)量,只有導出為jpeg和webp格式的時候此參數(shù)才有效,默認值是0.92 */
const newUrl = canvas.toDataURL('image/jpeg', 0.92); // base64 格式
resolve({
data: {
link: newUrl,
},
});
// 也可以把壓縮后的圖片轉(zhuǎn)blob格式用于上傳
// canvas.toBlob((blob)=>{
// console.log(blob)
// //把blob作為參數(shù)傳給后端
// }, 'image/jpeg', 0.92)
};
});
}