javascript 在 React 中创建自定义输入类型文件按钮

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/49555806/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 08:37:49  来源:igfitidea点击:

Creating custom Input type file button in React

javascripthtmlreactjscssecmascript-6

提问by Vibhor Sharma

I am trying to create custom <input type="file">upload button with the name of the uploaded file visible on the button itself after the upload, in React. I am creating this as the component. I found it very difficult to create a codepen demo so I am just uploading the code here (sorry for that).

我正在尝试创建自定义<input type="file">上传按钮,上传后在 React 中,上传文件的名称在按钮本身上可见。我正在创建它作为组件。我发现创建 codepen 演示非常困难,所以我只是在这里上传代码(抱歉)。

import React, { Component, PropTypes } from 'react';
import './InputFile.css';

export default class InputFile extends Component {

constructor(props: any)
{
    super(props);
    this.getUploadedFileName = this.getUploadedFileName.bind(this);
}

getUploadedFileName(selectorFiles: FileList, props) {

const { id } = this.props;

;( function ( document, window, index )
{
    var inputs = document.querySelectorAll(`#${id}`);
    Array.prototype.forEach.call( inputs, function( input )
    {
        var label    = input.nextElementSibling,
            labelVal = label.innerHTML;

        input.addEventListener( 'change', function( e )
        {
            var fileName = '';
            if( this.files && this.files.length > 1 )
                fileName = ( this.getAttribute( 'data-multiple-caption' ) || 
'' ).replace( '{count}', this.files.length );
            else
                fileName = e.target.value.split( '\' ).pop();

            if( fileName )
                label.querySelector( 'span' ).innerHTML = fileName;
            else
                label.innerHTML = labelVal;
        });

        // Firefox bug fix
        input.addEventListener( 'focus', function(){ input.classList.add( 
'has-focus' ); });
        input.addEventListener( 'blur', function(){ input.classList.remove( 
'has-focus' ); });
    });
}( document, window, 0 ));
}


render () {

    const { id, text, multiple } = this.props;

    return(
        <div>
            <input id={id} type="file" className="km-btn-file" data-multiple-caption="{count} files selected" multiple={multiple} onChange={ (e, id) => this.getUploadedFileName(e.target.files, id)}></input>
            <label htmlFor={id} className="km-button km-button--primary km-btn-file-label">
                <span>{text}</span>
            </label>
        </div>
    );
}
}

InputFile.propTypes = {
    id: PropTypes.string.isRequired,
    text: PropTypes.string.isRequired,
    multiple: PropTypes.string,
};

I am importing this component in my other file <InputFile id={'input-file'} text={'Upload File'} multiple={'multiple'}/>

我正在我的另一个文件中导入这个组件 <InputFile id={'input-file'} text={'Upload File'} multiple={'multiple'}/>

Here is the CSS code

这是CSS代码

.km-button--primary {
    background-color: #5C5AA7;
    color: #FFFFFF;
}
.km-button {
    border-radius: 3px;
    -webkit-appearance: none;
    border: none;
    outline: none;
    background: transparent;
    height: 36px;
    padding: 0px 16px;
    margin: 0;
    font-size: 14px;
    font-weight: 400;
    text-align: center;
    min-width: 70px;
    transition: all 0.3s ease-out;
}
.km-btn-file {
    width: 0.1px;
      height: 0.1px;
      opacity: 0;
      overflow: hidden;
      position: absolute;
      z-index: -1;
  }
  .km-btn-file-label {
    line-height: 36px;
    cursor: pointer;
  }

The problem I am facing is when I click on the button first time and choose a file to upload it selects the file but does not update the text "Upload File" with the name of the file. But after the click it the second time it works fine. I don't know why that is happening and for that I need help.

我面临的问题是,当我第一次单击按钮并选择要上传的文件时,它会选择该文件,但不会使用文件名更新文本“上传文件”。但是第二次点击它后它工作正常。我不知道为什么会这样,为此我需要帮助。

Thanks.

谢谢。

采纳答案by Nirit Levi

You can use the component 'state' to update your elements.

您可以使用组件“状态”来更新您的元素。

constructor(props: any)
{
  super(props);
  this.state = {message:'some initial message'};
}

and for the onChange event do:

对于 onChange 事件,请执行以下操作:

getUploadedFileName = (e) => {
   let files = e.target.files,
       value = e.target.value,
       message;
   if( files && files.length > 1 ) message = `${files.length} files selected`;
   else                            message = value.split( '\' ).pop();

   if(message) this.setState({...this.state,message});
}

and then in the element just bind the value to the state:

然后在元素中将值绑定到状态:

<div>
   <input id={id} type="file" className="km-btn-file" 
      data-multiple-caption={this.state.message}
      multiple={multiple} 
      onChange={this.getUploadedFileName}>
   </input>
   <label htmlFor={id} className="km-button km-button--primary km-btn-file-label">
       <span>{text}</span>
   </label>
</div>

回答by Tom Johnson

You'll need to bind the text property from props to your state, so in your constructor you'll have to do;

您需要将文本属性从 props 绑定到您的状态,因此在您的构造函数中您必须这样做;

this.state = {...props};

or

或者

this.state = { text: props.text, id: props.id, multiple: props.multiple };

Then calling when you want to update the view value instead of manually setting the innerHtmlon the label yourself; this.setState({text : new value});

然后在想要更新视图值的时候调用,而不是自己手动设置label上的innerHtml;this.setState({text : new value});

And in your render method;

在你的渲染方法中;

const { id, text, multiple } = this.state;

What this does is when you call this.setState, it tells React to re-render your component which then takes the updated values from the state.

当你调用 this.setState 时,它​​会告诉 React 重新渲染你的组件,然后从状态中获取更新的值。