自定义 vue 组件不更新值更改

Custom vue component not updating on value change

我在 https://codepen.io/james-hudson3010/pen/QWgarbr 有一个 codepen,它演示了这个问题。

我正在尝试创建和使用基于 v-btn 和 v-icon 的自定义复选框组件。

当我点击复选框时,我得到了输入事件并且数据发生了变化,但是复选框的外观并没有改变。我确定这是因为我调用的获取值的方法不是“反应性”的。因此,值更改后,不会重新渲染。

我需要调用一个方法来获取该值,因为获取该值可能很复杂,并且要基于单击的框。箱子数量未知。

但是,这里缺少一些基本概念,但我不确定它是什么。

我需要在我的代码中更改什么才能使其工作?

(不,我不想使用 v-checkbox...在某种程度上,这是为了让我自己了解如何创建此类东西。)

Javascript

Vue.component('mybox', {
    props: ['value'],

    data() {
      return  {
        selected: null,
      }
    },
  
    template: `
        <v-btn v-if="value" @click="clicked()" icon dense>
          <v-icon color="#f9a602">check_box</v-icon>
        </v-btn>
        <v-btn v-else @click="clicked()" icon dense>
          <v-icon color="#f9a602">check_box_outline_blank</v-icon>
        </v-btn>
    `,

    methods: {
      clicked() {
        console.log( "clicked", this.selected, this.value );
        this.selected = !this.value;
        console.log( "clicked", this.selected, this.value );
        this.$emit( "input", this.selected );
      }
    },

    watch: {
      selected() {
        console.log("selected:", this.selected);
        // this.$emit("input", this.selected);
      },
  }
});


new Vue({
  el: '#app',
  vuetify: new Vuetify(),
  
  data: {
    boxvalues: [true, false],
  },
  
  methods: {
    boxValueChanged( index ) {
      console.log( "boxValueChanged", index, this.boxvalues[ index ] );
      this.boxvalues[ index ] = !this.boxvalues[ index ];
      console.log( "boxValueChanged", index, this.boxvalues[ index ] );
    },
    
    boxValue( index ) {
      return this.boxvalues[ index ];
    }
  },
})

HTML

<div id="app">
  <mybox v-for="(value, index ) in boxvalues" 
         :value="boxValue( index )" 
         @input="boxValueChanged( index )"
         :key="index"
         :id="index"/>
</div>

你是对的,罪魁祸首是这一行的反应性丧失:

this.boxvalues[index] = !this.boxvalues[ index ];

来自文档:

Vue cannot detect the following changes to an array:

When you directly set an item with the index, e.g. vm.items[indexOfItem] = newValue

When you modify the length of the array, e.g. vm.items.length = newLength

Vue 为这个用例提供了一个简单的解决方案:Vue.set()(或this.$set())方法:

this.$set(this.boxvalues, index, !this.boxvalues[index]);

您可以阅读有关此主题的更多信息here

补充 Igor 所说的内容,您还可以重写整个数组以触发反应性。 例如:

boxValueChanged( index ) {
  const boxvalues = [...this.boxvalues]
  
  boxvalues[index] = !boxvalues[index]
  this.boxvalues = boxvalues
},