Vueは配列やオブジェクトの変動を検出できない問題の解決

5427 ワード

例を見てみましょう.



  
  vue
  
  


  
  • {{item.name}} {{numbers[index]}}
var vm = new Vue({ el: ".wrap", data: { numbers: [], items: [ {name: 'jjj'}, {name: 'kkk'}, {name: 'lll'}, ] }, methods: { handle: function (index) { // WHY: ,view , console if (typeof(this.numbers[index]) === "undefined" ) { // : 。 // var arr = []; // arr[3]=3; // console.log(arr) //[empty × 3, 3] this.numbers[index] = 1; // this.numbers.splice(index,0,1) // splice , } else { this.numbers[index]++; // this.numbers.splice(index,1,this.numbers[index]++) } // console.log(this.numbers) } } });

実現したい効果はliをクリックしてvmを見ることです.nymbers[index]が存在するか、存在しない場合は1、存在する場合は1を加算します.
クリックした後、数字はviewレイヤで更新されず、console印刷でデータが更新されたことが分かったが、viewレイヤはタイムリーに検出されなかった.
もう一つの変更を見てみましょう.



  
  vue
  
  


  
  • {{item.name}}
var vm = new Vue({ el: ".wrap", data: { // numbers: [], items: [ {name: 'jjj'}, {name: 'kkk'}, {name: 'lll'}, ] }, methods: { handle: function (index) { // , view this.items[index].name += " success"; // console.log(this.numbers) } } });
はここのviewレイヤがタイムリーに更新されるのを見ることができますが、配列のどこに行けばいいのでしょうか.
Vue 2を見てみましょう.0公式のドキュメントの説明:
JavaScriptの制限により、Vueは以下の変動する配列を検出できません.
  • インデックスを使用して直接アイテムを設定する場合、たとえばvm.items[indexOfItem] = newValue
  • 配列の長さを変更すると、例えば、vm.items.length = newLength
  • 第1の問題を解決するために、以下の2つの方法は、vm.items[indexOfItem] = newValueと同じ効果を達成し、同時に状態更新をトリガすることができる.
    // Vue.set
    Vue.set(example1.items, indexOfItem, newValue)
    // Array.prototype.splice
    example1.items.splice(indexOfItem, 1, newValue)

    まだ使えますvm.$set
    インスタンスメソッド、グローバルのみVue.set
    を選択します.
    それともJavaScriptの制限のため、Vueはオブジェクト属性の追加または削除を検出できません:
    var vm = new Vue({
      data: {
        a: 1
      }
    })
    // `vm.a`        
    
    vm.b = 2
    // `vm.b`       

    作成したインスタンスに対して、Vueはルートレベルのレスポンス属性を動的に追加できません.ただし、使用可能Vue.set(object, key, value)
    メソッドネストされたオブジェクトに応答プロパティを追加します.たとえば、次のようになります.
    var vm = new Vue({
      data: {
        userProfile: {
          name: 'Anika'
        }
      }
    })

    既存のオブジェクトに複数の新しいプロパティを割り当てる必要がある場合があります.たとえば、Object.assign()
    または_.extend()
    .この場合、2つのオブジェクトのプロパティで新しいオブジェクトを作成する必要があります.新しいレスポンス属性を追加したい場合は、次のようにしないでください.
    Object.assign(this.userProfile, {
      age: 27,
      favoriteColor: 'Vue Green'
    })
    は、次のようにする必要があります.
    this.userProfile = Object.assign({}, this.userProfile, {
      age: 27,
      favoriteColor: 'Vue Green'
    })

    したがって、上記の例は次のように変更する必要があります.
    
    
    
      
      vue
      
      
    
    
      
    • {{item.name}} {{numbers[index]}}
    var vm = new Vue({ el: ".wrap", data: { numbers: [], items: [ {name: 'jjj'}, {name: 'kkk'}, {name: 'lll'}, ] }, methods: { handle: function (index) { if (typeof(this.numbers[index]) === "undefined" ) { this.$set(this.numbers, index, 1); //(arr,index,newvalue) } else { this.$set(this.numbers, index, ++this.numbers[index]); } } } });
    できました!
    1.17補足------------------------------------------------------------------------------------------------------------
    作成したインスタンスに対して、Vueはルート・レベルのレスポンス・プロパティを動的に追加できません.
    例:
    var vm=new Vue({
        el:'#test',
        data:{
            //data     info   
            info:{
                name:'  '
            }
        }
    });
    // info        
    Vue.set(vm.info,'sex',' ');

    上は正しいやり方ですが、下のやり方は間違っています.
    Vue.set(vm.data,'sex',' ')
    実際には、dataに直接属性を追加することはできませんが、data内のオブジェクトに属性を追加することができます.
    実はvm.dataはundefinedです.