Get file objects

  • Ordinary function mode

    fileInput.addEventListener('change'.function() {
      const files = [...this.files]
    })
    Copy the code
  • Arrow function mode

    fileInput.addEventListener('change'.() = > {
      const files = [...event.target.files]
    })
    Copy the code
  • Matters needing attention

    fileInput.addEventListener('change'.() = > {
      const files = [...event.target.files]
      event.target.value = null
    })
    Copy the code

    After the file is selected, the file name is stored in the value value of the form. If the value does not change before and after the selection, the change event will not be triggered

    When you click unclose the file selection box without selecting any file objects, the Change event is triggered

    In both cases, it is important to clear the value of the form

File type verification

  • HTML attribute mode

    <input type="file" accept=".mp4, .mov">
    <input type="file" accept=".png, .jpg, .jpeg, .gif">
    Copy the code

    Disadvantages: The Accept attribute can be removed from the console, bypassing the limitation

  • The MIME type of the file

    const fileType = Object.assign(Object.create(null), {
      'video': ['video/mp4'.'video/quicktime'].'image': ['image/png'.'image/jpeg'.'image/gif'],})const validFileType = (type, mimeType) = > fileType[type].includes(mimeType)
    const validator = async (type, files) => {
      const result = files.map(file= > validFileType(type, file.type)).every(boolean= > boolean)
      return { valid: result }
    }
    Copy the code

    Disadvantages: Can be tampered with file extensions, circumvent restrictions

  • File header data mode

    const blobToString = async blob => {
      const buffer = await blob.arrayBuffer()
      return [...new Uint8Array(buffer)].map(n= > n.toString(16).toUpperCase().padStart(2.'0')).join(' ')}const fileType = Object.assign(Object.create(null), {
      'isMp4': str= > ['00 00 00 18'.'00 00 00 20'.'00 00 00 1C'].includes(str),
      'isMov': str= > str === '00 00 00 14'.'isJpg': str= > str === 'FF D8 FF E0'.'isPng': str= > str === '89 50 4E 47'.'isGif': str= > str === '47 49 46 38'
    })
    const validFileType = Object.assign(Object.create(null), {
      'video': str= > fileType['isMp4'](str) || fileType['isMov'](str),
      'image': str= > fileType['isJpg'](str) || fileType['isPng'](str) || fileType['isPng'](str) || fileType['isGif'](str)
    })
    const validator = async (type, files) => {
      const result = (await Promise.all(files.map(file= > blobToString(file.slice(0.4)))))
        .map(str= > validFileType[type](str))
        .every(boolean= > boolean)
      return { valid: result }
    }
    Copy the code

    Turn the file header data into hexadecimal characters to prevent tampering with file extensions

Calculates the MD5 value of the file

  • The role of the md5

    As a unique identifier of a file, it prevents the same file from being uploaded repeatedly, thus avoiding wasting bandwidth

  • The sample code

    import BMF from 'browser-md5-file'
    const bmf = new BMF()
    const getFileMd5 = file= > {
      return new Promise((resolve, reject) = > {
        bmf.md5(
          file,
          (err, md5) = > {
            err ? reject(err) : resolve({ metamd5: md5 })
          },
          progress= > {
            console.log('md5 progress number:', progress)
          }
        )
      })
    }
    Copy the code

    The larger the file, the longer it takes

  • Performance optimization

    Worker threads are used for calculation, giving full play to the computing capacity of multi-core CPU

    For knowledge about workers, please pay attention to the subsequent articles

Capture video cover

  • Implementation approach

    Set the video source and video loading duration

    Add a listening event to capture the current frame drawing image on Canvas after the specified frame data is loaded

    Convert the Canvas image to a Blob object

  • The sample code

    const getVideoCover = (file, time = 1, coverWidth = 300) = > {
      return new Promise(resolve= > {
        const element = document.createElement('video')
        // Set the video source and video loading duration
        Object.assign(element, { src: URL.createObjectURL(file), currentTime: time })
        // Add listening event: after the specified frame data is loaded
        element.addEventListener('loadeddata'.function() {
          const { videoWidth, videoHeight } = this
          // Create canvas
          const canvas = document.createElement('canvas')
          // Set the canvas size proportionally to the specified cover width
          Object.assign(canvas, { width: coverWidth, height: coverWidth / videoWidth * videoHeight })
          canvas
            .getContext('2d')
            // Grab the current frame as an image from the video element as the image source
            .drawImage(this.0.0, canvas.width, canvas.height)
          canvas
            // Convert the Canvas image to a file
            .toBlob(blob= > {
              URL.revokeObjectURL(this.src)
              resolve(blob)
              // Display quality can be specified for image/ JPEG and image/webp
            }, 'image/jpeg'.0.95)})})}Copy the code

Generate a universal unique identifier UUID

  • Format a

    Consisting of 32-bit hexadecimal numbers of 8-4-4-4-12, the first numeric value of the third paragraph identifies its version

  • Use third-party libraries

    import { v4 as uuidv4 } from 'uuid'
    uuidv4()  // '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d'
    Copy the code
  • Using native JS generation

    const getUuid = () = > {
      const blobUrl = URL.createObjectURL(new Blob())
      URL.revokeObjectURL(blobUrl)
      return blobUrl.slice(blobUrl.lastIndexOf('/') + 1)}Copy the code

Upload a file

  • Upload to Tencent Cloud COS first

    Refer to official documentation

  • The COS response is then stored on a third-party server