ReactJS:在上传之前预览多个图像

时间:2019-04-05 00:59:12

标签: javascript reactjs

我试图在浏览器中预览多个图像,然后再使用ReactJS和FileReader() API将它们上传到服务器。我的问题是,每次我选择一些图像进行预览时,仅显示最后一张图像。

我的代码如下:

class App extends Component {
    constructor(props){
        super(props);
        this.state = {
            id: "upload-photo",
            imageURI: null
        }
    }

    buildImgTag(){
        let imgTag = null;
        if (this.state.imageURI !== null) {
            imgTag = (
                <div className="photo-container">
                    <img className="photo-uploaded" src={this.state.imageURI} alt="Photo uploaded"/>
                </div>
            );
            return imgTag;
        }
    }

    readURI(e){
        if (e.target.files) {
            let filesAmount = e.target.files.length;
            let i;
            for (i = 0; i < filesAmount; i++) {
                let reader = new FileReader();
                reader.onload = function(ev) {
                    this.setState (
                        {
                            imageURI: ev.target.result
                        }
                    )
                }.bind(this);
                reader.readAsDataURL(e.target.files[i]);
            }
        }
    }

    handleChange(e){
        this.readURI(e);
        if (this.props.onChange !== undefined) {
            this.props.onChange(e);
        }
    }

    render() {
        const imgTag = this.buildImgTag();

        return (
            <div className="container">
                <div className="row justify-content-center">

                    <div className="col-md-6">
                        <div className="card">
                            <div className="card-header" style={{backgroundColor: 'rgb(232, 245, 253)', borderTopLeftRadius: '4px', borderTopRightRadius: '4px', display: 'flex', maxHeight: '50vh', minHeight: '25vh', overflow: 'hidden'}}>
                                <div className="avatar">
                                    <img src="http://laratweet.local:8080/images/avatar-default.png" alt="User Avatar" className="user-avatar"/>
                                </div>
                                <div id="textEditor">
                                    <form method="post" action="" encType="multipart/form-data">
                                        <textarea name="" id="richTextArea" placeholder="What's happening?"></textarea>
                                        {imgTag}
                                        <div id="theRibbon">
                                            <div>
                                                <input
                                                    id={this.state.id}
                                                    type="file"
                                                    name=""
                                                    accept="image/gif,image/jpeg,image/jpg,image/png,video/mp4,video/x-m4v"
                                                    title="Add photos or video"
                                                    onChange={this.handleChange.bind(this)}
                                                    multiple
                                                />
                                                <label htmlFor={this.state.id}>
                                                    <figure>
                                                        <svg xmlns="http://www.w3.org/2000/svg" width="30" height="27"
                                                             viewBox="0 0 20 17" className="upload-icon">
                                                            <path
                                                                d="M10 0l-5.2 4.9h3.3v5.1h3.8v-5.1h3.3l-5.2-4.9zm9.3 11.5l-3.2-2.1h-2l3.4 2.6h-3.5c-.1 0-.2.1-.2.1l-.8 2.3h-6l-.8-2.2c-.1-.1-.1-.2-.2-.2h-3.6l3.4-2.6h-2l-3.2 2.1c-.4.3-.7 1-.6 1.5l.6 3.1c.1.5.7.9 1.2.9h16.3c.6 0 1.1-.4 1.3-.9l.6-3.1c.1-.5-.2-1.2-.7-1.5z"/>
                                                        </svg>
                                                    </figure>
                                                    <span className="tooltiptext">Add photos or video</span>
                                                </label>
                                            </div>
                                            <button type="submit" className="tweet">Tweet</button>
                                        </div>
                                    </form>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        );
    }
}

我希望所有选择的图像都可以在浏览器中显示/预览,但是只有最后一张图像可以预览。我在做什么错了?

3 个答案:

答案 0 :(得分:1)

这里的主要问题是您的App组件状态目前只能跟踪一个imageURI。考虑修改state模型,以便可以存储和呈现imageURI数组:

this.state = {
    id: "upload-photo",
    imageArray: [] /* Replace imageURI with an array for multiple images */
}

接下来,您需要更新readURI(),以便它以组件状态存储多个图像。一种方法是使用Promise.all()异步加载图像数组:

readURI(e){
    if (e.target.files) {

        /* Get files in array form */
        const files = Array.from(e.target.files);

        /* Map each file to a promise that resolves to an array of image URI's */ 
        Promise.all(files.map(file => {
            return (new Promise((resolve,reject) => {
                const reader = new FileReader();
                reader.addEventListener('load', (ev) => {
                    resolve(ev.target.result);
                });
                reader.addEventListener('error', reject);
                reader.readAsDataURL(file);
            }));
        }))
        .then(images => {

            /* Once all promises are resolved, update state with image URI array */
            this.setState({ imageArray : images })

        }, error => {        
            console.error(error);
        });
    }
}

最后,您只需要更新buildImgTag()即可呈现多个图像。一种解决方法可能是:

buildImgTag(){

    return <div className="photo-container">
    { 
      this.state.imageArray.map(imageURI => 
      (<img className="photo-uploaded" src={imageURI} alt="Photo uploaded"/>)) 
    }
    </div>
}

此外,here is a jsFiddle显示了实际的文件读取逻辑。 希望有帮助

答案 1 :(得分:1)

Tentei durante um dia to do a resposta do amigo @ Dacre Denny e acabei utilizando aprima linha de suaresolução,bass as respostassãonativas do JavaScript FileReader() 中的示例,请使用示例性的图像作为 base64 数据集,nãotenho certeza ... >

Base64 de uma forma muito的Acabei resolvendo sem转换器“ mais simples ” 总理声明国家

const [files, setFiles] = useState([]);
const [previews, setPreviews] = useState([]);
const [files, setFiles] = useState([]);

...

const handleUpload = (event) => {
const fileList = Array.from(event.target.files);

setFiles(fileList); //Passei o valor de fileList para o State Files

const mappedFiles = fileList.map((file) => ({
  ...file,
  preview: URL.createObjectURL(file),
}));

setPreviews(mappedFiles); };

... Em meu Styled-Component de上传:

<UploadPhoto type="file" id="files" accept="image/*" multiple="true" onChange={(e) => handleUpload(e)} />

最终结局array.Map

if (previews.length > 0) {
  return (
    <FormGroup> //styled-component (div) para organizar os itens do form
      <UploadContainer> //styled-component (div) display: flex para suportar as imagens
        {previews.map((file) => <ImgUpload preview={file.preview} />)} //styled-component 
        //(div) que se repete de acordo com o número de imagens
      </UploadContainer>
    </FormGroup>
  );
}

以渐进图像的形式显示背景图像,作为背景图像,作为重复图像背景重复:不重复,背景尺寸:封面e背景位置:50%50 %

export const ImgUpload = styled.div`
flex-direction: row;
text-align: center;
margin: 10px;
background-image: ${(props) => (props.preview ? `url(${props.preview})` : null)} ;
min-height: 100px;
min-width: 100px;
border-radius: 5px;
background-repeat: no-repeat;
background-size: cover;
background-position: 50% 50%;
margin-right: 5px;
`;

答案 2 :(得分:0)

对于那些正在寻找相同答案的人,有一个更清洁的选项,它不涉及使用javascript以外的其他东西:

HTML:

<!DOCTYPE html>
<html>
    <head>
        <title>File API - FileReader as Data URL</title>
    </head>
    <body>
        <header>
            <h1>File API - FileReader</h1>
        </header>
        <article>
            <label for="files">Select multiple files: </label>
            <input id="files" type="file" multiple/>
            <output id="result" />
        </article>
    </body>
</html>

CSS:

body
{
    font-family: 'Segoe UI';
    font-size: 12pt;
}

header h1
{
    font-size:12pt;
    color: #fff;
    background-color: #1BA1E2;
    padding: 20px;
}
article
{
    width: 80%;
    margin:auto;
    margin-top:10px;
}
.thumbnail
{
    height: 100px;
    margin: 10px;    
}

JAVASCRIPT

window.onload = function()
{

    //Check File API support
    if ( window.File && window.FileList && window.FileReader )
    {
        var filesInput = document.getElementById("files");

        filesInput.addEventListener 
        ( 
            "change", function ( event )
            {
                var files = event.target.files; //FileList object
                var output = document.getElementById ( "result" );

                for ( var i = 0; i< files.length; i++ )
                {
                    var file = files [ i ];

                    //Only pics
                    if ( !file.type.match ( 'image' ) )
                    continue;

                    var picReader = new FileReader();

                    picReader.addEventListener 
                    ( 
                        "load", function ( event )
                        {                    
                            var picFile = event.target;

                            var div = document.createElement ( "div" );

                            div.innerHTML = "<img class='thumbnail' src='" + picFile.result + "'" + "title='" + picFile.name + "'/>";

                            output.insertBefore ( div, null );
                        }
                    );

                   //Read the image
                   picReader.readAsDataURL ( file );
               }                               
           }
        );
    }
    else
    {
        console.log ( "Your browser does not support File API" );
    }
}

http://jsfiddle.net/0GiS0/Yvgc2/

相关问题