前端react简单封装 ---《图片预览插件》

效果图


组件

js代码



    import React from 'react';

    import ReactDOM from 'react-dom';

    import PropTypes from 'prop-types';

    import { ZoomInOutlined, ZoomOutOutlined,RedoOutlined,UndoOutlined,ArrowLeftOutlined,ArrowRightOutlined,CloseOutlined} from '@ant-design/icons'

    import './index.css';


    class PhotoPreview extends React.Component {

    constructor(props) {

        super(props);

        this.state = {

            bigUrl: props.bigUrl === '' ? props.url : props.bigUrl,

            tool: Object.assign(PhotoPreview.defaultProps.tool, props.tool),

            imgIndex: props.imgIndex,

            imgs: props.imgs,


            loadEl: true, // loading元素显示隐藏

            figureEl: false, // 生成图片预览元素

            imgOriginalWidth: 0, // 当前大图默认宽度值

            imgOriginalHeight: 0, // 当前大图默认高度值

            imgAttr: {

                // 大图的地址及描述

                src: '',

                alt: '',

            },

            imgParentStyle: {

                // 大图父级div元素样式

                width: '0px',

                height: '0px',

            },

            rotateDeg: 0, // 图片旋转角度

            increaseNum: 20, // 图片放大时距离空隙

        };


        // 获取相关元素

        this.bigImgRef = React.createRef();

        this.ppiRef = React.createRef();

    }


    // 预览图片超出window宽或高的处理

    beyondWindow = () => {

        const { imgParentStyle, rotateDeg, increaseNum } = this.state;

        const iWidth = parseFloat(imgParentStyle.width) + increaseNum * 2;

        const iHeight = parseFloat(imgParentStyle.height) + increaseNum * 2;

        const ppiEl = this.ppiRef.current;


        let ips = imgParentStyle;

        if (rotateDeg % 360 === 90 || rotateDeg % 360 === 270) {

            if (iHeight > window.innerWidth) {

                ips = { ...ips, left: `${(iHeight - iWidth) / 2 + increaseNum}px` };

            } else {

                ips = { ...ips, left: 'auto' };

            }

            if (iWidth > window.innerHeight) {

                ips = { ...ips, top: `${(iWidth - iHeight) / 2 + increaseNum}px` };

            } else {

                ips = { ...ips, top: 'auto' };

            }

        } else if (

            (rotateDeg % 360 === -90 && iWidth > iHeight) ||

            (rotateDeg % 360 === -270 && iWidth > iHeight)

        ) {

            // 如果是-90或-270,并且图片宽大于高的话,那么则需要做兼容处理

            let left = 'auto';

            let top = 'auto';

            if (iHeight > ppiEl.clientWidth) {

                left = `${-(iHeight / 2) + increaseNum * 2}px`;

            }

            if (iWidth > ppiEl.clientHeight) {

                top = `${iHeight / 2 + increaseNum / 2}px`;

            }

            ips = { ...ips, left: `${left}`, top: `${top}` };

        } else if (

            (rotateDeg % 360 === -90 && iHeight > iWidth) ||

            (rotateDeg % 360 === -270 && iHeight > iWidth)

        ) {

            // 如果是-90或-270,并且图片高大于宽的话,那么则需要做兼容处理

            let left = 'auto';

            let top = 'auto';

            if (iHeight > ppiEl.clientWidth) {

                left = `${iWidth / 2}px`;

            }

            if (iWidth > ppiEl.clientHeight) {

                top = `${-(iWidth / 2) + increaseNum * 2}px`;

            }


            ips = { ...ips, left: `${left}`, top: `${top}` };

        } else {

            if (iWidth > window.innerWidth) {

                ips = { ...ips, left: `${increaseNum}px` };

            } else {

                ips = { ...ips, left: 'auto' };

            }

            if (iHeight > window.innerHeight) {

                ips = { ...ips, top: `${increaseNum}px` };

            } else {

                ips = { ...ips, top: 'auto' };

            }

        }

        this.setState({

            imgParentStyle: ips,

        });

    };


    // 图片缩小事件

    toSmallEvent = () => {

        const { tool, imgParentStyle, imgOriginalWidth, imgOriginalHeight } = this.state;

        if (tool.toSmall === false) {

            return;

        }

        let width = parseFloat(imgParentStyle.width) / 1.5;

        let height = parseFloat(imgParentStyle.height) / 1.5;

        // 图片缩小不能超过5倍

        if (width < imgOriginalWidth / 5) {

            width = imgOriginalWidth / 5;

            height = imgOriginalHeight / 5;

        }

        this.setState(

            {

                imgParentStyle: Object.assign(imgParentStyle, {

                    width: `${width}px`,

                    height: `${height}px`,

                }),

            },

            () => {

                this.beyondWindow();

            }

        );

    };


    // 图片放大事件

    toBigEvent = () => {

        const { tool, imgParentStyle, imgOriginalWidth, imgOriginalHeight } = this.state;

        if (tool.toBig === false) {

            return;

        }

        let width = parseFloat(imgParentStyle.width) * 1.5;

        let height = parseFloat(imgParentStyle.height) * 1.5;

        // 图片放大不能超过5倍

        if (width > imgOriginalWidth * 5) {

            width = imgOriginalWidth * 5;

            height = imgOriginalHeight * 5;

        }

        this.setState(

            {

                imgParentStyle: Object.assign(imgParentStyle, {

                    width: `${width}px`,

                    height: `${height}px`,

                }),

            },

            () => {

                this.beyondWindow();

            }

        );

    };


    // 向左旋转事件

    turnLeftEvent = () => {

        const { tool, rotateDeg, imgParentStyle } = this.state;

        if (tool.turnLeft === false) {

            return;

        }

        const iRotateDeg = rotateDeg - 90;

        this.setState(

            {

                imgParentStyle: Object.assign(imgParentStyle, {

                    transform: `rotate(${iRotateDeg}deg)`,

                }),

                rotateDeg: iRotateDeg,

            },

            () => {

                this.beyondWindow();

            }

        );

    };


    // 向右旋转事件

    turnRightEvent = () => {

        const { tool, rotateDeg, imgParentStyle } = this.state;

        if (tool.turnRight === false) {

            return;

        }

        const iRotateDeg = rotateDeg + 90;

        this.setState(

            {

                imgParentStyle: Object.assign(imgParentStyle, {

                    transform: `rotate(${iRotateDeg}deg)`,

                }),

                rotateDeg: iRotateDeg,

            },

            () => {

                this.beyondWindow();

            }

        );

    };


    // 上一张图片

    goLeftEvent = () => {

        const { imgIndex, imgs, loadEl } = this.state;

        // 如果还在loading加载中,不予许上一张下一张操作

        if (loadEl) {

            return;

        }

        const nImgIndex = imgIndex - 1;

        // console.log(nImgIndex);

        if (nImgIndex < 0) {

            return;

        }

        this.setState(

            {

                imgIndex: nImgIndex,

                rotateDeg: 0,

                imgParentStyle: {

                    width: '0px',

                    height: '0px',

                },

            },

            () => {

                this.photoShow(imgs[nImgIndex].bigUrl, imgs[nImgIndex].alt, false);

            }

        );

    };


    // 下一张图片

    goRightEvent = () => {

        const { imgIndex, imgs, loadEl } = this.state;

        // 如果还在loading加载中,不予许上一张下一张操作

        if (loadEl) {

            return;

        }

        const nImgIndex = imgIndex + 1;

        // console.log(nImgIndex);

        if (nImgIndex > imgs.length - 1) {

            return;

        }

        this.setState(

            {

                imgIndex: nImgIndex,

                rotateDeg: 0,

                imgParentStyle: {

                    width: '0px',

                    height: '0px',

                },

            },

            () => {

                // 如果不存在大图,那么直接拿小图代替。

                const bigUrl = imgs[nImgIndex].bigUrl || imgs[nImgIndex].url;

                this.photoShow(bigUrl, imgs[nImgIndex].alt);

            }

        );

    };


    // 关闭事件

    closeEvent = () => {

        // 恢复到默认值

        const { imgIndex, imgs } = this.props;

        this.setState({

            imgIndex,

            imgs,

            figureEl: false,

            rotateDeg: 0,

            imgParentStyle: {

                width: '0px',

                height: '0px',

            },

        });

        window.removeEventListener('mousewheel', this._psMousewheelEvent);

        window.removeEventListener('keydown', this._psKeydownEvent);

        window.removeEventListener('resize', this._psWindowResize);

        document.body.removeAttribute('photo-preview-show');

    };


    // 大图被执行拖拽操作

    bigImgMouseDown = (event) => {

        event.preventDefault();

        const ppiEl = this.ppiRef.current;

        const bigImgEl = this.bigImgRef.current;

        const diffX = event.clientX - bigImgEl.offsetLeft;

        const diffY = event.clientY - bigImgEl.offsetTop;

        // 鼠标移动的时候

        bigImgEl.onmousemove = (ev) => {

            const moveX = parseFloat(ev.clientX - diffX);

            const moveY = parseFloat(ev.clientY - diffY);

            const mx = moveX > 0 ? -moveX : Math.abs(moveX);

            const my = moveY > 0 ? -moveY : Math.abs(moveY);

            let sl = ppiEl.scrollLeft + mx * 0.1;

            let sr = ppiEl.scrollTop + my * 0.1;

            if (sl <= 0) {

                sl = 0;

            } else if (sl >= ppiEl.scrollWidth - ppiEl.clientWidth) {

                sl = ppiEl.scrollWidth - ppiEl.clientWidth;

            }

            if (sr <= 0) {

                sr = 0;

            } else if (sr >= ppiEl.scrollHeight - ppiEl.clientHeight) {

                sr = ppiEl.scrollHeight - ppiEl.clientHeight;

            }

            ppiEl.scrollTo(sl, sr);

        };

        // 鼠标抬起的时候

        bigImgEl.onmouseup = () => {

            bigImgEl.onmousemove = null;

            bigImgEl.onmouseup = null;

        };

        // 鼠标离开的时候

        bigImgEl.onmouseout = () => {

            bigImgEl.onmousemove = null;

            bigImgEl.onmouseup = null;

        };

    };


    // 鼠标滚轮事件

    _psMousewheelEvent = (event) => {

        // event.preventDefault();

        const { figureEl, tool } = this.state;

        if (figureEl && tool.mousewheel) {

            if (event.wheelDelta > 0) {

                this.toBigEvent();

            } else {

                this.toSmallEvent();

            }

        }

    };


    // 键盘按下事

    _psKeydownEvent = (event) => {

        const { figureEl, tool } = this.state;

        if (event.keyCode === 27 && tool.esc && figureEl) {

            this.closeEvent();

        }

    };


    // 窗口发生改变的时候

    _psWindowResize = () => {

        const { figureEl } = this.state;

        if (figureEl) {

            this.beyondWindow();

        }

    };


    // 图片展示

    photoShow = (url, alt, winEventToggle) => {

        // 图片加载并处理

        this.setState({

            loadEl: true,

            figureEl: true,

        });

        const img = new Image();

        img.src = url;

        img.onload = async () => {

            this.setState(

                {

                    loadEl: false,

                    imgOriginalWidth: img.width,

                    imgOriginalHeight: img.height,

                    imgAttr: {

                        src: url,

                        alt,

                    },

                    imgParentStyle: {

                        width: `${img.width}px`,

                        height: `${img.height}px`,

                    },

                },

                () => {

                    this.beyondWindow();

                }

            );

        };


        // 是否需再次执行window事件

        const wev = winEventToggle || true;

        if (wev) {

            // console.log('wev');

            // window触发事件

            window.addEventListener('mousewheel', this._psMousewheelEvent);

            window.addEventListener('keydown', this._psKeydownEvent);

            window.addEventListener('resize', this._psWindowResize);

            document.body.setAttribute('photo-preview-show', 'true');

        }

    };


    UNSAFE_componentWillReceiveProps(newProps) {

        console.log(`new-props:${newProps.nImgIndex}`);

    }


    render() {

        const { alt, url } = this.props;

        const {

            bigUrl,

            tool,

            figureEl,

            loadEl,

            imgAttr,

            imgParentStyle,

            imgIndex,

            imgs,

            increaseNum,

        } = this.state;

        const iParentStyle = { ...imgParentStyle };

        const iSpanStyle = {

            width: `${parseFloat(imgParentStyle.width) + increaseNum * 2}px`,

            height: `${parseFloat(imgParentStyle.height) + increaseNum * 2}px`,

        };

        return (

            <>

                

                    onClick={this.photoShow.bind(this, bigUrl, alt)}

                    src={url}

                    alt={alt}

                    className="photo-preview__thumb-img"

                />

                {figureEl

                    ? ReactDOM.createPortal(

                          <>

                              

                                  

                                      {loadEl ? (

                                          

                                      ) : (

                                          

                                              className="photo-preview__img-wrap"

                                              style={iParentStyle}

                                          >

                                              

                                                  className="photo-preview__img-placeholder"

                                                  style={{

                                                      ...iSpanStyle,

                                                      marginLeft: `-${increaseNum}px`,

                                                      marginTop: `-${increaseNum}px`,

                                                  }}

                                              >

                                              

                                                  src={imgAttr.src}

                                                  alt={imgAttr.alt}

                                                  onMouseDown={this.bigImgMouseDown}

                                                  ref={this.bigImgRef}

                                              />

                                          

                                      )}

                                      

                                          {tool.toSmall ? (

                                              

                                          ) : null}

                                          {tool.toBig ? (

                                              

                                          ) : null}

                                          {tool.turnLeft ? (

                                              

                                          ) : null}

                                          {tool.turnRight ? (

                                              

                                          ) : null}


                                          {imgIndex !== '' && imgs.length > 1 ? (

                                              <>

                                              

                                              

                                              

                                          ) : null}


                                          {tool.close ? (

                                              

                                          ) : null}

                                      

                                  

                              

                          ,

                          document.body

                      )

                    : null}

            

        );

    }

    }


    PhotoPreview.defaultProps = {

    bigUrl: '',

    alt: '',

    tool: {

        toSmall: true, // 缩小按钮

        toBig: true, // 放大按钮

        turnLeft: true, // 左转按钮

        turnRight: true, // 右转按钮

        close: true, // 关闭按钮

        esc: true, // esc键触发

        mousewheel: true, // 鼠标滚轮事件是否触发

    },

    imgIndex: '',

    imgs: [],

    };

    PhotoPreview.propTypes = {

    bigUrl: PropTypes.string,

    url: PropTypes.string.isRequired,

    alt: PropTypes.string,

    tool: PropTypes.object,

    imgIndex: PropTypes.number,

    imgs: PropTypes.array,

    };

    export default PhotoPreview;



css代码

.photo-preview__thumb-img {

    cursor: pointer;

  }

  .photo-preview {

    margin: 0;

    position: fixed;

    left: 0;

    top: 0;

    bottom: 0;

    right: 0;

    z-index: 999999;

    background-color: rgba(0, 0, 0, 0.5);

    animation: fadeIn 0.4s;

  }

  .photo-preview .photo-preview__in {

    position: absolute;

    left: 0;

    top: 0;

    right: 0;

    bottom: 0;

    overflow: auto;

    user-select: none;

    display: flex;

    justify-content: center;

    align-items: center;

  }

  .photo-preview .photo-preview__in::-webkit-scrollbar {

    width: 15px;

    height: 15px;

  }

  .photo-preview .photo-preview__in::-webkit-scrollbar-track {

    border-radius: 0;

  }

  .photo-preview .photo-preview__in::-webkit-scrollbar-thumb {

    border-radius: 0;

    background-color: silver;

  }

  .photo-preview .photo-preview__in .photo-preview__img-wrap {

    transition-duration: 0.2s;

    position: absolute;

  }

  .photo-preview .photo-preview__in .photo-preview__img-wrap .photo-preview__img-placeholder {

    display: block;

    width: 100%;

    height: 100%;

    position: absolute;

    pointer-events: none;

  }

  .photo-preview .photo-preview__in .photo-preview__img-wrap img {

    position: absolute;

    width: 100%;

    height: 100%;

  }

  .photo-preview .photo-preview__loading {

    position: relative;

  }

  .photo-preview .photo-preview__loading::before {

    content: ' ';

    display: block;

    border-top: 5px solid #999999;

    border-right: 5px solid #999999;

    border-bottom: 5px solid #999999;

    border-left: 5px solid #ffffff;

    width: 50px;

    height: 50px;

    border-radius: 50%;

    animation: rotating 0.8s linear 0s infinite;

  }

  .photo-preview .photo-preview__tool {

    border-radius: 45px;

    padding: 5px 10px;

    height: 45px;

    background-color: #ffffff;

    opacity: 0.3;

    position: fixed;

    top: 20px;

    right: 20px;

    user-select: none;

    transition-duration: 0.5s;

    display: flex;

  }

  .photo-preview .photo-preview__tool:hover {

    opacity: 0.9;

  }

  .photo-preview .photo-preview__tool .iconfont {

    font-size: 25px;

    text-align: center;

    width: 35px;

    height: 35px;

    line-height: 35px;

    color: #444444;

    transition-duration: 0.4s;

    margin: 0 2px;

    cursor: pointer;

  }

  .photo-preview .photo-preview__tool .icon-close:hover {

    transform: scale(1.15);

  }

  .photo-preview .photo-preview__tool .icon-turn-left {

    transform: rotate(50deg);

  }

  .photo-preview .photo-preview__tool .icon-turn-left:hover {

    transform: rotate(0deg);

  }

  .photo-preview .photo-preview__tool .icon-turn-right {

    transform: rotate(-50deg);

  }

  .photo-preview .photo-preview__tool .icon-turn-right:hover {

    transform: rotate(0deg);

  }

  .photo-preview .photo-preview__tool .icon-go-left[data-disable='true'],

  .photo-preview .photo-preview__tool .icon-go-right[data-disable='true'] {

    cursor: wait;

  }

  body[photo-preview-show='true'] {

    overflow: hidden;

  }

  @keyframes fadeIn {

    0% {

      opacity: 0;

    }

    100% {

      opacity: 1;

    }

  }

  @keyframes rotating {

    0% {

      transform: rotate(0deg);

    }

    100% {

      transform: rotate(360deg);

    }

  }

引用代码

import PhotoPreview from '@src/components/Common/PhotoPreview'

html

                                                            key={index}

                                                            imgIndex={index}

                                                            tool={{ turnLeft: false, turnRight: false}}

                                                            imgs={detailList} 

                                                            url={item.saveFilePath}

                                                            bigUrl={item.saveFilePath} 

                                                            className='images'/>



配置项列表

你可能感兴趣的:(前端react简单封装 ---《图片预览插件》)