Mat*_*gan 5 javascript throttling vue.js vuejs2
我有一个 Vue 2 应用程序,它使用对象数组来支持vue-multiselect提供的搜索/多选小部件。
我已经查看了关于去抖动调用的Vue 1 -> 2 迁移指南,但是他们给出的示例没有将参数从 DOM 元素传播到业务逻辑。
现在,每次击键时 select 都会触发更改事件,但我想限制它(例如,使用 lodash#throttle),这样我就不会在他们打字时每隔几毫秒就调用我的 API。
import {mapGetters} from 'vuex';
import { throttle } from 'lodash';
import Multiselect from 'vue-multiselect'
export default {
components: {
Multiselect
},
data() {
return {
selectedWork: {},
works: [],
isLoading: false
}
},
computed: {
...mapGetters(['worksList']),
},
methods: {
getWorksAsync: throttle((term) => {
// the plan is to replace this with an API call
this.works = this.worksList.filter(work => titleMatches(work, term));
}, 200)
}
}
Run Code Online (Sandbox Code Playgroud)
问题:当用户在选择框中键入内容时,出现错误:
TypeError: Cannot read property 'filter' of undefined
Run Code Online (Sandbox Code Playgroud)
这是因为this.worksList是undefined在函数内部发生的throttle。
奇怪的是,当我使用开发工具调试器时,this.worksList有我需要取消引用的值,this引用 Vue 组件来取消引用该值。
目前我没有从组件内调用 API,但问题仍然相同:
this上下文来更新我的this.works列表?编辑:这在使用 axios 时 Vue Watch 不会触发中进行了解释Vue 2 中正确的模式是什么?
我无法找到有关此问题(或任何地方)的答案,但我最终通过反复试验以及此处和文档中的相关材料将其拼凑在一起。
我没有做过但有效的事情,以及为什么
可以使用 JavaScript DOM 查询直接获取值,也可以深入研究多选组件的结构并获取值。第一个解决方案绕过了框架,第二个解决方案依赖于多选组件的未记录属性。我避免使用这两种解决方案,因为它们不惯用且脆弱。
我目前的解决方案
function函数而不是箭头函数传递给throttle,这给出了正确的this(Vue 组件。)如果有人有关于在 Vue 2 中实现此操作的更好方法的建议,我会洗耳恭听。
这是我的解决方案最终的样子:
<template>
<div>
<label
class="typo__label"
for="ajax">Async select</label>
<multiselect
id="ajax"
v-model="selectedWork"
label="title"
track-by="id"
placeholder="Type to search"
:options="works"
:searchable="true"
:loading="isLoading"
:internal-search="false"
:multiple="false"
:clear-on-select="true"
:close-on-select="true"
:options-limit="300"
:limit="3"
:limit-text="limitText"
:max-height="600"
:show-no-results="false"
open-direction="bottom"
@select="redirect"
@search-change="updateSearchTerm">
<span slot="noResult">Oops! No elements found. Consider changing the search query.</span>
</multiselect>
</div>
</template>
<script>
import {mapGetters} from 'vuex';
import { throttle } from 'lodash';
import Multiselect from 'vue-multiselect'
export default {
components: {
Multiselect
},
data() {
return {
searchTerm: '',
selectedWork: {},
works: [],
isLoading: false
}
},
computed: {
...mapGetters(['worksList']),
},
methods: {
limitText(count) {
return `and ${count} other works`;
},
redirect(work) {
// redirect to selected page
},
updateSearchTerm(term){
this.searchTerm = term;
this.isLoading = true;
this.getWorksAsync();
},
getWorksAsync: throttle(function() {
const term = this.searchTerm.toLowerCase();
callMyAPI(term)
.then(results => {
this.works = results;
this.isLoading = false;
})
}, 200)
}
}
</script>
Run Code Online (Sandbox Code Playgroud)