基础前端React简书整理--前端相关1

文件点击上传和拖拽上传

2019-08-23  本文已影响2人  CondorHero
一、文件点击上传(事件代理)

核心思想就是模拟鼠标点击事件 <input type="file" />还是文件上传的渠道,只不过我们需要把它给隐藏掉,加个 hidden 属性 <input type="file" hidden/> 虽然标签仍然在,但是我们看不见了,现在我们只需要,点击页面的加号图标点击图标来唤醒文件上传框。
核心代码:

onClick = {()=>{
    let evt = document.createEvent("mouseEvents");
    evt.initMouseEvent("click",false,false);
    this.refs.file.dispatchEvent(evt);
}}
模拟表单提交

源代码展示:

import React, { Component } from 'react';
import { Progress , Icon , Button} from 'antd';
import classnames from "classnames";
import axios from "axios";
export default class S1 extends Component {
    constructor(){
        super();
        this.state = {
            base64 : "",
            progress : 0
        }
    }
    render() {
        return (
            <div>   
                    <div className = "img" style = {{
                        width: "400px",
                        height: "300px",
                        textAlign:"center",
                        border: "1px dashed #457791",
                        backgroundImage:`url(${this.state.base64})`
                    }}>
                        <div>
                            <Icon type="plus-circle" style={{ fontSize: '150px', color: '#08c' , marginTop:'20px'}} onClick = {()=>{
                                let evt = document.createEvent("mouseEvents");
                                evt.initMouseEvent("click",false,false);
                                this.refs.file.dispatchEvent(evt);
                            }}/>
                        </div>
                            <Button style={{ marginTop:'40px'}} onClick = {()=>{
                            // 点击提交创建虚拟表单
                            let vform = new FormData();
                            // 追加文件
                            vform.append('file',this.refs.file.files[0]);
                            axios({
                                method: 'post',
                                url: '/api/uppic',
                                data: vform,
                                onUploadProgress: (progressEvent)=> {
                                    // ~~()取整
                                    this.setState({
                                        progress : ~~(progressEvent.loaded / progressEvent.total * 100)
                                    })
                                }
                            }).then(data=>{
                                this.setState({
                                    filename : data.data.filename
                                })
                            });
                        }}>提交</Button>
                        {/*上传进度条*/}
                        <div className = "img2">
                            <Progress className = {classnames({
                                    isHidden:this.state.progress <= 0 || this.state.progress >= 100
                                })} type="line" strokeColor = "primary" percent={this.state.progress} width = {100} />
                        </div>
                        <input type = "file" ref = "file" hidden multiple onChange = {(e)=>{
                            let file = e.target.files[0];
                            // HTML的新特性可以把图片变成base64地址
                            let fr = new FileReader();
                            fr.readAsDataURL(file);
                            fr.onload = (_e)=>{
                                this.setState({
                                    base64 : _e.target.result
                                })
                            }
                        }}/>
                    </div>
            </div>
        )
    }
}
五、文件拖拽上传

拖拽上传的思路:

// 移动拖着不放事件
document.addEventListener("dragover",function(e){
    console.log("拖着不放事件!");
    e.preventDefault();
});
// 移动拖着放下事件
document.addEventListener("drop",function(e){
    console.log("拖着放下事件!");
    e.preventDefault();
});

阻止这两个事件,就发现拖拽图片到浏览器(其实任何文件都行)已经没有任何效果了。


阻止浏览器默认事件
let evt = document.createEvent("mouseEvents");
evt.initMouseEvent("click",false,false);
this.refs.file.dispatchEvent(evt);

比如下面我拖拽上来的八张图片信息打印如下:


最终的实验效果:


图片拖拽效果

完整代码及注释:

import React, { Component } from 'react';

import {Icon} from "antd";

export default class S2 extends Component {
    constructor(){
        super();
        this.state = {
            arr : [],
            base64:[]
        }
    }
    componentDidMount(){
        // 移动拖着不放事件
        document.addEventListener("dragover",function(e){
            console.log("拖着不放事件!");
            e.preventDefault();
        });
        // 移动拖着放下事件
        document.addEventListener("drop",function(e){
            console.log("拖着放下事件!");
            e.preventDefault();
        });
    }
    render() {
        return (
            <div className = "box" onDrop = {(e)=>{
                // 这是个对象e.dataTransfer.files
                console.log(e.dataTransfer.files.length)
                // 拿到所有图片的地址,把他们放到数组里面好进行下步操作
                this.setState({
                    arr : [...e.dataTransfer.files]
                },()=>{
                    console.log(this.state.arr);
                    // 这步把所有的图片全部变成base64地址格式
                    // 为图片预览提供准备
                    this.state.arr.map(item => {
                        let file = item;
                        // HTML的新特性可以把图片变成base64地址
                        let fr = new FileReader();
                        fr.readAsDataURL(file);
                        fr.onload = (_e)=>{
                            this.setState({
                                base64 : [...this.state.base64,_e.target.result]
                            })
                        }
                    })
                })
            }}>
            {/*这是个加号*/}
            <Icon  onClick = {()=>{
                // 虚拟表单事件,用来打开文件夹
                let evt = document.createEvent("mouseEvents");
                evt.initMouseEvent("click",false,false);
                this.refs.file.dispatchEvent(evt);
            }} type="plus-circle" style={{ fontSize: '150px',position:"absolute",left:"50%",top:"50%",transform:"translate(-50%,-50%)"}} />
            {/*这是需要被代理的事件*/}
            <input type = "file" ref = "file" hidden multiple />
            {/*base64位的提供的地址进行预览*/}
            {
                this.state.base64.map((item,index) => <img  className = "cur" key = {index} src = {item}/>)
            }
            </div>
        )
    }
}

还有对应的 css 样式:

.box{
    width: 500px;
    height: 300px;
    background-color: #f6f6f6;
    border:1px dashed #343;
    position: relative;
}
.cur{
    width: 100px;
    margin:10px;
}
三、修复一个 bug

这是第二次修改:

上面写的拖拽效果是非常的好。这个 bug 是不是很直观,哈哈哈哈。



解决办法也很简单,去除图片的默认点击事件:

{
    this.state.base64.map((item,index) => <img onMouseDown = {(e)=>{
        e.preventDefault()
    }} className = "cur" key = {index} src = {item}/>)
}

如此,现在放在页面上的图片已经没了鼠标按下的事件,现在任你怎么拖都没效果了。

这是第三次修改:

再次修正错误我发现不是因为图片没去掉默认事件的问题。而是因为代码段多了个...this.state.arr 所以才会导致上面那个 bug 。数组应该时刻保持是新的。

 this.setState({
                    arr : [...this.state.arr,...e.dataTransfer.files]
                }
上一篇 下一篇

猜你喜欢

热点阅读