在React上传之前获取图像预览

时间:2016-06-27 09:10:22

标签: javascript jquery reactjs

这里有很多这样的例子,但似乎无法找到任何反应。我设法将vanilla js转换为反应但得到an error

答案看起来很简单所以我在这里做出反应:

getInitialState: function(){
  return{file: []}
},

_onChange: function(){
  // Assuming only image
  var file = this.refs.file.files[0];
  var reader = new FileReader();
  var url = reader.readAsDataURL(file);
  console.log(url) // Would see a path?
  // TODO: concat files for setState
},

render: function(){
 return(
  <div>
    <form>
      <input 
        ref="file" 
        type="file" 
        name="user[image]" 
        multiple="true"
        onChange={this._onChange}/>
     </form>
    {/* Only show first image, for now. */}
    <img src={this.state.file[0} />
  </div>
 )
};

基本上我见过的所有答案都显示了我所拥有的东西。 React应用程序有什么区别吗?

关于答案:

enter image description here

12 个答案:

答案 0 :(得分:23)

没有区别,只需在load事件结束时阅读您的图片。在load end事件处理程序中,只需说明您的状态:

getInitialState: function(){
  return{file: []}
}

_onChange: function(){
  // Assuming only image
  var file = this.refs.file.files[0];
  var reader = new FileReader();
  var url = reader.readAsDataURL(file);

   reader.onloadend = function (e) {
      this.setState({
          imgSrc: [reader.result];
      })
    }.bind(this);
  console.log(url) // Would see a path?
  // TODO: concat files
},

render: function(){
 return(
  <div>
    <form>
      <input 
        ref="file" 
        type="file" 
        name="user[image]" 
        multiple="true"
        onChange={this_onChange}/>
     </form>
    {/* Only show first image, for now. */}
    <img src={this.state.imgSrc} />
  </div>
 )
}

答案 1 :(得分:5)

这是一个简单有效的解决方案,可显示所有选定的图像

Set.unionMany

答案 2 :(得分:3)

扩展到Cels' answer,并避免将createObjectURL设置为@El Anonimo warns about导致内存泄漏,我们可以使用useEffect创建预览并像这样卸载组件后进行清理< / p>

useEffect(() => {
   // create the preview
   const objectUrl = URL.createObjectURL(selectedFile)
   setPreview(objectUrl)

   // free memory when ever this component is unmounted
   return () => URL.revokeObjectURL(objectUrl)
}, [selectedFile])

完整的代码可能看起来像这样

export const ImageUpload = () => {
    const [selectedFile, setSelectedFile] = useState()
    const [preview, setPreview] = useState()

    // create a preview as a side effect, whenever selected file is changed
    useEffect(() => {
        if (!selectedFile) {
            setPreview(undefined)
            return
        }

        const objectUrl = URL.createObjectURL(selectedFile)
        setPreview(objectUrl)

        // free memory when ever this component is unmounted
        return () => URL.revokeObjectURL(objectUrl)
    }, [selectedFile])

    const onSelectFile = e => {
        if (!e.target.files || e.target.files.length === 0) {
            setSelectedFile(undefined)
            return
        }

        // I've kept this example simple by using the first image instead of multiple
        setSelectedFile(e.target.files[0])
    }

    return (
        <div>
            <input type='file' onChange={onSelectFile} />
            {selectedFile &&  <img src={preview} /> }
        </div>
    )
}

答案 3 :(得分:2)

请这对我来说很完美

state = {
  img: logo
}

handleChangeImage = e => {
  this.setState({[e.target.name]: URL.createObjectURL(e.target.files[0])})
}

<input type="file" id="img" name="img" accept="image/*" className="w-100" onChange={this.handleChangeImage}/>

<img src={this.state.img} alt="img"/>

查看链接以获取更多详细信息https://medium.com/@650egor/react-30-day-challenge-day-2-image-upload-preview-2d534f8eaaa

答案 4 :(得分:1)

您可以使用base64并将其结果用于img src。这里我使用的是打字稿,但是您可以对纯JS使用相同的逻辑

(file: Blob):Promise< string | ArrayBuffer | null> => new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = () => resolve(reader.result);
    reader.onerror = error => reject(error);
}),

答案 5 :(得分:0)

有我的解决方案。非常简单易用。

JSX

<form onSubmit={this.onSubmit} >      
      <input
         ref="uploadImg"
         type="file"
         name="selectedFile"
         onChange={this._onChange}
        />
</form>

<img src={this.state.imageUrl} />

功能

  _onChange = (e) => {

    const file    = this.refs.uploadImg.files[0]
    const reader  = new FileReader();

    reader.onloadend = () => {
        this.setState({
            imageUrl: reader.result
        })
    }
    if (file) {
        reader.readAsDataURL(file);
        this.setState({
            imageUrl :reader.result
        })
    } 
    else {
        this.setState({
            imageUrl: ""
        })
    }
}

当然你需要像imageUrl这样的状态,这是我们在jsx中的src。

答案 6 :(得分:0)

我度过了疯狂的时光,试图使其与多个文件一起使用,因此,如果其他任何人都遇到了这个问题,那么您就可以这样做:

const onFileChange = e => {
e.preventDefault();
const filesList = e.target.files;

if (filesList.length === 0) return;
//Spread array to current state preview URLs
let arr = [...data.imagePreviewUrls];
for (let i = 0; i < filesList.length; i++) {
  const file = filesList[i];

  const reader = new FileReader();
  reader.onload = upload => {
    //push new image to the end of arr
    arr.push(upload.target.result);
    //Set state to arr
    setData({
      ...data,
      imagePreviewUrls: arr
    });
  };
  reader.readAsDataURL(file);
}
};

基本上,for循环在第一个onload事件触发之前就已解决,从而在每次迭代时重置状态。要解决此问题,只需在for循环外创建一个数组,然后在加载时将新项目推送到该数组即可。即使用户关闭了文件对话框,并且以后选择上传更多文件,只要状态尚未重置,它都将处理多个文件。

答案 7 :(得分:0)

这是基于@Mohammed的答案以及使用方法的示例

const loadImage = (file: Blob) =>
  new Promise<string>((resolve, reject) => {
    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = () =>
      typeof reader.result === "string" ? resolve(reader.result) : reject(reader.result);
    reader.onerror = error => reject(error);
  });

export const FilePreview: React.FC<{ file: File }> = ({ file }) => {
  const [imageUrl, setImageUrl] = React.useState<string | undefined>(undefined);
  React.useEffect(() => {
    loadImage(file).then(setImageUrl);
  }, [file]);
  return (
    <div>
      {imageUrl && <img src={imageUrl} alt={file.name} />}
      <div>{file.name}</div>
    </div>
  );
};

答案 8 :(得分:0)

尝试多次上传和预览:

import React,{useState} from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';
import IconButton from '@material-ui/core/IconButton';
import PhotoCamera from '@material-ui/icons/PhotoCamera';
 

const useStyles = makeStyles((theme) => ({
  root: {
    '& > *': {
      margin: theme.spacing(1),
    },
  },
  input: {
    display: 'none',
  },
}));

export default function UploadButtons() {
  const classes = useStyles();
  const [files,setFile]=useState([]);
  const handlerFile=(e)=>{    
    console.log(e.target.files);
    
    let allfiles=[]
   for(let i=0;i<e.target.files.length;i++){
    allfiles.push(e.target.files[i]);
   }
    if(allfiles.length>0){
      setFile(allfiles);  
    }
  };
  return (
    <div className={classes.root}>
        {files.map((file, key) => {
                            return (
                                <div key={key} className="Row">
                                    <span className="Filename">
                                        {file.name}
                                        <img src={URL.createObjectURL(file)}  alt={file.name} />
                                    </span>
                                </div>
                            )
                        })}
      <input
        accept="image/*"
        className={classes.input}
        id="contained-button-file"
        multiple
        type="file"
        onChange={handlerFile}
      />
      <label htmlFor="contained-button-file">
        <Button variant="contained" color="primary" component="span">
          Upload
        </Button>
      </label> 
      
  );
}

答案 9 :(得分:0)

 1. image with preview and close button

import React,{useState} from "react";

export default function App() {
  const  [preview,setPreview] = useState([]);

  const maxLength = 3;



  const onSelectFile=(e)=>{
      for (var i=0;i < e.target.files.length;i++){
        arrayofFiles.push(e.target.files[i]);
        
    }
    
  let images = [];
  arrayofFiles.map((e)=>{
  const ImageUrl =  URL.createObjectURL(e);
  images.push(ImageUrl)
      
  })
  setPreview(images)
  }



  const removeImageFromArray=(e)=>{
    const index = e.target.id;
    let newPreview = [...preview];

    newPreview.splice(index,1);
    setPreview(newPreview);
  }
  return (
    <div className="App">
      <h1>Image view and close</h1>
      <input type="file" name="file" multiple onChange={onSelectFile}/>
    {preview.map((img,index)=>
      (
        <div key={index}>
         <img src={img} id={index} alt="pic1" width="250" height="250" />
           <button
              id={index}
              key={index}
              onClick={(e) => {
                removeImageFromArray(e);
              }}
            >
              Close
            </button>

        </div>
      )  
    )}
     </div>
  );
}

答案 10 :(得分:-2)

-构造函数

constructor(props) {
  super(props);
  this.state = {
     imgRef: ""
  };
}

-功能

filePreview(e) {
    const file = e.target.files[0];
    this.setState({
        imgRef: URL.createObjectURL(file)
    });
}

-HTML

<input
   type="file"
   name="photo"
   onChange={this.fileSelectHandler.bind(this)}
/>
<img src={this.state.imgRef} />

答案 11 :(得分:-2)

URL.createObjectURL(文件) 简短而精细的解决方案