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

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

源码


/*
 * 图片预览组件
 * @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,
};


@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%);
    }
}
目录
相关文章
|
数据采集 机器学习/深度学习 搜索推荐
大模型开发: 描述主成分分析(PCA)以及它在降维中的应用。
PCA是广泛应用的降维技术,通过线性变换找到最大化方差的主成分,降低数据维度,简化计算并揭示数据结构。步骤包括数据预处理、计算协方差矩阵、特征值分解、选择主成分和数据转换。适用于图像识别、推荐系统等领域,但无监督性质可能导致类别信息丢失,且假设数据服从高斯分布。
417 1
|
算法 搜索推荐 安全
淘宝信息流融合混排服务升级
淘宝信息流融合混排服务升级
892 1
|
网络协议 自动驾驶 安全
掌握SOME/IP:远程过程调用 构建高效通信系统的关键技术
掌握SOME/IP:远程过程调用 构建高效通信系统的关键技术
1425 0
|
网络性能优化 调度 网络虚拟化
配置HQoS示例
HQoS简介 HQoS通过多级队列进一步细化区分业务流量,对多个用户、多种业务等传输对象进行统一管理和分层调度,在现有的硬件环境下使设备具备内部资源的控制策略,既能够为高级用户提供质量保证,又能够从整体上节约网络建设成本。 交换机的HQoS主要通过流队列和用户队列实现。
294 7
|
11月前
|
前端开发 JavaScript API
React 文件下载组件:File Download
本文详细介绍了如何在React应用中实现文件下载组件,包括基本概念、实现步骤和代码示例。同时,探讨了常见问题如文件类型不匹配、文件名乱码等及其解决方法,旨在提升用户体验和代码可维护性。
738 2
|
JavaScript
【ElementUI】Vue+ElementUI多文件上传,一次请求上传多个文件!
教大家一次请求,上传多个文件。 ElementUI如果是默认方案,上传多张图片并不是真正的一次上传多张,而是发送多次请求,一次请求携带一张图片。
1416 0
|
10月前
|
前端开发 安全 UED
React 文件预览组件:File Preview
在现代Web应用中,文件上传和预览功能至关重要。本文基于React库,详细介绍如何构建文件预览组件,涵盖文件选择器、图片预览、文件大小限制及多种文件类型支持。通过实际代码示例,解析常见问题如跨域请求、文件路径处理和状态管理,并提供解决方案。帮助开发者提升用户体验,减少误操作。
736 2
|
数据采集 自然语言处理 Python
深入探索Python中的汉字处理技巧
深入探索Python中的汉字处理技巧
266 1
|
机器学习/深度学习 人工智能 自然语言处理
人工智能浪潮下的自然语言处理技术演进
本文从自然语言处理(NLP)技术的历史发展出发,深入剖析了在人工智能(AI)大潮中该领域的创新突破。我们将探讨深度学习如何推动语言模型的革新、多语言处理技术的发展,以及机器翻译和语音识别的最新进展。文章还将讨论这些技术进步如何影响社会,并展望未来NLP技术的潜力与挑战。
449 0
|
监控 前端开发 安全
【专栏】介绍了前端工程师如何掌握SSH命令,包括SSH协议的基础知识、命令行操作如登录、文件传输、目录管理和进程管理
【4月更文挑战第29天】本文介绍了前端工程师如何掌握SSH命令,包括SSH协议的基础知识、命令行操作如登录、文件传输、目录管理和进程管理。在前端开发中,SSH用于部署项目、协同后端开发及服务器监控。文章还强调了使用密钥认证、配置别名及安全注意事项,并提醒开发者面对问题时如何解决。学习和熟练运用SSH是前端工程师适应复杂项目需求的关键。
392 0