Check selected file matches accept attribute on an <input> tag

后端 未结 3 1412
隐瞒了意图╮
隐瞒了意图╮ 2021-01-16 00:37

I wish to prevent the user from uploading a file the server will reject from a page with minimal JavaScript on it, ideally without adding any heavy dependencies like jQuery

相关标签:
3条回答
  • 2021-01-16 01:20

    The accepted answer only works when accept is a single value. Also, it doesn't support the multiple attribute. For multiple accept values, comma separated, and multiple files, use the following:

    window.validateFileFormat = function() {
      const valid = [...i.files].every(file => {
        if (!i.accept) {
          return true;
        }
        return i.accept.replace(/\s/g, '').split(',').filter(accept => {
          return new RegExp(accept.replace('*', '.*')).test(file.type);
        }).length > 0;
      });
      alert('Valid: ' + valid);
    }
    

    Fiddle: http://jsfiddle.net/ynj8dsu6/

    0 讨论(0)
  • 2021-01-16 01:23

    You could just perform a RegExp test — the following converts the wildcard in MIME type strings to match RegExp syntax, and tests that against the input file's type:

    ( new RegExp( i.accept.replace( '*', '.\*' ) ) ).test( i.files[ 0 ].type )
    

    Demo here.

    EDIT:

    I eventually found a way to make this functionality seamless with native browser validation behaviour (ie prevent submission for invalid inputs, notify user using native validation warnings), but I'm not exactly sure how the code works or whether it's good practice (I've asked about the stranger parts here). However, this appears to behave as expected, at least in Chrome 31:

    void function enhanceFileInputTypeValidityCheck(){
        var inputPrototype      = document.createElement( 'input' ).constructor.prototype;
        var nativeCheckValidity = inputPrototype.checkValidity;
    
        function validateFileInputType( input ){
            var MIMEtype = new RegExp( input.accept.replace( '*', '.\*' ) );
    
            return Array.prototype.every.call( input.files, function passesAcceptedFormat( file ){
                return MIMEtype.test( file.type );
            } );
        }
        
        function validateInputs(){
            Array.prototype.forEach.call( document.querySelectorAll( 'input, select' ), function callValidation( input ){
                input.checkValidity();
            } );
        }
    
        inputPrototype.checkValidity = function enhancedCheckValidity(){        
            if( this.type === 'file' &&  this.accept && this.files && this.files.length ){
                if( !validateFileInputType( this ) ){
                    this.setCustomValidity( 'Please only submit files of type ' + this.accept );
                    
                    return false;
                }
            }
    
            return nativeCheckValidity.apply( this );
        }
        
        Array.prototype.forEach.call( [ 'change', 'input' ], function bindValidation( event ){
            document.documentElement.addEventListener( event, validateInputs );
        } );
    }();
    

    Demo here (attempt to submit with an invalid file type).

    0 讨论(0)
  • 2021-01-16 01:24

    This one gathers the techniques from the other posts and make it to a short and easy function, working with multiple expressions:

    verifyAccept = function( file-type, accept ) {
        var type-regex = new RegExp( accept.replace( /\*/g, '.\*' ).replace( /\,/g, '|' ) );
        return type-regex.test( file-type );
    }
    

    instead of looping through the splitted accept string it uses regular expression features, just replace , through | which means the single expressions are or'ed.

    0 讨论(0)
提交回复
热议问题