Vue.js - проп синхронизировать не мгновенно - PullRequest
0 голосов
/ 20 сентября 2018

Использование vue.js для синхронизации реквизита между родителем и ребенком.Проблема в том, что синхронизация использует события, и каждый раз, когда я меняю значение, мне приходится ждать $ nextTick, прежде чем значение будет обновлено.Это не идеально, потому что я не хочу ставить $ nextTick каждый раз, когда меняю значение.Есть ли способ, чтобы обновление события / пропуска происходило немедленно?

HTML:

<div id="app">
    <foo inline-template v-bind:bar.sync="bar">
        <div>
            <button v-on:click="handler_button_click">Set to 5</button>
        </div>
    </foo>
    <span>bar: {{bar}}</span>
</div>

JS:

const EVENT_UPDATE_BAR = "update:bar";

Vue.component("foo", {
    props:["bar"],
    computed:{
        _bar:{
            get:function(){
                return this.bar;
            },
            set:function(value){
                //Mutating the prop here solves the problem, but then I get a warning about mutating the prop...
                //this.bar = value;
                this.$emit(EVENT_UPDATE_BAR, value);
            }
        }
    },
    methods:{
        handler_button_click:function(){
            //It seems that $nextTick must run before value is updated
            this._bar = 5;
            //This shows old value - event / prop has not fully propagated back down to child
            alert("bar: " + this._bar);
        }
    }
});

new Vue({
    el:"#app",

    data:{
        bar:1
    }
});

См. Рабочий пример на CodePen: https://codepen.io/koga73/pen/MqLBXg

1 Ответ

0 голосов
/ 20 сентября 2018

Давайте посмотрим на ваш пример.Я добавил наблюдатели для значения свойства bar для родительского и дочернего компонентов и операторов console.log, чтобы отметить различные моменты при передаче данных между двумя компонентами:

const EVENT_UPDATE_BAR = "update:bar";

Vue.component("foo", {
  props:["bar"],
  computed:{
    _bar:{
      get:function(){
          console.log('_bar getter is called')
        return this.bar;
      },
      set:function(value){
          console.log('_bar setter is called')
        this.$emit(EVENT_UPDATE_BAR, value);
      }
    }
  },
  methods:{
    handler_button_click:function(){
      console.log('handler_button_click is called')
      this._bar = 5;
      console.log('this._bar is accessed with value: ', this._bar);
      this.$nextTick(() => {
        console.log('next tick handler is called')			
      })
      console.log('handler_button_click finishes')
    }
  },
  watch: {
    bar() {
      console.log('child bar watcher is called')
    }
  }
});

new Vue({
  el:"#app",
  
  data:{
    bar:1
  },
  watch: {
    bar() {
      console.log('parent bar watcher is called')
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="app">
  <foo inline-template v-bind:bar.sync="bar">
    <div>
      <button v-on:click="handler_button_click">Set to 5</button>
    </div>
  </foo>
  <span>bar: {{bar}}</span>
</div>

Вы заметите, что сначала запускается handler_button_click, а затем методы get и set для вычисленного _bar.Но два наблюдателя для bar не срабатывают до тех пор, пока не завершится функция handler_button_click.Это указывает на то, что значение, передаваемое дочерним вызовом $emit, не обрабатывается родительским компонентом до тех пор, пока не завершится выполнение функции handler_button_click.

Единственный способ, которым Vue обеспечивает ожидание синхронизации свойств родителя и потомка в функции handler_button_click, - это вызов $nextTick, как вы описали.Функция $nextTick будет ожидать выполнения своего обработчика, пока DOM не закончит обновление.Поскольку DOM не завершит рендеринг, пока все изменения данных в родительском и дочернем компонентах не будут разрешены, вы можете быть уверены, что все будет синхронизировано на этом этапе.


Все это говорит,кажется, что вы просто хотите, чтобы дочернее свойство _bar обновлялось сразу после его установки, и вам не обязательно, чтобы значение обновлялось в родительской области сразу.

В этом случае вы могли бы использовать наблюдатели вместо вычисленных методов получения и установки.Таким образом, поскольку свойство потомка не вычисляется, оно будет обновлено немедленно, а свойство родителя будет обновлено после следующего тика.

Вот пример:

const EVENT_UPDATE_BAR = "update:bar";

Vue.component("foo", {
  props: ["bar"],
  data() {
    return {
      value: this.bar,
    };
  },
  methods: {
    handler_button_click() {
      this.value = 5;
      alert("bar: " + this.value);
    }
  },
  watch: {
    value(val) {
      this.$emit(EVENT_UPDATE_BAR, val);
    },
    bar(val) {
      this.value = val;
    }
  }
});

new Vue({
  el: "#app",
  data() {
    return { 
      bar: 1
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="app">
  <foo inline-template v-bind:bar.sync="bar">
    <div>
      <button v-on:click="handler_button_click">Set to 5</button>
    </div>
  </foo>
  <span>bar: {{bar}}</span>
</div>

Обратите внимание, что я изменил имя свойства _bar на value, поскольку свойства с добавлением подчеркивания не могут быть просмотрены как они не передаются на экземпляр Vue .

...