import { JSXElement, Show, batch, createEffect, createSignal, onCleanup, onMount } from "solid-js" import { ImagePreview } from "../ImagePreview"; type ImageProps = { classList?: any, class?: string, style?: any, failInfo?: string | JSXElement, preview?: boolean, previewTip?: string | JSXElement, previewList?: string[], fit?: 'fill'|'contain'|'cover'|'none'|'scale-down', alt?: string, src?: string, lazy?: boolean, referrerPolicy?: any, scrollContainer?: string | HTMLElement, onLoad?: Function, onError?: Function, placeholder?: string | JSXElement, width?: number | string, height?: number | string, infinite?: boolean, maskClosable?: boolean, onClose?: Function, onSwitch?: Function, previewIndex?: number } export function Image (props: ImageProps) { const [imageError, setImageError] = createSignal(false); const [loading, setLoading] = createSignal(false); const [loadingImage, setLoadingImage] = createSignal(false); const [previewVisible, setPreviewVisible] = createSignal(false); const failSvg = const loadSvg = const failInfo = props.failInfo ?? failSvg; const previewTip = props.previewTip ?? '预览'; const fit = props.fit ?? '' const placeholder = props.placeholder ?? loadSvg; let wrap: any; let scrollElement: any = null; const innerClass = () => ({ 'cm-image-inner': true, 'cm-image-cursor': props.preview }); const imgClasses = () => ({ 'cm-image-img': true, 'cm-image-img-hidden': imageError() || loading() }); // 进行预览 const handlePreview = () => { setPreviewVisible(true); } // fit 样式 const fitStyle = () => { const fitContains = ['fill', 'contain', 'cover', 'none', 'scale-down']; return fitContains.includes(fit) ? `object-fit:${fit};` : ''; } const imageStyles = () => { return { width: typeof props.width === 'number' ? `${props.width}px` : props.width, height: typeof props.height === 'number' ? `${props.height}px` : props.height }; } // img onload const handleImageLoad = () => { batch(() => { setLoading(false); setImageError(false); }); props.onLoad && props.onLoad(); } // img onError const handleImageError = () => { batch(() => { setLoading(false); setImageError(true); setLoadingImage(false); }); props.onError && props.onError(); } // 修改状态 const loadImage = () => { batch(() => { setLoading(true); setImageError(false); setLoadingImage(true); }); } // watch src 重新加载 createEffect(() => { props.src; loadImage(); }); let observer: any; // 交叉监视器 const handleLazy = () => { observer = new IntersectionObserver(handlerObserveImage, { root: scrollElement, rootMargin: "0px", threshold: 0 }); observer.observe(wrap); } // 停止监听 const offObserver = () => { observer && observer.disconnect(); } const handlerObserveImage = (entries: any) => { for( let entry of entries) { if (entry.isIntersecting) { // destory new IntersectionObserver offObserver(); // run image onload loadImage(); } } } const addLazyImageListener = () => { const { scrollContainer } = props; if (typeof scrollContainer === 'object' && scrollContainer instanceof HTMLElement) { scrollElement = scrollContainer } else if (scrollContainer && typeof scrollContainer === 'string') { scrollElement = document.querySelector(scrollContainer); } // on scrollElement scroll handleLazy(); } const handleImageEvent = () => { props.lazy ? addLazyImageListener() : loadImage(); } const handleClose = () => { props.onClose && props.onClose(); } onMount(() => { handleImageEvent(); }) onCleanup(() => { offObserver(); }) return