Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

图片和文件预览组件(部分源码),可拖动,缩小,放大。 #41

Open
xuya227939 opened this issue Dec 26, 2018 · 0 comments
Labels
Technology 技术分享

Comments

@xuya227939
Copy link
Owner

xuya227939 commented Dec 26, 2018

源码

/*
 * 图片预览组件
 * @Author: Jiang 
 * @since: 2018-12-21 13:54:00 
 */
import React from 'react';
import { Modal, Icon } from 'antd';
import PropTypes from 'prop-types';
import config from 'Common/config';
import { redirect } from 'Common/util';
import './index.less';
// 判断游览器
const USER_AGENT = navigator.userAgent;
export default class PreviewImage extends React.Component {
    constructor(props) {
        super(props);
        // 是否按下
        this.isDown = false;
        this.IMG_WIDTH = 300;
        this.IMG_HEIGHT = 300;
        // 放大或缩小比例
        this.zoomOut = 0;
        this.state = {
            // 移动的时候,更改距离和放大缩小
            imgStyle: {
                position: 'relative',
                left: '0px',
                top: '0px'
            },
            // 放大缩小比例
            num: 0,
            // 是否显示缩小放大比例
            isShowRate: false,
            // true 为图片模式, false为pdf|word|xls预览模式
            isShowPreView: false
        };
        // 图片按下事件
        this.handlerImgDown = this.handlerImgDown.bind(this);
        // 图片加载
        this.onload = this.onload.bind(this);
    }

    componentDidMount() {
        const { url, destruction } = this.props;
        // true 打开弹窗 false 预览pdf or xls or word
        if(this.getType(url)) {
            const getType = this.getType(url);
            if(document.addEventListener && USER_AGENT.indexOf('Firefox') > -1) {
                document.addEventListener('DOMMouseScroll', this.onScroll, false); 
            } else {
                document.body.onmousewheel = this.onScroll;
            }
            this.setState({
                isShowPreView: getType
            });
        } else {
            this.openUrl(url);
            destruction();
        }
    }

    // 销毁
    componentWillUnmount() {
        document.onmousemove = null;
        document.onmouseup = null;
        document.body.onmousewheel = null;
        document.removeEventListener('DOMMouseScroll', this.onScroll, false); 
    }

    // 取得文件后缀名
    getFileSuffix = url => {
        const fileArr = url.split('.');
        return fileArr[fileArr.length - 1].toLocaleLowerCase();
    }

    // 根据文件类型是跳转页面还是预览图片
    getType = url => {
        if(url) {
            let suffix = this.getFileSuffix(url);
            if(suffix.indexOf('?') > -1) {
                suffix = suffix.split('?')[0];
            }
            return config.FILE_TYPE.IMAGE.indexOf(suffix) > -1;
        }
    }

    // 缩小或放大
    onScroll = (e) => {
        const { num, imgStyle } = this.state;
        const event = e || window.event;
        let style = {};
        let wheelDelta;
        let wheelDeltaNumber;
        let rate;
        // firefox and safari 的滚动轴值不一样,其余的都是1200
        if(USER_AGENT.indexOf('Firefox') > -1) {
            // wheelDelta = 3 or -3
            wheelDelta = event.detail;
            wheelDeltaNumber = 30;
        } else if(USER_AGENT.indexOf('Safari') > -1) {
            // wheelDelta = 360 or -360
            wheelDelta = event.wheelDelta;
            wheelDeltaNumber = 3600;
        } else {
            // wheelDelta = 120 or -120
            wheelDelta = event.wheelDelta;
            wheelDeltaNumber = 1200;
        }
        // 如果比例达到100或者为1的时候,停止继续放大或缩小 > 0 放大, < 0 缩小
        if((num === 100 && wheelDelta > 0) || (num === 1 && wheelDelta < 0)) {
            return;
        }
        // 计算放大或缩小比例
        this.zoomOut = (this.zoomOut + wheelDelta / wheelDeltaNumber);
        style.width = this.IMG_WIDTH * (1 + this.zoomOut) + 'px';
        style.height = this.IMG_HEIGHT * (1 + this.zoomOut) + 'px';
        style.top = imgStyle.top;
        style.left = imgStyle.left;
        style.position = 'relative';
        // 换算成百分比,显示
        if(this.zoomOut.toFixed(1) * 100 < 0) {
            rate = 10 + (this.zoomOut.toFixed(1) * 100) / 10;
        } else {
            rate = parseInt(this.zoomOut.toFixed(1) * 100);
        }
        // 不允许出现百分之0
        rate = rate === 0 ? rate = 10 : rate;
        this.setState({
            imgStyle: style,
            num: rate,
            isShowRate: true
        });
    }

    // 打开pdf、xls、word等文件
    openUrl = url => {
        if(url) {
            redirect(url, '_blank'); 
        }
    }

    // 图片按下事件
    handlerImgDown = (e) => {
        e.preventDefault();
        const previewImg = document.getElementsByClassName('preview-image');
        this.isDown = true;
        this.currentX = e.clientX;
        this.currentY = e.clientY;
        this.offsetLeft = parseInt(previewImg[0].offsetLeft);
        this.offsetTop = parseInt(previewImg[0].offsetTop);
        this.handlerImgMove();
        // 移除事件
        document.onmouseup = () => {
            document.onmousemove = null;
            document.onmouseup = null;
            this.isDown = false;
        };
    }

    // 图片移动
    handlerImgMove = () => {
        document.onmousemove = (e) => {
            if(this.isDown) {
                const { imgStyle } = this.state;
                let style = {};
                style.width = imgStyle.width + 'px';
                style.height = imgStyle.height + 'px';
                style.left = e.clientX - (this.currentX - this.offsetLeft) + 'px';
                style.top = e.clientY - (this.currentY - this.offsetTop) + 'px';
                style.position = 'relative';
                this.setState({
                    imgStyle: style
                });
            }
        };
    }

    // 获取图片真实宽高
    onload = (e) => {
        this.IMG_WIDTH = e.target.width;
        this.IMG_HEIGHT = e.target.height;
    }
    
    render() {
        const { imgStyle, isShowRate, num } = this.state;
        const { url, hideModal } = this.props;
        const { isShowPreView } = this.state;
        return (
            <div className="c-c-preview-image">
                {
                    isShowPreView &&
                    <Modal
                        wrapClassName="c-c-preview-image-modal"
                        visible={true}
                        centered={true}
                        closable={false}
                        width="100%"
                        onCancel={hideModal}
                        footer={null}
                    >
                        <img
                            draggable="false"
                            alt="img"
                            className="preview-image select-cursor"
                            onMouseDown={this.handlerImgDown}
                            src={url}
                            onLoad={this.onload}
                            style={imgStyle}
                        />
                        {
                            isShowRate && 
                            <div className="viewer-tooltip">{num}%</div>
                        }
                    </Modal>
                }
                <Icon onClick={hideModal} className="close" type="close" />
            </div>
        );
    }
}

PreviewImage.propTypes = {
    // src or pdf or xls or word
    url: PropTypes.string,
};

less

@import "../../../common/asset/variable.less";

.c-c-preview-image {
    .close {
        position: fixed;
        padding: 15px;
        top: 0px;
        right: 0px;
        font-size: 32px;
        color: #333;
        cursor: pointer;
        z-index: 1002;
    }
}

.c-c-preview-image-modal {
    overflow: hidden;
    user-select: none;

    .viewer-tooltip {
        background-color: rgba(0,0,0,.8);
        border-radius: 10px;
        color: #fff;
        font-size: 12px;
        height: 20px;
        left: 50%;
        line-height: 20px;
        margin-left: -25px;
        margin-top: -10px;
        position: absolute;
        text-align: center;
        top: 50%;
        width: 50px;
        z-index: 1001;
    }

    .ant-modal-close-x {
        font-size: 32px;
    }

    .select-cursor {
        cursor: move;
        cursor: grab;
    }

    .ant-modal-close {
        position: fixed;
        color: #333;
    }
    
    .ant-modal-body {
        padding: 0px;
    }
    
    .ant-modal-content {
        background-color: transparent;
        box-shadow: none;
        position: absolute;
        user-select: none;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%);
    }
}
@xuya227939 xuya227939 changed the title 图片预览组件(部分源码),可拖动,缩小,放大。 图片和文件预览组件(部分源码),可拖动,缩小,放大。 Dec 26, 2018
@xuya227939 xuya227939 added the Technology 技术分享 label Jun 26, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Technology 技术分享
Projects
None yet
Development

No branches or pull requests

1 participant