feat: use lazyload image

This commit is contained in:
fantasticit 2022-04-13 20:30:03 +08:00
parent f1b039a687
commit 0337629d75
1 changed files with 22 additions and 11 deletions

View File

@ -1,7 +1,8 @@
import Image from 'next/image';
import cls from 'classnames';
import { useCallback, useEffect, useMemo, useRef } from 'react';
import { NodeViewWrapper, NodeViewContent } from '@tiptap/react'; import { NodeViewWrapper, NodeViewContent } from '@tiptap/react';
import { Resizeable } from 'components/resizeable'; import { Resizeable } from 'components/resizeable';
import { useEffect, useRef } from 'react';
import cls from 'classnames';
import { Typography, Spin } from '@douyinfe/semi-ui'; import { Typography, Spin } from '@douyinfe/semi-ui';
import { useToggle } from 'hooks/use-toggle'; import { useToggle } from 'hooks/use-toggle';
import { uploadFile } from 'services/file'; import { uploadFile } from 'services/file';
@ -10,30 +11,35 @@ import styles from './index.module.scss';
const { Text } = Typography; const { Text } = Typography;
const isNumber = (v) => typeof v === 'number';
export const ImageWrapper = ({ editor, node, updateAttributes }) => { export const ImageWrapper = ({ editor, node, updateAttributes }) => {
const isEditable = editor.isEditable; const isEditable = editor.isEditable;
const { hasTrigger, error, src, alt, title, width, height, textAlign } = node.attrs; const { hasTrigger, error, src, alt, title, width, height, textAlign } = node.attrs;
const $upload = useRef<HTMLInputElement>(); const $upload = useRef<HTMLInputElement>();
const [loading, toggleLoading] = useToggle(false); const [loading, toggleLoading] = useToggle(false);
const onResize = (size) => { const onResize = useCallback((size) => {
updateAttributes({ height: size.height, width: size.width }); updateAttributes({ height: size.height, width: size.width });
}; }, []);
const selectFile = () => { const selectFile = useCallback(() => {
if (!isEditable || error || src) return; if (!isEditable || error || src) return;
isEditable && $upload.current.click(); isEditable && $upload.current.click();
}; }, [isEditable, error, src]);
const handleFile = async (e) => { const handleFile = useCallback(async (e) => {
const file = e.target.files && e.target.files[0]; const file = e.target.files && e.target.files[0];
const fileInfo = { const fileInfo = {
fileName: extractFilename(file.name), fileName: extractFilename(file.name),
fileSize: file.size, fileSize: file.size,
fileType: file.type, fileType: file.type,
fileExt: extractFileExtension(file.name), fileExt: extractFileExtension(file.name),
}; };
toggleLoading(true); toggleLoading(true);
try { try {
const src = await uploadFile(file); const src = await uploadFile(file);
const size = await getImageWidthHeight(file); const size = await getImageWidthHeight(file);
@ -43,7 +49,7 @@ export const ImageWrapper = ({ editor, node, updateAttributes }) => {
updateAttributes({ error: '图片上传失败:' + (error && error.message) || '未知错误' }); updateAttributes({ error: '图片上传失败:' + (error && error.message) || '未知错误' });
toggleLoading(false); toggleLoading(false);
} }
}; }, []);
useEffect(() => { useEffect(() => {
if (!src && !hasTrigger) { if (!src && !hasTrigger) {
@ -52,7 +58,7 @@ export const ImageWrapper = ({ editor, node, updateAttributes }) => {
} }
}, [src, hasTrigger]); }, [src, hasTrigger]);
const content = (() => { const content = useMemo(() => {
if (error) { if (error) {
return ( return (
<div className={cls(styles.wrap, 'render-wrapper')}> <div className={cls(styles.wrap, 'render-wrapper')}>
@ -72,7 +78,12 @@ export const ImageWrapper = ({ editor, node, updateAttributes }) => {
); );
} }
const img = <img src={src} alt={alt} width={width} height={height} />; const img =
isNumber(width) && isNumber(height) ? (
<Image src={src} alt={alt} width={width} height={height} layout="responsive" />
) : (
<img src={src} alt={alt} width={width} height={height} />
);
if (isEditable) { if (isEditable) {
return ( return (
@ -87,7 +98,7 @@ export const ImageWrapper = ({ editor, node, updateAttributes }) => {
{img} {img}
</div> </div>
); );
})(); }, [error, src, isEditable]);
return ( return (
<NodeViewWrapper as="div" style={{ textAlign, fontSize: 0, maxWidth: '100%' }}> <NodeViewWrapper as="div" style={{ textAlign, fontSize: 0, maxWidth: '100%' }}>