如何在保持引用函数外部变量的能力的同时从嵌套组件发出

How to emit from a nested component while maintaining ability to reference variables outside of function

我正在尝试构建一个图像上传应用程序,它将图像上传到 firebase 存储,一路跟踪上传百分比,并在上传时更新图库以显示所有图像,包括新上传的图像。

我开始构建用于上传和跟踪上传进度的组件。但是,它不起作用,因为 onUpload() 方法无法更改 this.uploadPercentage 的值。

<template>
  <v-container style="height: 100%;">
      <v-row
        align-content="center"
        justify="center"
      >
        <h1>Image Uploader</h1>
      </v-row>
      <v-row
        align-content="center"
        justify="center"
      >
        <v-col cols="6">
          <v-progress-linear
            color="deep-purple accent-4"
            rounded
            height="6"
            :value="uploadPercentage"
            id="uploader"
          ></v-progress-linear>
        </v-col>
      </v-row>
      <v-row
        align-content="center"
        justify="center"
      >
        <v-col
          class="align-content-center"
          cols="4"
        >
          <v-file-input
            v-model="file"
            accept="image/*"
            label="choose an image"
            outlined
            @change="onFileChange"
            ></v-file-input>
        </v-col>
        <v-col
          class="align-content-center mt-2"
          cols="2"
        >
          <v-btn
            @click="onUpload"
          >
            Upload
            <v-icon right dark>mdi-cloud-upload</v-icon>
          </v-btn>
        </v-col>
      </v-row>
    </v-container>
</template>

<script>
import firebase from '@/firebase/init'

export default {
  data: () => ({
    file: null,
    imageURL: null,
    uploadPercentage: 0
  }),
  methods: {
    onFileChange () {
      let reader = new FileReader()
      reader.onload = () => {
        reader.imagUrl = reader.result
      }
      reader.readAsDataURL(this.file)
    },
    onUpload () {
      // create a firebase storage ref
      var storageRef = firebase.storage().ref('public_wall/' + this.file.name)

      // upload file
      var task = storageRef.put(this.file)

      // update progress bar
      task.on('state_changed',
        function (snapshot) {
          console.log('uploading')
          var percentage = (snapshot.bytesTransferred / snapshot.totalBytes) * 100
          this.uploadPercentage = percentage
        },

        function error (err) {
          console.log(err)
        },

        function completed () {
          console.log('upload complete')
        }

      )
    }
  }
}
</script>

我发现这是因为函数的范围,并且将 task.on() 中的快照函数更改为箭头函数我能够解决这个问题。

task.on('state_changed',
        snapshot => {
          console.log('uploading')
          var percentage = (snapshot.bytesTransferred / snapshot.totalBytes) * 100
          this.uploadPercentage = percentage
        },

但是,我希望这个组件是一个嵌套组件,并在上传完成时发出一个信号。为此,我尝试将 task.on() 中的已完成函数更改为以下内容:

function completed () {
          console.log('upload complete function')
          this.$emit('upload-complete', 'hello')
        }

这会抛出错误:TypeError: this.$emit is not a function。

通过一些研究我发现你不能在箭头函数中引用this.$emit,但是,完成的函数不是箭头函数,将快照函数改回非箭头并不能解决问题,只是停止了上传百分比跟踪器的工作。

我哪里做错了,我该如何解决这个问题?

是因为 This 引用了已完成函数中的其他内容。你可以这样做

onUpload () {
  let _self = this // saving reference to this
  // create a firebase storage ref
  var storageRef = firebase.storage().ref('public_wall/' + this.file.name)

  // upload file
  var task = storageRef.put(this.file)

  // update progress bar
  task.on('state_changed',
    function (snapshot) {
      console.log('uploading')
      var percentage = (snapshot.bytesTransferred / snapshot.totalBytes) * 100
      this.uploadPercentage = percentage
    },

    function error (err) {
      console.log(err)
    },

    function completed () {
      _self.$emit('upload-complete', 'hello')
      // accessing that reference using closure
    }

  )
}