单击一个div,打开文件浏览器

时间:2016-05-26 09:43:58

标签: reactjs

我的反应成分:

import React, { PropTypes, Component } from 'react'


class Content extends Component {
    handleClick(e) {
        console.log("Hellooww world")
    }
    render() {
        return (
            <div className="body-content">
                <div className="add-media" onClick={this.handleClick.bind(this)}>
                    <i className="plus icon"></i>
                    <input type="file" id="file" style={{display: "none"}}/>
                </div>
            </div>
        )
    }
}

export default Content

当我点击带有图标的div时,我想打开一个<input>文件,显示我选择照片的选项。选择照片后,我想获取选择照片的值。我怎么能这样做?

9 个答案:

答案 0 :(得分:20)

将ref属性添加到您的输入中:

<input type="file" id="file" ref="fileUploader" style={{display: "none"}}/>

更改handleClick功能:

handleClick(e) {
    this.refs.fileUploader.click();
}

由于您使用的是ES6,因此需要将其绑定到handleClick函数,我们可以在构造函数中执行此操作:

constructor (props) {
  super(props);
  this.handleClick = this.handleClick.bind(this);
}

答案 1 :(得分:9)

其他只是将输入放在您的视图上,您​​将需要处理输入内容的更改。为此,请实现onChange,并获取打开的文件信息,如下所示:

<input id="myInput"
   type="file"
   ref={(ref) => this.upload = ref}
   style={{display: 'none'}}
   onChange={this.onChangeFile.bind(this)}
/>

<RaisedButton
    label="Open File"
    primary={false}
    onClick={()=>{this.upload.click()}}
/>


onChangeFile(event) {
    event.stopPropagation();
    event.preventDefault();
    var file = event.target.files[0];
    console.log(file);
    this.setState({file}); /// if you want to upload latter
}

控制台将输出:

File {
  name: "my-super-excel-file.vcs", 
  lastModified: 1503267699000, 
  lastModifiedDate: Sun Aug 20 2017 19:21:39 GMT-0300 (-03), 
  webkitRelativePath: "", 
  size: 54170,
  type:"application/vnd.vcs"
}

现在你可以像你想的那样使用它。但是,如果你想上传它,你必须从:

开始
var form = new FormData();
form.append('file', this.state.file);

YourAjaxLib.doUpload('/yourEndpoint/',form).then(result=> console.log(result));

答案 2 :(得分:5)

React 16.3使用React.createRef()方法提供了更好的方法。见https://reactjs.org/blog/2018/03/29/react-v-16-3.html#createref-api

打字稿示例:

export class MainMenu extends React.Component<MainMenuProps, {}> {

private readonly inputOpenFileRef : RefObject<HTMLInputElement>

constructor() {
    super({})

    this.inputOpenFileRef = React.createRef()
}

showOpenFileDlg = () => {
    this.inputOpenFileRef.current.click()
}

render() {

    return (
       <div>
                <input ref={this.inputOpenFileRef} type="file" style={{display:"none"}}/>
                <button onClick={this.showOpenFileDlg}>Open</Button>
      </div>
    )
}
}

答案 3 :(得分:3)

<块引用>

所有建议的答案都很棒。我超越并允许用户添加图像并立即预览。我使用了 React 钩子。

感谢大家的支持

结果应如下所示

enter image description here

import React, { useEffect, useRef, useState } from 'react';

// Specify camera icon to replace button text 
import camera from '../../../assets/images/camera.svg'; // replace it with your path

// Specify your default image
import defaultUser from '../../../assets/images/defaultUser.svg'; // replace it with your path

// Profile upload helper

const HandleImageUpload = () => {
  // we are referencing the file input
  const imageRef = useRef();

  // Specify the default image
  const [defaultUserImage, setDefaultUserImage] = useState(defaultUser);
  
  // On each file selection update the default image
  const [selectedFile, setSelectedFile] = useState();

  // On click on camera icon open the dialog
  const showOpenFileDialog = () => {
    imageRef.current.click();
  };

  // On each change let user have access to a selected file
  const handleChange = (event) => {
    const file = event.target.files[0];
    setSelectedFile(file);
  };

  // Clean up the selection to avoid memory leak
  useEffect(() => {
    if (selectedFile) {
      const objectURL = URL.createObjectURL(selectedFile);
      setDefaultUserImage(objectURL);
      return () => URL.revokeObjectURL(objectURL);
    }
  }, [selectedFile]);

  return {
    imageRef,
    defaultUserImage,
    showOpenFileDialog,
    handleChange,
  };
};

// Image component
export const ItemImage = (props) => {
  const {itemImage, itemImageAlt} = props;
  return (
    <>
      <img
        src={itemImage}
        alt={itemImageAlt}
        className="item-image"
      />
    </>
  );
};

// Button with icon component
export const CommonClickButtonIcon = (props) => {
  const {
    onHandleSubmitForm, iconImageValue, altImg,
  } = props;
  return (
    <div className="common-button">
      <button
        type="button"
        onClick={onHandleSubmitForm}
        className="button-image"
      >
        <img
          src={iconImageValue}
          alt={altImg}
          className="image-button-img"
        />
      </button>
    </div>
  );
};

export const MainProfileForm = () => {
  const {
    defaultUserImage,
    handleChange,
    imageRef,
    showOpenFileDialog,
  } = HandleImageUpload();

  return (
    <div className="edit-profile-container">

      <div className="edit-profile-image">
        <ItemImage
          itemImage={defaultUserImage}
          itemImageAlt="user profile picture"
        />
        <CommonClickButtonIcon // Notice I omitted the text instead used icon
          onHandleSubmitForm={showOpenFileDialog}
          iconImageValue={camera}
          altImg="Upload image icon"
        />
        <input
          ref={imageRef}
          type="file"
          style={{ display: 'none' }}
          accept="image/*"
          onChange={handleChange}
        />
      </div>
    </div>
  );
};


我的 CSS

.edit-profile-container {
  position: relative;
}

.edit-profile-container .edit-profile-image {
  position: relative;
  width: 200px;
  display: flex;
  justify-content: center;
}

.edit-profile-container .edit-profile-image .item-image {
  height: 160px;
  width: 160px;
  border-radius: 360px;
}

.edit-profile-container .edit-profile-image .common-button {
  position: absolute;
  right: 0;
  top: 30px;
}

.edit-profile-container .edit-profile-image .common-button .button-image {
  outline: none;
  width: 50px;
  height: 50px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  background: transparent;
}

.edit-profile-container .edit-profile-image .common-button .image-button-img {
  height: 30px;
  width: 30px;
  box-shadow: 0 10px 16px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19);
}

答案 4 :(得分:2)

使用反应钩

上传新答案

首先创建您的Input ref钩子

const inputFile = useRef(null) 

然后将其设置为INPUT并添加要显示的样式:输入内容将不会在屏幕上显示

<input type='file' id='file' ref={inputFile} style={{display: 'none'}}/>

然后创建用于处理打开文件的函数,该函数应位于与 useRef Hook

相同的函数中
 const onButtonClick = () => {
    // `current` points to the mounted file input element
   inputFile.current.click();
  };

然后将功能设置为Button元素

 <button onClick={onButtonClick}>Open file upload window</button>

API for HTML INPUT FILE

答案 5 :(得分:2)

您可以将其包装在标签中,当您单击标签时,它会单击对话框。

    <div>
      <label htmlFor="fileUpload">
        <div>
          <h3>Open</h3>
          <p>Other stuff in here</p>
        </div>
      </label>
      <input hidden id="fileUpload" type="file" accept="video/*" />
    </div>

答案 6 :(得分:1)

如果你可以使用钩子,这个包将解决你的问题,而无需创建输入元素。这个包不呈现任何 html 输入元素。您可以简单地在 div 元素上添加 OnClick。

这是工作演示:https://codesandbox.io/s/admiring-hellman-g7p91?file=/src/App.js

import { useFilePicker } from "use-file-picker";
import React from "react";

export default function App() {
  const [files, errors, openFileSelector] = useFilePicker({
    multiple: true,
    accept: ".ics,.pdf"
  });

  if (errors.length > 0) return <p>Error!</p>;

  return (
    <div>
      <div
        style={{ width: 200, height: 200, background: "red" }}
        onClick={() => openFileSelector()}
      >
        Reopen file selector
      </div>
      <pre>{JSON.stringify(files)}</pre>
    </div>
  );
}

调用 openFileSelector() 打开浏览器文件选择器。

文件属性:

    lastModified: number;
    name: string;
    content: string;

https://www.npmjs.com/package/use-file-picker

我创建这个包是为了解决同样的问题。

答案 7 :(得分:0)

import React, { useRef, useState } from 'react'
...
const inputRef = useRef()
....
function chooseFile() {
  const { current } = inputRef
  (current || { click: () => {}}).click()
}
...
<input
   onChange={e => {
     setFile(e.target.files)
    }}
   id="select-file"
   type="file"
   ref={inputRef}
/>
<Button onClick={chooseFile} shadow icon="/upload.svg">
   Choose file
</Button>

使用next.js对我有用的唯一代码 enter image description here

答案 8 :(得分:0)

我最近想用 Material UI 实现一个类似的功能,这种方法类似于 @Niyongabo 的实现,只是我使用的是 Material UI 框架并利用了 Avatar/Badge 组件。

在使用图像之前,我还调整了图像的大小。

enter image description here

import React, { useEffect, useRef } from "react";
import List from "@material-ui/core/List";
import t from "prop-types";
import { makeStyles } from "@material-ui/core/styles";
import { Avatar, Badge } from "@material-ui/core";
import withStyles from "@material-ui/core/styles/withStyles";
import IconButton from "@material-ui/core/IconButton";
import EditIcon from "@material-ui/icons/Edit";
import useTheme from "@material-ui/core/styles/useTheme";

import("screw-filereader");

const useStyles = makeStyles((theme) => ({
  root: {
    display: "flex",
    "& > *": {
      margin: theme.spacing(1)
    }
  },
  form: {
    display: "flex",
    flexDirection: "column",
    margin: "auto",
    width: "fit-content"
  },
  input: {
    fontSize: 15
  },
  large: {
    width: theme.spacing(25),
    height: theme.spacing(25),
    border: `4px solid ${theme.palette.primary.main}`
  }
}));

const EditIconButton = withStyles((theme) => ({
  root: {
    width: 22,
    height: 22,
    padding: 15,
    border: `2px solid ${theme.palette.primary.main}`
  }
}))(IconButton);

export const AvatarPicker = (props) => {
  const [file, setFile] = React.useState("");
  const theme = useTheme();
  const classes = useStyles();

  const imageRef = useRef();

  const { handleChangeImage, avatarImage } = props;

  useEffect(() => {
    if (!file && avatarImage) {
      setFile(URL.createObjectURL(avatarImage));
    }

    return () => {
      if (file) URL.revokeObjectURL(file);
    };
  }, [file, avatarImage]);

  const renderImage = (fileObject) => {
    fileObject.image().then((img) => {
      const canvas = document.createElement("canvas");
      const ctx = canvas.getContext("2d");
      const maxWidth = 256;
      const maxHeight = 256;

      const ratio = Math.min(maxWidth / img.width, maxHeight / img.height);
      const width = (img.width * ratio + 0.5) | 0;
      const height = (img.height * ratio + 0.5) | 0;

      canvas.width = width;
      canvas.height = height;
      ctx.drawImage(img, 0, 0, width, height);

      canvas.toBlob((blob) => {
        const resizedFile = new File([blob], file.name, fileObject);
        setFile(URL.createObjectURL(resizedFile));
        handleChangeImage(resizedFile);
      });
    });
  };

  const showOpenFileDialog = () => {
    imageRef.current.click();
  };

  const handleChange = (event) => {
    const fileObject = event.target.files[0];
    if (!fileObject) return;
    renderImage(fileObject);
  };

  return (
    <List data-testid={"image-upload"}>
      <div
        style={{
          display: "flex",
          justifyContent: "center",
          margin: "20px 10px"
        }}
      >
        <div className={classes.root}>
          <Badge
            overlap="circle"
            anchorOrigin={{
              vertical: "bottom",
              horizontal: "right"
            }}
            badgeContent={
              <EditIconButton
                onClick={showOpenFileDialog}
                style={{ background: theme.palette.primary.main }}
              >
                <EditIcon />
              </EditIconButton>
            }
          >
            <Avatar alt={"avatar"} src={file} className={classes.large} />
          </Badge>
          <input
            ref={imageRef}
            type="file"
            style={{ display: "none" }}
            accept="image/*"
            onChange={handleChange}
          />
        </div>
      </div>
    </List>
  );
};
AvatarPicker.propTypes = {
  handleChangeImage: t.func.isRequired,
  avatarImage: t.object
};
export default AvatarPicker;

Edit patient-pond-0ech0