在 Vue.js 中如何在上传图片之前显示图片?

How to show images before uploading them in Vue.js?

按照 this 教程,我制作了这个组件,它可以一次上传多张图片,并显示要上传的文件名。

效果很好,但我想知道如何显示照片(最好调整到特定的最大宽度)而不是它们的文件名?

      <div v-if="showUploadPhotoModal">
        <transition name="modal">
          <div class="modal-mask">
            <div class="modal-wrapper">

            <div class="modal-dialog" role="document">
                <div class="modal-content">
                    <div class="modal-header"><strong>{{username}}</strong>&nbsp;&nbsp;
                        <h6 class="modal-title">Upload Photos <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-image"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect><circle cx="8.5" cy="8.5" r="1.5"></circle><polyline points="21 15 16 10 5 21"></polyline></svg>
                        </h6>
                        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                        <span aria-hidden="true" @click="showUploadPhotoModal = false">&times;</span>
                        </button>
                    </div>
                    <div class="modal-body">


                        <form @submit.prevent="sendFile" enctype="multipart/form-data">
                              <div class="form-group">
                                  <textarea class="form-control" rows="5" v-model="title" placeholder="Title"></textarea>

                              </div>

                              <div v-if="fileError" class="alert alert-danger">{{message}}</div>


                             <label class="upload-btn"><br>
                             <span>
                               <img class="logo img-responsive" src="../assets/images/upload.png">
                               <br>
                             </span>
                                Upload Files <input multiple type="file" @change="selectFile" ref="files" hidden>
                                 <br>

                             </label>
                            </form>   

                    </div>

                  <div class="field">
                    <div v-for="(file, index) in files"  :key="index" class="row photo-list" >

                      <div class="col-10 col-push-6">
                        <div :class="`text-right ${file.invalidMessage ?'red':'black'}`">{{file.name}} 

                          <span v-if="file.invalidMessage!=''">&nbsp; <small>{{file.invalidMessage}}</small> </span>
                        </div>

                      </div>
                      <div class="col-2">
                        <div class="text-left">
                          <a @click.prevent="files.splice(index, 1);uploadFiles.splice(index, 1)" class="remove-btn"> <strong >&times;</strong></a>
                        </div>
                      </div>
                    </div>

                  </div>

                    <span @click="sendFile" class="btn btn-primary">Send</span>

                </div>
            </div>

            </div>
          </div>
        </transition>
      </div>





 data () {
    return { 
        showUploadPhotoModal: false,
        files: [],
        uploadFiles: [],
        title: "",
        message: "",
        fileError: false,


    }
  },
  methods: {
    selectFile() {
      const files = this.$refs.files.files;
      this.uploadFiles = [...this.uploadFiles, ...files];
  this.files = [
       ...this.files,
       ..._.map(files, file => ({
         name: file.name,
         type: file.type,
         invalidMessage: this.validate(file)

       }))
  ];

},

validate(file) {
  const allowedTypes = ["image/jpeg", "image/png", "image/gif"];
  if(!allowedTypes.includes(file.type)) { 
    return "Not an image"
  }
  return "";
},

sendFile() {
  const formData = new FormData();

  formData.append('title', this.title);
  formData.append('token', this.token);

  _.forEach(this.uploadFiles, file => {
    if(this.validate(file)==="") {
      formData.append('files', file);
    }
  });

  axios.post(this.BASE_URL + "/api/post", formData)
  .then(res => {
    console.log('res data is:', res.data);
    this.files=[];
    this.uploadFiles=[];
    })
  .catch(err => {
    console.log('error is', err.response.data.error)
    this.fileError = true;
    });
}


  },

为了处理这个问题,我从这个布局开始:

<div id="app" v-cloak>
  <input type="file" multiple accept="image/*"
     @change="handleSelects" name="images">
  <div v-for="image in images">
    <img :src="image" class="preview">
  </div>
</div>

我有一个使用@change 的输入标签到运行 每当用户选择一些文件时的方法。在它下面我有一个 v-for 来迭代并提供图像的缩略图。

这里是 JavaScript:

const app = new Vue({
  el:'#app',
  data:{
    images:[]
  },
  methods:{
    handleSelects(e) {
      this.images = [];
      let fileList = Array.prototype.slice.call(e.target.files);
      fileList.forEach(f => {

        if(!f.type.match("image.*")) {
          return;
        }

        let reader = new FileReader();
        let that = this;

        reader.onload = function (e) {
          that.images.push(e.target.result);
        }
        reader.readAsDataURL(f); 
      });
    }
  }
})

所以 handleSelects 做了一些事情。首先,它重置缩略图 (this.images)。然后它查看输入中选择的文件,检查它们是否为图像,并为每个文件设置一个 FileReader。对于每个文件,它都会获取一个数据 url,然后将其添加到该图像数组中,以便可以创建预览。

您可以在此处查看完整的 CodePen:https://codepen.io/cfjedimaster/pen/VqrGQw?editors=1111