【问题标题】:Vue2: passing function as prop triggers warning that prop is already setVue2:传递函数作为道具触发警告道具已设置
【发布时间】:2018-11-23 23:47:15
【问题描述】:

我是 Vue 的新手,到目前为止我很喜欢单文件组件。

在制作我真正想做的东西之前,我想我会尝试一些小事情,看看我是否掌握了这个概念。

所以我开始制作一个用于打开 XMLHttpRequest 的组件,带有一个进度条。

<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>

index.html

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

用JS

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

而且效果还不错……

但是,有一些小错误我一生都无法弄清楚:

  • 我想定义一个函数 onSuccess 并传递给 prop success,但这会从 Vue 中引发错误
  • statusTooltip 的计算属性未更新
  • 无论我如何尝试绑定,尝试设置 automaticCloseQ 都会导致默认值

例如

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

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

我错过了什么?

【问题讨论】:

    标签: javascript vue.js vuejs2


    【解决方案1】:

    希望这会有所帮助。

    我想定义一个函数 onSuccess 传递给 props 成功,但这会从 Vue 引发错误

    您在 Vue 之外定义 onSuccess。应该是在 Vue 的methods中定义的


    statusTooltip 的计算属性没有得到更新

    在 Javascript 中,对象是通过引用传递的。 xhr 总是引用同一个对象。这就是计算值不会更新的原因。见https://vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats。解决它的一种方法是使用另一个名为 xhrStatus 的反应数据并在 xhr 的事件侦听器中手动更新此状态。


    无论我如何尝试绑定,尝试设置 automaticCloseQ 都会导致默认值

    (我不知道这是什么意思...)

    【讨论】:

    • 所以没有办法将在 Vue 之外定义的任意命名的函数作为道具传递给 Vue,除非在 vue 内部有相同的任意名称?这看起来很傻...如果我想要 3 个实例,其函数为 onSuccessCallback1onSuccessCallback2onSuccessCallback3,该怎么办?那我就不能泛化我的组件了?
    • 我想为组件automaticCloseQ 的行为添加一个切换按钮,它可以在成功传输后自动删除元素(不是 vue 实例),或者在关闭时显示 vue 实例按钮。我定义了一个默认为 false 的布尔 prop(无论如何它都是布尔值),然后尝试了 :automaticCloseQ="true" 并且无论如何(例如 v-bind,没有 : 等)我无法得到 automaticCloseQ设置为真
    猜你喜欢
    • 2018-03-05
    • 2018-11-05
    • 1970-01-01
    • 2018-11-24
    • 2019-11-05
    • 2022-08-12
    • 2019-12-01
    • 1970-01-01
    相关资源
    最近更新 更多