Vue2: passing function as prop triggers warning th

2019-02-25 17:40发布

I am new to Vue and I am so far enjoying the Single File Components.

Prior to making what I really want to make, I figured I would try some small things to see if I grasp the concept.

So I set off to make a component for opening an XMLHttpRequest, with a progress bar.

enter image description here

<template >
  <div  v-if="showQ">
    <div class="text-muted">
      <span>{{humanReadableLead}}</span>
      <span :class="'text-'+color">{{humanReadableMessage}}</span>
      <span>{{humanReadableEnd}}</span>
    </div>
    <div class="progress">
      <div
        class="progress-bar progress-bar-striped progress-bar-animated"
        :class="'bg-'+color"
        role="progressbar"
        :style="{width: String(percent)+'%'}"
        :aria-valuenow="percent"
        aria-valuemin="0"
        aria-valuemax="100"
      ></div>
    </div>

    <div class="text-right text-muted form-text text-small">
      <span class="float-left">{{xhrMessage}}</span>
      <span
        class="badge"
        :class="'badge-'+color"
        data-toggle="tooltip"
        data-placement="right"
        :title="readyStateTooltip"
        >
          {{xhr.readyState}}
        </span>
      <span
        class="badge"
        :class="'badge-'+color"
        data-toggle="tooltip"
        data-placement="right"
        :title="statusTooltip"
      >
        {{xhr.status}}
      </span>
      <span
        v-if="transferComplete"
        @click="goodbye"
        class="badge badge-secondary"
        data-toggle="tooltip"
        data-placement="right"
        title="Dismiss progress bar"
      >
        &times;
      </span>
    </div>
  </div>

</template>

<script>

import {httpStatusCodes, httpReadyStateCodes} from './http-responses';

export default {
  props: {
    method: {
      type: String,
      default: "GET",
      validator: function(value) {
        return ["GET", "POST", "PUT", "DELETE"].includes(value)
      }
    },
    url: {
      type: String,
      required: true
    },
    async: {
      type: Boolean,
      default: true
    },
    success: {
      type: Function,
      default: function() {
        console.log(this.xhr.response)
      }
    },
    readystatechange: {
      type: Function,
      default: function(event) {
      }
    },
    automaticCloseQ: {
      type: Boolean,
      default: false
    }
  },
  data: function() {
    return {
      xhr: new XMLHttpRequest(),
      httpStatusCodes:httpStatusCodes,
      httpReadyStateCodes:httpReadyStateCodes,
      color: "primary",
      percent: 0,
      humanReadableLead: "",
      humanReadableMessage: "",
      humanReadableEnd: "",
      xhrMessage: "",
      showQ: true,
      completeQ: false
    }
  },
  computed: {
    readyStateTooltip: function() {
      var rs = this.xhr.readyState,
      rsc = httpReadyStateCodes[rs]
      return `Ready state ${rs}: ${rsc}`
    },
    statusTooltip: function() {
      var s = this.xhr.status
      // s = s == 0 ? 218 : s
      var sc = httpStatusCodes[s]
      return `Status ${s}: ${sc}`
    },
    transferComplete: function() {
      return this.completeQ
    }
  },
  methods: {
    open: function() {
      this.xhr.open(this.method, this.url, this.async)
    },
    send: function() {
      this.xhr.send()
    },
    goodbye: function() {
      this.showQ = false
    }
  },

  created: function() {
    var that = this
    that.open()

    that.xhr.addEventListener("error", function(event) {
      that.color = "danger"
      that.xhrMessage = "An error has occured."
    })

    this.xhr.addEventListener("progress", function(event) {
      if (event.lengthComputable) {
        var percentComplete = event.loaded / event.total * 100;
        that.percent = percentComplete
      } else {
        that.percent = 100
        that.xhrMessage = "Unable to compute progress information since the total size is unknown."
      }
    })

    that.xhr.addEventListener("abort", function(event) {
      that.color = "danger"
      that.xhrMessage = "The transfer has been canceled by the user."
    });

    that.xhr.addEventListener("load", function(event) {
      that.color = "success"
      that.xhrMessage = "Transfer complete."
      that.completeQ = true
      if (that.automaticCloseQ) { that.showQ = false }
      that.success()
    })

    that.xhr.addEventListener("readystatechange", function(event) {
      that.readystatechange(event)
    })

    that.send()
  }
}
</script>

<style scoped>
</style>

and in index.html

<div id="request" style="width:50%;" >
  <http-request :url="'./<some-file>'"/>
</div>

with JS

var progress = new Vue({
  el: '#request',
  components: { httpRequest }
})

and this works fairly nicely...

However, there are a few small bugs that for the life of me I can not figure out:

  • I would like to define a function onSuccess that I pass to the prop success, but this throws an error from Vue
  • the computed properties for statusTooltip does not get updated
  • trying to set automaticCloseQ results in the default value no matter how I try to bind

e.g.

var onSuccess = function() {console.log('here')}

<http-request :url="'./<some-file>'" :success="onSuccess" :automaticCloseQ="true"/>

what am I missing?

1条回答
混吃等死
2楼-- · 2019-02-25 18:25

Hope this helps.

I would like to define a function onSuccess that I pass to the prop success, but this throws an error from Vue

You are defining onSuccess outside of Vue. It should be defined in Vue's methods


the computed properties for statusTooltip does not get updated

In Javascript, an object is passed by reference. xhr always reference the same object. That's why the computed value won't update. See https://vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats . 1 way to solve it is to have another reactive data called xhrStatus and update this status manually in the xhr's event listeners.


trying to set automaticCloseQ results in the default value no matter how I try to bind

(I dunno what this means...)

查看更多
登录 后发表回答