微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

多文件上传和预览图片和视频

如何解决多文件上传和预览图片和视频

我有一个子组件,它有一个隐藏在开槽元素后面的输入字段。父级将提供带槽的点击事件元素,但也会显示文件的预览,并可以在上方删除它们。

我不确定在子/父关系之间工作时如何使用此选择和预览功能

下面是我所得到的,但我现在对去哪里感到困惑。

该插槽用于触发子级中的事件,但在尝试实际按照当前编写的方式呈现事物时,我得到了 "TypeError: Failed to execute 'readAsDataURL' on 'FileReader': parameter 1 is not of type 'Blob'."。 我哪里出错了?

如果您需要更多信息,请告诉我!加油!

注意:我还需要使其与 V-model 兼容,但我目前不知道如何做到这一点。

UploadMediaFiles(子组件)

<template>
  <div class="upload-media-files">
    <input
      id="input-file"
      type="file"
      accept="*"
      multiple
      @change="addMedia"
      class="_add-media-input"
      ref="input"
    />
    <label for="input-file">
      <slot :openFileDialog="openFileDialog">
        <img
          src="https://www.clipartmax.com/png/middle/142-1422132_png-file-svg-upload-file-icon-png.png"
          alt=""
        />
      </slot>
    </label>
  </div>
</template>

<style lang="sass" scoped>
input
  display: none
</style>

<script>
export default {
  name: 'UploadMediaFiles',props: {
    multiple: { type: Boolean },accept: { type: String },},data() {
    return {
      files: [],}
  },computed: {},methods: {
    async addMedia(event) {
      const files = event.target.files || event.dataTransfer.files
      if (!files.length) return
      console.log(`files → `,files)
      this.files.push(files)
      this.$emit('selected',this.files)
    },openFileDialog() {
      this.$refs.input.click()
    },}
</script>

SelectAndPreviewFiles(父组件)

<template>
  <div class="select-and-preview-files">
    <div v-if="selectedFiles">
      <div :key="index" v-for="(selectedFile,index) in selectedFiles">
        <img :src="selectedFile" alt="" />
        <button @click="deleteFile(index)">Delete</button>
      </div>
    </div>
    <!-- <img />
      //OR
      <video /> -->
    <!-- <img :src="selectedFile" alt="" />-->
    <UploadMediaFiles @selected="(files) => selectFiles(files)" v-slot="{ openFileDialog }">
      <button @click="openFileDialog">
        <img
          src="https://upload.wikimedia.org/wikipedia/commons/thumb/a/a1/Circle-icons-upload.svg/1200px-Circle-icons-upload.svg.png"
          alt=""
        />
      </button>
    </UploadMediaFiles>
  </div>
</template>

<style lang="sass" scoped>
img
  width: 20%
  margin: auto
  display: block
  margin-bottom: 10px
</style>

<script>
import UploadMediaFiles from '../atoms/UploadMediaFiles.vue'
export default {
  name: 'SelectAndPreviewFiles',components: {
    UploadMediaFiles,props: {},data() {
    return {
      selectedFiles: [],methods: {
    selectFiles(files) {
      this.selectedFiles.push(files)
      this.previewImage(files)
    },previewImage(files) {
      var vm = this
      for (var index = 0; index < files.length; index++) {
        var reader = new FileReader()
        reader.onload = function (event) {
          const imageUrl = event.target.result
          vm.files.push(imageUrl)
        }
        reader.readAsDataURL(files[index])
      }
    },deleteFile(index) {
      this.selectedFiles.splice(index,1)
    },}
</script>

没有父子关系的 CodePen https://codepen.io/LovelyAndy/pen/gOmYGKO?editors=0001

解决方法

问题是多个选定文件的 input 值是一个 FileList 数组,它本身是一个 File 对象列表。但是,previewImage() 似乎假定该值是一个 File 对象数组。

files[index] 实际上是一个 FileList,它不是 reader.readAsDataURL() 可接受的参数,从而导致错误。

要解决此问题,请迭代数组中的每个 FileList

export default {
  methods: {
    selectFiles(files) {
      this.selectedFiles.push(files);
      this.previewImage(files);
    },previewImage(files) {
      var vm = this
      for (var index = 0; index < files.length; index++) {
        const fileList = files[index]
        fileList.forEach(file => {
          var reader = new FileReader()
          reader.onload = function (event) {
            const imageUrl = event.target.result
            vm.selectedFiles.push(imageUrl)
          }
          reader.readAsDataURL(file)
        })
      }
    },}
}

demo

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。