简体   繁体   English

Vuejs:检测计算值的更改事件

[英]Vuejs: Detect Change Event On Computed Value

Goal目标

I want to detect only a change event to searchTerms .我只想检测到searchTerms的更改searchTerms

Problem问题

The watcher currently triggers on each keypress, but I don't want that many events.观察者当前在每次按键时触发,但我不想要那么多事件。

Context ( View Fiddle )上下文(查看小提琴

<template>
<div id="app">
  <table class="table">
    <tr>
      <td><label>Name</label></td>
      <td><input class="form-control" v-model="customer.name" autofocus></td>
    </tr>
    <tr>
      <td><label>Short Code</label></td>
      <td><input class="form-control" v-model="customer.shortCode"></td>
    </tr>
    <tr>
      <td><label>Address</label></td>
      <td><input class="form-control" v-model="customer.address"></td>
    </tr>
    <tr>
      <td><label>Caller</label></td>
      <td><input class="form-control" v-model="customer.caller"></td>
    </tr>
    <tr>
      <td><label>Phone</label></td>
      <td><input class="form-control" v-model="customer.phone"></td>
    </tr>
  </table>

  <div class="models">
    <pre><strong>customer:</strong> {{ customer | json }}</pre>
    <pre><strong>searchTerms:</strong> {{ searchTerms | json }}</pre>
  </div>
</div>
</template>

<script>
new Vue({
  el: '#app',
  data: {
    customer: {
      name: 'Donnie',
      phone: '',
      caller: '',
      address: '',
      shortCode: 'DO'
    }
  },

  computed: {
    searchTerms: function() {
      let terms = {};

      _.forOwn(this.customer, (value, key) => {
        if (value.length >= 3) {
          terms[key] = value;
        }
      });

      return terms;
    }
  },

  watch: {
    'searchTerms': function() {
      if (_.isEmpty(this.searchTerms)) {
        return;
      }

      alert('searchTerms Changed');
    }
  }
});
</script>

You can use debounce for this, which is provided by lodash .您可以为此使用debounce ,它由lodash提供。 It Creates a debounced function that delays invoking func until after wait milliseconds have elapsed since the last time the debounced function was invoked.它创建一个 debounced 函数,该函数延迟调用 func 直到自上次调用 debounced 函数后等待毫秒过去。 Debouncing is used to limit how often we execute Ajax requests and other expensive operations去抖动用于限制我们执行 Ajax 请求和其他昂贵操作的频率

You can add the things you want to not call that often in a separate method, and call those actions inside a _.debounce , like following:您可以在单独的方法中添加您不想经常调用的内容,并在_.debounce中调用这些操作,如下所示:

  methods: {
    // This is where the debounce actually belongs.
    expensiveOperation: _.debounce(function () {
      this.isCalculating = true
      setTimeout(function () {
                alert('searchTerms Changed');
      }.bind(this), 1000)
    }, 500)
  }

You can change the delay in setTimeout as par your requirement.您可以根据您的要求更改setTimeout中的延迟。

Find updated fiddle here .在这里找到更新的小提琴。

The computed property searchTerms creates a new object every time it runs.计算属性searchTerms每次运行时都会创建一个新对象 This means that the reference to searchTerms changes, causing the watcher to fire.这意味着对searchTerms的引用发生了变化,导致观察者被触发。

You only want the watcher to fire if one of the values has changed.您只希望观察者在其中一个发生变化时触发。 The easiest way to do this is to watch a stringified version of searchTerms , rather than the object.最简单的方法是查看searchTerms的字符串化版本,而不是对象。

Here is the updated fiddle: https://jsfiddle.net/qLzu0seq/5/这是更新的小提琴: https ://jsfiddle.net/qLzu0seq/5/

And here is the code as a snippet (it's nice to keep code in stackoverflow, rather than an external site):这是代码片段(将代码保存在 stackoverflow 中而不是外部站点中很好):

 new Vue({ el: '#app', data: { customer: { name: 'Donnie', phone: '', caller: '', address: '', shortCode: 'DO' } }, computed: { searchTerms: function() { let terms = {}; _.forOwn(this.customer, (value, key) => { if (value.length >= 3) { terms[key] = value; } }); return terms; }, searchTermsStringified: function() { return JSON.stringify(this.searchTerms); } }, watch: { 'searchTermsStringified': function() { if (_.isEmpty(this.searchTerms)) { return; } alert('searchTerms Changed'); } } });
 <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.4/vue.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.2/lodash.js"></script> <div id="app"> <table class="table"> <tr> <td><label>Name</label></td> <td><input class="form-control" v-model="customer.name" autofocus></td> </tr> <tr> <td><label>Short Code</label></td> <td><input class="form-control" v-model="customer.shortCode"></td> </tr> <tr> <td><label>Address</label></td> <td><input class="form-control" v-model="customer.address"></td> </tr> <tr> <td><label>Caller</label></td> <td><input class="form-control" v-model="customer.caller"></td> </tr> <tr> <td><label>Phone</label></td> <td><input class="form-control" v-model="customer.phone"></td> </tr> </table> <div class="models"> <pre><strong>customer:</strong> {{ JSON.stringify(customer,null,2) }}</pre> <pre><strong>searchTerms:</strong> {{ JSON.stringify(searchTerms,null,2) }}</pre> </div> </div>

You can check if the value has changed directly in the computed property function.您可以直接在计算的属性函数中检查值是否已更改。
Since you are generating objects you need to use _.isEqual method in order to test if the value has changed.由于您正在生成对象,因此您需要使用_.isEqual方法来测试值是否已更改。 You will also need to store the previous value for comparison.您还需要存储之前的值以进行比较。

 new Vue({ el: '#app', data: { customer: { name: 'Donnie', phone: '', caller: '', address: '', shortCode: 'DO' }, previousSearchTerms: null }, computed: { searchTerms: function() { let terms = {}; _.forOwn(this.customer, (value, key) => { if (value.length >= 3) { terms[key] = value; } }); if (this.previousSearchTerms && !_.isEqual(terms, this.previousSearchTerms)) { alert('I was changed !'); } this.previousSearchTerms = terms; return terms; } } });
 label { font-weight: bold; } .models { background: #eee; margin: 1rem; padding: 1rem; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.2/lodash.min.js"></script> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.5/css/bootstrap.min.css" /> <div id="app"> <table class="table"> <tr> <td><label>Name</label></td> <td><input class="form-control" v-model="customer.name" autofocus></td> </tr> <tr> <td><label>Short Code</label></td> <td><input class="form-control" v-model="customer.shortCode"></td> </tr> <tr> <td><label>Address</label></td> <td><input class="form-control" v-model="customer.address"></td> </tr> <tr> <td><label>Caller</label></td> <td><input class="form-control" v-model="customer.caller"></td> </tr> <tr> <td><label>Phone</label></td> <td><input class="form-control" v-model="customer.phone"></td> </tr> </table> <div class="models"> <pre><strong>customer:</strong> {{ customer | json }}</pre> <pre><strong>searchTerms:</strong> {{ searchTerms | json }}</pre> </div> </div> <script src="//cdnjs.cloudflare.com/ajax/libs/vue/1.0.12/vue.js"></script>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM