我正在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)
上:
<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
。其他一切都会奏效。
@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;