【问题标题】:computed function runs in one component but not in another计算函数在一个组件中运行,但不在另一个组件中运行
【发布时间】:2018-10-19 06:29:09
【问题描述】:

我在一个页面上有多个组件,我发现对父对象的更新会反映在其中一个组件中,而不会反映在另一个组件中。

主页PatientEditor.vue 包含以下组件:

                <notes-editor v-model="pt" />
                <chart-completion v-model="pt" arrange="horiz" />

并且有这个脚本:

module.exports = {
  props: ["pt"]
};

所以,pt 对象在父对象中,它作为v-model 传递给多个组件

组件ChartCompletion.vue 运行良好。里面有这些。

module.exports = {
  props: ["value", "arrange"],

  computed: {
    completed_notes: function() {
      return this.value.notes.filter(function(note) {
        return note.signed_at;
      }).length;
    },

不过,我的问题孩子是 NotesEditor.vue 模板,其中包含以下内容:

module.exports = {
  props: ["value"],

  computed: {
    completed_notes: function() {
      return this.value.notes.filter(function(note) {
        return note.signed_at;
      }).length;
    }
  },

不确定它是否重要,但 notes 对象是从另一个组件中的 ajax 调用填充的,如下所示:

      this.value.notes.splice(0, this.value.notes.length, ...response.body.notes);
      this.$emit("input", this.value);

太好了,问题来了。

this.value.notes 更新时,结果会在ChartCompletion 组件中看到,但在NotesEditor 组件中看不到。当我在 chrome 中使用 Vue 调试器时,我可以看到 notes 对象已更改,但由于某种原因,计算属性不会重新触发,即使它在 ChartCompletion 组件中具有相同的定义。另外,我在NotesEditor 中有一个v-for,它也不会改变。

调试此问题的最佳方法是什么?

EDIT 1 -- 包括NotesEditor 组件

<template>
  <span>
    <table class="table">
      <thead>
        <tr>
          <th>Date</th>
          <th>Status</th>
          <th>Audio</th>
          <th>Text</th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="n in value.notes" :key="n.id">
          <th>{{n.created_at}}</th>
          <td>{{n.note_status_id}}</td>
          <td>
            <span v-if="n.audio_length > 0">
              <audio controls="controls" preload="none">
                <source :src="audioURL(n.id)" type="audio/webm"> Your browser does not support the audio element.
              </audio>
              ({{n.audio_length}}s)
            </span>
            <span v-else>
              None
            </span>
          </td>
          <td>
            <span v-if="n.note_text">
              <button data-toggle="tooltip" :title="n.note_text" class="btn btn-outline-primary btn-sm" @click.prevent="openChartEditor(n.id)">
                <span class="glyphicon glyphicon-edit"></span> Edit Note ({{ n.note_text.length }} chars)
              </button>
            </span>
            <span v-else>
              <button class="btn btn-primary btn-sm" @click.prevent="openChartEditor(n.id)">
                <span class="glyphicon glyphicon-pencil"></span> Create Note
              </button>
            </span>
          </td>
        </tr>
        <tr>
          <td colspan="3">
            <record v-model="value" />
          </td>
          <td>
            <button class="btn btn-primary" @click.prevent="openChartEditor(0)">
              <span class="glyphicon glyphicon-pencil"></span> Create Note
            </button>
          </td>
        </tr>
      </tbody>
    </table>
  </span>
</template>


<script>
module.exports = {
  props: ["value"],

  data: function() {
    return {
      sendFaxWorking: false
    };
  },

  computed: {
    completed_notes: function() {
      return this.value.notes.filter(function(note) {
        return note.signed_at;
      }).length;
    }
  },

  methods: {
    audioURL: function(id) {
      return "/notes/getAudio/" + id;
    },

    openChartEditor: function(id) {
      this.$root.$emit("showEditor", id);
    }
  }
};
</script>

<style>
audio {
  vertical-align: middle;
  border: 0;
  margin: 0;
}
</style>

【问题讨论】:

  • 你的v-for 使用了一些:key= 吗? AFAIK this.value.notes.splice( 也改变了道具,而是创建一个新的道具然后你 $emit
  • 两个组件中是否实际使用了计算属性?它们是惰性求值的,因此只有在需要时才会更新
  • 实际上我无法重现您的问题(快速尝试jsfiddle.net/maxsinev/dp86Lzyu),但我可以对您的代码说的是 - 不要更改this.value.notes(因为它是一个道具字段!)子组件,您需要另一个组件,其中notes 将分别作为v-model 传递,您应该执行类似this.$emit('input', response.body.notes) 的操作。或者你可以使用 Vuex 来避免使用 props 的深度嵌套和代码重复。
  • @birdspider - v-for 确实使用了 :key 并且它第一次可以正常工作。它只是不更新​​;根据vuejs.org/v2/guide/list.html#Array-Change-Detection,看来 splice 是一个包装函数,应该引起通知。事实上,它确实在ChartCompletion 组件中通知,只是不在NotesEditor 组件中。
  • @mankowitz 是的,它不一样,但value 包含notes。您通过引用子组件传递value,作为最佳实践,您不应更改道具(或道具本身)的内部值。老实说,$emit 在你的情况下什么都不做,这表明存在一些不一致,例如,你可以删除 $emit,它会像以前一样工作(你可以在我上面的小提琴中尝试)。

标签: javascript vue.js vuejs2 vue-component


【解决方案1】:

我认为这不是一个好的答案,但它确实有效。我添加了一个调用 $forceUpdate()

的 watcher 函数
  mounted: function() {
    this.$watch("value.notes", this.$forceUpdate);
  },

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-04
    • 1970-01-01
    • 1970-01-01
    • 2012-09-28
    • 2014-01-21
    • 1970-01-01
    相关资源
    最近更新 更多