【问题标题】:How to enable file upload on React's Material UI simple input?如何在 React Material UI 简单输入中启用文件上传?
【发布时间】:2017-03-28 02:57:28
【问题描述】:

我正在创建一个简单的表单来使用 electron-react-boilerplate 和 redux 表单和材料 ui 上传文件。

问题是我不知道如何创建输入文件字段,因为材料ui不支持上传文件输入。

关于如何实现这一点的任何想法?

【问题讨论】:

标签: reactjs electron react-redux redux-form formsy-material-ui


【解决方案1】:

API 为此目的提供了component

<Button
  variant="contained"
  component="label"
>
  Upload File
  <input
    type="file"
    hidden
  />
</Button>

【讨论】:

    【解决方案2】:

    较新的 MUI 版本:

    <input
      accept="image/*"
      className={classes.input}
      style={{ display: 'none' }}
      id="raised-button-file"
      multiple
      type="file"
    />
    <label htmlFor="raised-button-file">
      <Button variant="raised" component="span" className={classes.button}>
        Upload
      </Button>
    </label> 
    

    【讨论】:

    • 谢谢,这是来自示例here,您还需要为此元素添加样式input: {display: 'none'}
    • 或者只是&lt;input hidden&gt;
    • 您好 - 上传文件后(即,当您突出显示文件并在弹出的表单上单击打开时)会调用 &lt;input /&gt; 上的 onChange 事件,但我的文件不是t 在事件对象的target 属性中可用(或我可以看到的事件对象上的任何属性)。文件在哪里?
    • @jboxxx:文件将在target.files 上(input 元素有一个内置的files 属性,列出了每个选定的文件)
    • 在最新版本中 variant="raised" 已弃用,它需要 ["text","outlined","contained"] 之一
    【解决方案3】:

    您需要使用 组件包装您的输入,并添加 containerElement 属性与 value 'label' ...

    <RaisedButton
       containerElement='label' // <-- Just add me!
       label='My Label'>
       <input type="file" />
    </RaisedButton>
    

    您可以在此 GitHub issue 中阅读更多相关信息。

    编辑:2019 年更新。

    查看@galki的底部答案

    TLDR;

    <input
      accept="image/*"
      className={classes.input}
      style={{ display: 'none' }}
      id="raised-button-file"
      multiple
      type="file"
    />
    <label htmlFor="raised-button-file">
      <Button variant="raised" component="span" className={classes.button}>
        Upload
      </Button>
    </label> 
    

    【讨论】:

    • 如何使用这个文件对象呢? HTML FileReader 似乎不起作用:/ 考虑到,我使用了 &lt;input type='file' onChange='handleFile'&gt; handleFile = file =&gt; { .. }
    • 如果您在 2019 年访问此页面,请查看底部的 @galki 的答案:D
    【解决方案4】:

    这是一个使用 IconButton 使用 v3.9.2 捕获输入(照片/视频捕获)的示例:

    import React, { Component, Fragment } from 'react';
    import PropTypes from 'prop-types';
    
    import { withStyles } from '@material-ui/core/styles';
    import IconButton from '@material-ui/core/IconButton';
    import PhotoCamera from '@material-ui/icons/PhotoCamera';
    import Videocam from '@material-ui/icons/Videocam';
    
    const styles = (theme) => ({
        input: {
            display: 'none'
        }
    });
    
    class MediaCapture extends Component {
        static propTypes = {
            classes: PropTypes.object.isRequired
        };
    
        state: {
            images: [],
            videos: []
        };
    
        handleCapture = ({ target }) => {
            const fileReader = new FileReader();
            const name = target.accept.includes('image') ? 'images' : 'videos';
    
            fileReader.readAsDataURL(target.files[0]);
            fileReader.onload = (e) => {
                this.setState((prevState) => ({
                    [name]: [...prevState[name], e.target.result]
                }));
            };
        };
    
        render() {
            const { classes } = this.props;
    
            return (
                <Fragment>
                    <input
                        accept="image/*"
                        className={classes.input}
                        id="icon-button-photo"
                        onChange={this.handleCapture}
                        type="file"
                    />
                    <label htmlFor="icon-button-photo">
                        <IconButton color="primary" component="span">
                            <PhotoCamera />
                        </IconButton>
                    </label>
    
                    <input
                        accept="video/*"
                        capture="camcorder"
                        className={classes.input}
                        id="icon-button-video"
                        onChange={this.handleCapture}
                        type="file"
                    />
                    <label htmlFor="icon-button-video">
                        <IconButton color="primary" component="span">
                            <Videocam />
                        </IconButton>
                    </label>
                </Fragment>
            );
        }
    }
    
    export default withStyles(styles, { withTheme: true })(MediaCapture);
    

    【讨论】:

    • IconButton 肯定需要 component="span",这就是我所缺少的!
    【解决方案5】:

    这对我有用(“@material-ui/core”:“^4.3.1”):

        <Fragment>
            <input
              color="primary"
              accept="image/*"
              type="file"
              onChange={onChange}
              id="icon-button-file"
              style={{ display: 'none', }}
            />
            <label htmlFor="icon-button-file">
              <Button
                variant="contained"
                component="span"
                className={classes.button}
                size="large"
                color="primary"
              >
                <ImageIcon className={classes.extendedIcon} />
              </Button>
            </label>
          </Fragment>
    

    【讨论】:

      【解决方案6】:

      如果您使用 React 函数组件,并且不喜欢使用标签或 ID,您也可以使用参考。

      const uploadInputRef = useRef(null);
      
      return (
        <Fragment>
          <input
            ref={uploadInputRef}
            type="file"
            accept="image/*"
            style={{ display: "none" }}
            onChange={onChange}
          />
          <Button
            onClick={() => uploadInputRef.current && uploadInputRef.current.click()}
            variant="contained"
          >
            Upload
          </Button>
        </Fragment>
      );
      

      【讨论】:

      • 为我工作 - 如上所述 更简单
      【解决方案7】:

      2020 年 11 月

      使用 Material-UI 和 React Hooks

      import * as React from "react";
      import {
        Button,
        IconButton,
        Tooltip,
        makeStyles,
        Theme,
      } from "@material-ui/core";
      import { PhotoCamera } from "@material-ui/icons";
      
      const useStyles = makeStyles((theme: Theme) => ({
        root: {
          "& > *": {
            margin: theme.spacing(1),
          },
        },
        input: {
          display: "none",
        },
        faceImage: {
          color: theme.palette.primary.light,
        },
      }));
      
      interface FormProps {
        saveFace: any; //(fileName:Blob) => Promise<void>, // callback taking a string and then dispatching a store actions
      }
      
      export const FaceForm: React.FunctionComponent<FormProps> = ({ saveFace }) => {
      
        const classes = useStyles();
        const [selectedFile, setSelectedFile] = React.useState(null);
      
        const handleCapture = ({ target }: any) => {
          setSelectedFile(target.files[0]);
        };
      
        const handleSubmit = () => {
          saveFace(selectedFile);
        };
      
        return (
          <>
            <input
              accept="image/jpeg"
              className={classes.input}
              id="faceImage"
              type="file"
              onChange={handleCapture}
            />
            <Tooltip title="Select Image">
              <label htmlFor="faceImage">
                <IconButton
                  className={classes.faceImage}
                  color="primary"
                  aria-label="upload picture"
                  component="span"
                >
                  <PhotoCamera fontSize="large" />
                </IconButton>
              </label>
            </Tooltip>
            <label>{selectedFile ? selectedFile.name : "Select Image"}</label>. . .
            <Button onClick={() => handleSubmit()} color="primary">
              Save
            </Button>
          </>
        );
      };
      
      

      【讨论】:

        【解决方案8】:

        您可以使用 Material UI 的 Input 和 InputLabel 组件。这是一个示例,如果您使用它们来输入电子表格文件。

        import { Input, InputLabel } from "@material-ui/core";
        
        const styles = {
          hidden: {
            display: "none",
          },
          importLabel: {
            color: "black",
          },
        };
        
        <InputLabel htmlFor="import-button" style={styles.importLabel}>
            <Input
                id="import-button"
                inputProps={{
                  accept:
                    ".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel",
                }}
                onChange={onInputChange}
                style={styles.hidden}
                type="file"
            />
            Import Spreadsheet
        </InputLabel>
        

        【讨论】:

          【解决方案9】:

          和应该的一样,只是把按钮组件改成这样的标签

          <form id='uploadForm'
                action='http://localhost:8000/upload'
                method='post'
                encType="multipart/form-data">
              <input type="file" id="sampleFile" style="display: none;" />
              <Button htmlFor="sampleFile" component="label" type={'submit'}>Upload</Button> 
          </form>
          

          【讨论】:

            【解决方案10】:
            <input type="file"
                           id="fileUploadButton"
                           style={{ display: 'none' }}
                           onChange={onFileChange}
                    />
                    <label htmlFor={'fileUploadButton'}>
                      <Button
                        color="secondary"
                        className={classes.btnUpload}
                        variant="contained"
                        component="span"
                        startIcon={
                          <SvgIcon fontSize="small">
                            <UploadIcon />
                          </SvgIcon>
                        }
                      >
            
                        Upload
                      </Button>
                    </label>
            

            确保 Button 具有 component="span",这对我有帮助。

            【讨论】:

              【解决方案11】:

              这里是一个例子:

              return (
                  <Box alignItems='center' display='flex' justifyContent='center' flexDirection='column'>
                    <Box>
                      <input accept="image/*" id="upload-company-logo" type='file' hidden />
                      <label htmlFor="upload-company-logo">
                        <Button component="span" >
                          <Paper elevation={5}>
                            <Avatar src={formik.values.logo} className={classes.avatar} variant='rounded' />
                          </Paper>
                        </Button>
                      </label>
                    </Box>
                  </Box>
                )
              
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2021-07-14
                • 2019-02-27
                • 1970-01-01
                • 2021-02-02
                • 2021-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多