【问题标题】:How to prevent @change event when changing v-model value更改 v-model 值时如何防止 @change 事件
【发布时间】:2018-08-05 17:17:08
【问题描述】:

我正在由 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-model 对象正在触发 @change 事件。在第二次单击时,值实际上并没有改变,因为它已经设置了,所以没有调用 searcher() 也没有错误。

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

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

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

【问题讨论】:

    标签: vuejs2


    【解决方案1】:

    开启:

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

    “搜索器”应该是一种方法。每当b-component 发出change 事件时都会调用的方法。

    但是看你的代码,不是方法,而是computed:

    computed: {
      searcher() {
        ...
      },
    
      showSearcherDropdown() {
        ...
      }
    },
    
    methods: {
      selectToUser: function( user ) {
       ...
      }
    }
    

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

    现在,由于您真正想要的是在this.selectedTo 更改时更新searcher,因此实际上不需要@change 处理程序。这是因为computed: { searcher() { 的代码已经依赖于this.selectedTo。每当this.selectedTo发生变化时,Vue都会重新计算searcher。

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

    【讨论】:

      【解决方案2】:

      @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;
      

      【讨论】:

        猜你喜欢
        • 2016-01-20
        • 1970-01-01
        • 2020-03-07
        • 2019-10-14
        • 2017-09-09
        • 2014-11-08
        • 2023-01-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多