Vue.js - नेस्टेड डेटा को ठीक से कैसे देखें


413

मैं यह समझने की कोशिश कर रहा हूं कि कुछ प्रोपर वेरिएशन को कैसे ठीक से देखा जाए। मेरे पास एक पैरेंट घटक (.vue फाइलें) हैं जो एक अजाक्स कॉल से डेटा प्राप्त करते हैं, एक ऑब्जेक्ट के अंदर डेटा डालते हैं और मेरे कार्यान्वयन के सरलीकरण के नीचे, v-for directive के माध्यम से कुछ चाइल्ड घटक रेंडर करने के लिए इसका उपयोग करते हैं:

<template>
    <div>
        <player v-for="(item, key, index) in players"
            :item="item"
            :index="index"
            :key="key"">
        </player>
    </div>
</template>

... तो <script>टैग के अंदर :

 data(){
     return {
         players: {}
 },
 created(){
        let self = this;
        this.$http.get('../serv/config/player.php').then((response) => {
            let pls = response.body;
            for (let p in pls) {
                self.$set(self.players, p, pls[p]);
            }
    });
}

आइटम ऑब्जेक्ट इस प्रकार हैं:

item:{
   prop: value,
   someOtherProp: {
       nestedProp: nestedValue,
       myArray: [{type: "a", num: 1},{type: "b" num: 6} ...]
    },
}

अब, मेरे बच्चे "खिलाड़ी" घटक के अंदर मैं किसी भी आइटम की संपत्ति भिन्नता के लिए देखने की कोशिश कर रहा हूं और मैं उपयोग करता हूं:

...
watch:{
    'item.someOtherProp'(newVal){
        //to work with changes in "myArray"
    },
    'item.prop'(newVal){
        //to work with changes in prop
    }
}

यह काम करता है लेकिन यह मुझे थोड़ा मुश्किल लगता है और मैं सोच रहा था कि क्या यह करने का सही तरीका है। मेरा लक्ष्य हर बार propबदलावों के दौरान कुछ कार्रवाई करना है या myArrayनए तत्वों या मौजूदा लोगों के अंदर कुछ भिन्नता प्राप्त करना है। सभी सुझावों का स्वागत है।


9
बस "item.someOtherProp": function (newVal, oldVal){@ रॉन के रूप में उपयोग का सुझाव दिया।
रीनर

1
@ राइनर यह वही था जो वह सवाल में बचने की कोशिश कर रहा था; यह केवल ES5 सिंटैक्स का उपयोग कर एक ही बात है। वास्तव में एक गणना देखने में कोई अतिरिक्त अतिदेय नहीं है और यह विभिन्न स्थितियों में एक उपयोगी तकनीक है।
क्रेग_ह

1
क्या keysकिसी वस्तु के अंदर बदलाव को देखना संभव है ? उदाहरण:"item.*": function(val){...}
चार्ली

जवाबों:


622

आप उसके लिए एक गहरे द्रष्टा का उपयोग कर सकते हैं :

watch: {
  item: {
     handler(val){
       // do stuff
     },
     deep: true
  }
}

यह अब itemसरणी में वस्तुओं को और सरणी में परिवर्धन (जब Vue.set के साथ प्रयोग किया जाता है ) में किसी भी परिवर्तन का पता लगाएगा । यहाँ एक JSField है: http://jsfiddle.net/je2rw3rs/

संपादित करें

यदि आप शीर्ष स्तर की वस्तु पर हर बदलाव के लिए नहीं देखना चाहते हैं, और बस नेस्टेड वस्तुओं को सीधे देखने के लिए कम अजीब सिंटैक्स चाहते हैं, तो आप बस computedइसके बजाय देख सकते हैं :

var vm = new Vue({
  el: '#app',
  computed: {
    foo() {
      return this.item.foo;
    }
  },
  watch: {
    foo() {
      console.log('Foo Changed!');
    }
  },
  data: {
    item: {
      foo: 'foo'
    }
  }
})

यहाँ JSFiddle: http://jsfiddle.net/oa07r5fw/


2
इस तरह से "हैंडलर" को जब भी किसी प्रोप में बदलाव किया जाएगा, तो मेरा उद्देश्य अलग से हैंडलर को अलग करना है, यह देखने के लिए कि क्या "प्रोप" में खुशी होती है या "someOtherProp" में myArray के भीतर अलग से
प्लास्टिक

9
यदि आप केवल विशिष्ट नेस्टेड वस्तुओं पर परिवर्तन देखना चाहते हैं तो आप जो कर रहे हैं वह ठीक है। यदि आप एक कम अजीब वाक्यविन्यास चाहते हैं तो आप computedइसके बजाय देख सकते हैं : jsfiddle.net/c52nda7x
craig_h

बिल्कुल वही जो मैं देख रहा था, अब यह मुझे बहुत तर्क लगता है: एक गणना की गई संपत्ति बनाएं जो नेस्टेड प्रोप को लौटाए और इसके लिए देखें। Tnx बहुत।
प्लास्टिक

मैं सिर्फ यह जोड़ना चाहता हूं - कि दूसरा विकल्प वास्तव में मूल द्रष्टा से बहुत अलग नहीं है। आंतरिक रूप से एक गणना की गई संपत्ति समारोह में सभी संदर्भित वस्तुओं / मूल्यों पर एक द्रष्टा है जो फ़ंक्शन के परिणाम के लिए एक डेटा-मूल्य निर्धारित करता है। - तो आप शायद केवल एक ही प्रभाव के साथ कोड को थोड़ा और अधिक जटिल बनाते हैं।
फाल्को

22
@ फ़ाल्को मैंने यहाँ एक टिप्पणी में उत्तर खोजा है । peerbolte ने संकेत दिया कि यह घड़ी का नाम एकल उद्धरणों में रखकर किया जा सकता है। मैंने इसका परीक्षण किया है और यह काम करता है। तो इस मामले में यह watch: { 'item.foo' : function(newVal, oldVal) { // do work here }} बहुत चालाक होगा। मैं प्यार करता हूँ Vue!
रॉन सी

436

एक और अच्छा दृष्टिकोण और एक जो थोड़ा अधिक सुरुचिपूर्ण है वह इस प्रकार है:

 watch:{
     'item.someOtherProp': function (newVal, oldVal){
         //to work with changes in someOtherProp
     },
     'item.prop': function(newVal, oldVal){
         //to work with changes in prop
     }
 }

(मैंने यहां टिप्पणी में @peerbolte से इस दृष्टिकोण को सीखा )


47
अधिक सुरुचिपूर्ण तरीके से (सिर्फ एक बिट नहीं): पी। यह Vue.js प्रलेखन में होना चाहिए क्योंकि यह एक सामान्य उपयोग का मामला है। मैं एक समाधान के लिए घंटों से खोज रहा हूं, आपके उत्तर के लिए धन्यवाद।
क्लाउडीयू

11
@ सिम्बा यह दिलचस्प है कि लोगों ने ध्यान नहीं दिया कि यह वही बात है जिसे ओपी ने बचने के लिए कहा है, बस ES5वाक्य रचना में। हम निश्चित रूप से तर्क दे सकते हैं कि ES2015 method definitionखुद बहुत ही सुरुचिपूर्ण नहीं है, लेकिन यह इस तरह के सवाल को याद करता है, जो कि नाम को लपेटने से बचने का तरीका है। मैं अनुमान लगा रहा हूं कि अधिकांश लोग मूल प्रश्न पर चमक रहे हैं, जिसमें पहले से ही उत्तर है, और वास्तव में कुछ ऐसी चीज की तलाश है, जैसा कि आप कहते हैं, बहुत अच्छी तरह से प्रलेखित नहीं किया गया है,
craig_h

1
@craig_h सुपर दिलचस्प बिंदु। मैं मूल रूप से एक नेस्टेड प्रोप को देखने का एक अच्छा तरीका खोजने के लिए घंटों तक शिकार कर रहा था। और यह प्रश्न शीर्षक मेरे द्वारा पाया गया निकटतम प्रश्न था, लेकिन मुझे याद आया कि उसने प्रश्न के शरीर में एक उद्धृत प्रस्ताव सूचीबद्ध किया था, लेकिन उत्तर इतने सुरुचिपूर्ण पाए। मैंने अंत में एक अन्य प्रश्न की टिप्पणी में उद्धृत प्रोप दृष्टिकोण पाया और एसओ पर उद्धृत प्रोप दृष्टिकोण के दस्तावेजीकरण के रूप में इसका उत्तर देने के लिए केवल एक प्रश्न बनाने का प्रलोभन दिया गया। लेकिन यह सवाल ठीक वैसा ही था जैसा कि मेरा शीर्षक था, इसलिए मैंने यहां जवाब जोड़ा। शायद मुझे एक नया प्रश्न बनाना चाहिए था।
रॉन सी

9
@ रोनक यह एक लोकप्रिय प्रश्न है और आपका उत्तर वास्तव में बहुत सारे लोग खोज रहे हैं, इसलिए मुझे लगता है कि यह यहां अच्छी तरह से बैठता है। हम सभी के पास केवल सीमित समय है, और हम में से अधिकांश ने मुश्किल से प्रश्नों को पढ़ा है, इसलिए यह निश्चित रूप से आपके द्वारा दिए गए उत्तर की आलोचना नहीं थी, मैं सिर्फ यह इंगित करने में थोड़ा कठिन हो रहा हूं कि मेरा मूल उत्तर विशिष्ट था सवाल और राय का इरादा नहीं था। मैं वास्तव में "देखने वाले गणना" दृष्टिकोण को पसंद करता हूं, हालांकि, कई लोग कम जटिल "उद्धरण" दृष्टिकोण पसंद करते हैं, जिसे आपने अपने उत्तर में संक्षेप में प्रस्तुत किया है।
क्रेग_ह

10
आधिकारिक दस्तावेज अब इस दृष्टिकोण शामिल हैं
feihcsim

19

VueJs बाल वस्तुओं में गहरी घड़ी

new Vue({
    el: "#myElement",
    data: {
        entity: {
            properties: []
        }
    },
    watch: {
        'entity.properties': {
            handler: function (after, before) {
                // Changes detected. Do work...     
            },
            deep: true
        }
    }
});

8

यदि आप किसी संपत्ति को कुछ समय के लिए देखना चाहते हैं और फिर उसे अन-वॉच करना चाहते हैं?

या लाइब्रेरी चाइल्ड कंपोनेंट प्रॉपर्टी देखना है?

आप "डायनमिक वॉचर" का उपयोग कर सकते हैं:

this.$watch(
 'object.property', //what you want to watch
 (newVal, oldVal) => {
    //execute your code here
 }
)

$watchएक unwatch समारोह जो अगर यह कहा जाता है देख रहा है बंद हो जाएगा देता है।

var unwatch = vm.$watch('a', cb)
// later, teardown the watcher
unwatch()

इसके अलावा आप deepविकल्प का उपयोग कर सकते हैं :

this.$watch(
'someObject', () => {
    //execute your code here
},
{ deep: true }
)

डॉक्स पर एक नज़र डालना सुनिश्चित करें


2
डॉक्स के अनुसार , आपको एक Note that you should not use an arrow function to define a watcher (e.g. searchQuery: newValue => this.updateAutocomplete(newValue)). The reason is arrow functions bind the parent context, so this will not be the Vue instance as you expect and this.updateAutocomplete will be undefined.
वॉकर

7

यहां उल्लेखित नहीं देखकर, लेकिन vue-property-decoratorयदि आप अपनी Vueकक्षा का विस्तार कर रहे हैं तो पैटर्न का उपयोग करना भी संभव है ।

import { Watch, Vue } from 'vue-property-decorator';

export default class SomeClass extends Vue {
   ...

   @Watch('item.someOtherProp')
   someOtherPropChange(newVal, oldVal) {
      // do something
   }

   ...
}

5

जोड़ने का एक अन्य तरीका यह है कि मैं इस समाधान को 'हैक' करता था: मैंने एक अलग computedमान सेट किया जो कि केवल नेस्टेड ऑब्जेक्ट मान को वापस करेगा।

data : function(){
    return {
        my_object : {
            my_deep_object : {
                my_value : "hello world";
            }.
        },
    };
},
computed : {
    helper_name : function(){
        return this.my_object.my_deep_object.my_value;
    },
},
watch : {
    helper_name : function(newVal, oldVal){
        // do this...
    }
}

अच्छा एक;) लेकिन सरणियों के साथ क्या? :)
वेबसेंट

3

उपयोग करने के स्वीकृत उत्तर के साथ मेरी समस्या deep: trueयह है कि जब किसी सरणी को गहराई से देखते हैं, तो मैं आसानी से पहचान नहीं सकता कि सरणी के किस तत्व में परिवर्तन है। एकमात्र स्पष्ट समाधान जो मैंने पाया है, यह उत्तर है, जो बताता है कि एक घटक कैसे बनाया जाए ताकि आप प्रत्येक सरणी तत्व को व्यक्तिगत रूप से देख सकें।


1
हाँ, यह सच है, लेकिन यह नहीं है कि एक गहरी द्रष्टा क्या है (वास्तव में आप पाएंगे oldValऔर newValदोनों एक ही वस्तु को संदर्भित करते हैं, इसलिए समान हैं)। एक करने के इरादे deep watcherके लिए है कुछ करना फेंकना के रूप में एक घटना है, जब मान बदलते हैं, इस तरह के, बनाने के मणि के जवाब में उठाई बाहर के रूप में एक ajax कॉल आदि अन्यथा, आप शायद चाहते हैं एक घटक।
क्रेग_ह

मुझे व्यक्तिगत परिवर्तनों पर नज़र रखने की समान समस्या थी! मुझे हालांकि एक समाधान मिला, और इसे यहां दस्तावेजित किया ।
एरिक कोपामंस

3

किसी सूची में अलग-अलग परिवर्तित आइटम ट्रैक करना

यदि आप किसी सूची में सभी आइटम देखना चाहते हैं और यह जानना चाहते हैं कि सूची में कौन सी वस्तु बदली गई है, तो आप प्रत्येक आइटम पर अलग से कस्टम वॉचर्स सेट कर सकते हैं, जैसे:

var vm = new Vue({
  data: {
    list: [
      {name: 'obj1 to watch'},
      {name: 'obj2 to watch'},
    ],
  },
  methods: {
    handleChange (newVal, oldVal) {
      // Handle changes here!
      // NOTE: For mutated objects, newVal and oldVal will be identical.
      console.log(newVal);
    },
  },
  created () {
    this.list.forEach((val) => {
      this.$watch(() => val, this.handleChange, {deep: true});
    });
  },
});

यदि आपकी सूची सीधे (मूल प्रश्न की तरह) आबाद नहीं है, तो आप तर्क createdको जहाँ कहीं भी आवश्यक हो, .then()ब्लॉक के अंदर स्थानांतरित कर सकते हैं ।

बदलती हुई सूची देखना

यदि आपकी सूची में नए या हटाए गए आइटम होने के लिए अपडेट हैं, तो मैंने एक उपयोगी पैटर्न विकसित किया है जो "उथले" सूची को स्वयं देखता है, और सूची में परिवर्तन के रूप में गतिशील रूप से घड़ियों / अनचेक करता है:

// NOTE: This example uses Lodash (_.differenceBy and _.pull) to compare lists
//       and remove list items. The same result could be achieved with lots of
//       list.indexOf(...) if you need to avoid external libraries.

var vm = new Vue({
  data: {
    list: [
      {name: 'obj1 to watch'},
      {name: 'obj2 to watch'},
    ],
    watchTracker: [],
  },
  methods: {
    handleChange (newVal, oldVal) {
      // Handle changes here!
      console.log(newVal);
    },
    updateWatchers () {
      // Helper function for comparing list items to the "watchTracker".
      const getItem = (val) => val.item || val;

      // Items that aren't already watched: watch and add to watched list.
      _.differenceBy(this.list, this.watchTracker, getItem).forEach((item) => {
        const unwatch = this.$watch(() => item, this.handleChange, {deep: true});
        this.watchTracker.push({ item: item, unwatch: unwatch });
        // Uncomment below if adding a new item to the list should count as a "change".
        // this.handleChange(item);
      });

      // Items that no longer exist: unwatch and remove from the watched list.
      _.differenceBy(this.watchTracker, this.list, getItem).forEach((watchObj) => {
        watchObj.unwatch();
        _.pull(this.watchTracker, watchObj);
        // Optionally add any further cleanup in here for when items are removed.
      });
    },
  },
  watch: {
    list () {
      return this.updateWatchers();
    },
  },
  created () {
    return this.updateWatchers();
  },
});

0

मेरे लिए कोई भी जवाब काम नहीं कर रहा था। दरअसल अगर आप कई बार कॉल किए जा रहे कंपोनेंट्स के साथ नेस्टेड डेटा देखना चाहते हैं। इसलिए उन्हें पहचानने के लिए अलग-अलग सहारा के साथ बुलाया जाता है। उदाहरण के लिए<MyComponent chart="chart1"/> <MyComponent chart="chart2"/> मेरा वर्कअर्ड एक एडिशनल vuex स्टेट वैरिएबल बनाना है, जिसे मैं पिछली बार अपडेट की गई प्रॉपर्टी को इंगित करने के लिए मैन्युअल रूप से अपडेट करता हूं।

यहाँ एक Vuex.ts कार्यान्वयन उदाहरण है:

export default new Vuex.Store({
    state: {
        hovEpacTduList: {},  // a json of arrays to be shared by different components, 
                             // for example  hovEpacTduList["chart1"]=[2,6,9]
        hovEpacTduListChangeForChart: "chart1"  // to watch for latest update, 
                                                // here to access "chart1" update 
   },
   mutations: {
        setHovEpacTduList: (state, payload) => {
            state.hovEpacTduListChangeForChart = payload.chart // we will watch hovEpacTduListChangeForChart
            state.hovEpacTduList[payload.chart] = payload.list // instead of hovEpacTduList, which vuex cannot watch
        },
}

स्टोर को अपडेट करने के लिए किसी भी कंपोनेंट फंक्शन पर:

    const payload = {chart:"chart1", list: [4,6,3]}
    this.$store.commit('setHovEpacTduList', payload);

अब अपडेट प्राप्त करने के लिए किसी भी घटक पर:

    computed: {
        hovEpacTduListChangeForChart() {
            return this.$store.state.hovEpacTduListChangeForChart;
        }
    },
    watch: {
        hovEpacTduListChangeForChart(chart) {
            if (chart === this.chart)  // the component was created with chart as a prop <MyComponent chart="chart1"/> 
                console.log("Update! for", chart, this.$store.state.hovEpacTduList[chart]);
        },
    },
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.