如何在更改v-model值时阻止@change事件

问题描述 投票:1回答:2

我正在Firebase支持的Vue.js中构建一个自动完成菜单(使用vue-fire)。目的是开始键入用户的显示名称,并在下面的div列表中显示匹配记录。

模板看起来像这样:

<b-form-input id="toUser"
    type="text"
    v-model="selectedTo"
    @change="searcher">
</b-form-input>

<div v-on:click="selectToUser(user)" class="userSearchDropDownResult" v-for="user in searchResult" v-if="showSearcherDropdown">{{ user.name }}</div>

点击潜在匹配后,目的是设置字段的值并清除匹配列表。

以下是组件的代码部分:

computed: {
  /* method borrowed from Reddit user imGnarly: https://www.reddit.com/r/vuejs/comments/63w65c/client_side_autocomplete_search_with_vuejs/ */
  searcher() {
    let self = this;
    let holder = [];
    let rx = new RegExp(this.selectedTo, 'i');
    this.users.forEach(function (val, key) {
      if (rx.test(val.name) || rx.test(val.email)) {
        let obj = {}
        obj = val;
        holder.push(obj);
      } else {
        self.searchResult = 'No matches found';
      }
    })
    this.searchResult = holder;
    return this.selectedTo;
  },

  showSearcherDropdown() {
    if(this.searchResult == null) return false;
    if(this.selectedTo === '') return false;
    return true;
  }
},

methods: {
  selectToUser: function( user ) {
    this.newMessage.to = user['.key'];
    this.selectedTo = user.name;
    this.searchResult = null;
  }
}

Typeahead运行良好,每次更改输入字段时都会调用searcher()函数,并使用正确的值填充searchResult。显示了v-for工程和div列表。

单击div后,我调用selectToUser(user)。这会正确地将用户对象的详细信息报告给控制台。

但是,在第一次单击时,我在控制台中得到一个异常并且div没有清除(我希望它们消失,因为我将searchResults设置为null)。

[Vue warn]: Error in event handler for "change": "TypeError: fns.apply is not a function"

found in

---> <BFormInput>
       <BFormGroup>
         <BTab>

TypeError: fns.apply is not a function
    at VueComponent.invoker (vue.esm.js?efeb:2004)
    at VueComponent.Vue.$emit (vue.esm.js?efeb:2515)
    at VueComponent.onChange (form-input.js?1465:138)
    at boundFn (vue.esm.js?efeb:190)
    at invoker (vue.esm.js?efeb:2004)
    at HTMLInputElement.fn._withTask.fn._withTask (vue.esm.js?efeb:1802)

如果我第二次单击div然后没有错误,则设置输入值并且div消失。

所以我怀疑为this.selectedTo写了一个值(这也是元素的v模型对象触发了@change事件。在第二次点击时,值实际上没有改变,因为它已经设置了,所以没有调用搜索者()并没有错误。

我注意到如果元素失去焦点也会发生这种情况。

问题:如何通过方法更改v-model值时阻止@change事件?

(其他信息:根据package.json我在vue 2.5.2)

vuejs2
2个回答
0
投票

上:

<b-form-input id="toUser"
    type="text"
    v-model="selectedTo"
    @change="searcher">

“搜索者”应该是一种方法。每当b-component发布change事件时将调用的方法。

但是看看你的代码,它不是一种方法,而是一种computed

computed: {
  searcher() {
    ...
  },

  showSearcherDropdown() {
    ...
  }
},

methods: {
  selectToUser: function( user ) {
   ...
  }
}

所以当change事件发生时,它会尝试调用不是方法的东西(换句话说,它试图调用一个不存在的方法)。这就是你得到错误的原因。

现在,因为你真正想要的是每当searcher改变时更新this.selectedTo,为了得到它,实际上不需要有@change处理程序。这是因为computed: { searcher() {的代码已经取决于this.selectedTo。每当this.selectedTo改变时,Vue将再次计算searcher

解决方案:只需从@change="searcher"中删除b-form。其他一切都会奏效。


0
投票

@acdcjunior,谢谢你的回答。

当然,删除对searcher()的引用只是意味着不会对字段值更改采取任何操作,因此该字段根本不起作用。

searcher()函数移动到methods: {}而不是computed: {}意味着它将在输入事件上调用而不是变化甚至(另一个神秘但今天不是一个)。一个微妙的差异,消除了我瞄准的先行功能。

但是,它确实让我记住computed: {}函数的结果被缓存,并且当任何参数改变时将重新计算。在这种情况下,我意识到searcher()函数依赖于this.selectedTo变量。因此,当selectToUser()函数设置this.selectedTo时,它会触发对searcher()的另一个调用。

现在修复了。如果将来有人遇到类似的问题,我通过添加另一个变量转向老式信号量来解决这个问题。

var userMadeSelection: false

现在,searcher()开始检查这个场景:

  computed: {
      searcher() {
          if(this.userMadeSelection) {
            this.userMadeSelection = false;
            return this.selectedTo;
          }
          …

然后在selectToUser()中:

this.userMadeSelection = true;
© www.soinside.com 2019 - 2024. All rights reserved.