我正在开发一个组件,当搜索栏中的文本发生变化时,该组件会查询外部API,我正在尝试取消该查询,使其只能每2秒执行一次。我正在尝试使用lodash的debounce
函数来实现这一点,并发现了多篇博客文章和SO关于将其与Vue组件一起使用的问题,但事情很复杂,因为我使用的是Typescript和Vue类组件语法(https://class-component.vuejs.org/)。老实说,我对这两件事都很陌生。
我发现一篇博客文章概述了如何使用基于对象的Vue组件语法来实现这一点,但它不适用于类组件语法。基于对象的语法允许您将方法封装在_.debounce
中,如下所示:
export default {
methods: {
throttledMethod: _.debounce(() => {
console.log('I only get fired once every two seconds, max!')
}, 2000)
}
}
有没有一种方法可以对Vue类组件语法进行类似的处理?
以下是我的代码的相关部分(没有任何去抖动的尝试(:
<template>
<input
v-model="searchQuery"
@keydown="doSearch"
>
</template>
<script lang="ts">
import axios from 'axios';
import _ from 'lodash';
import { Component, Vue } from 'vue-property-decorator';
@Component
export default class FooSearch extends Vue {
// data
searchQuery = '';
results = [];
// methods
async doSearch() {
try {
const response = await axios.get('https://api.example.org/search', {
params: {
query: this.searchQuery,
}
});
this.results = response.data.results;
} catch(error) {
console.log('error');
console.log(error);
}
}
</script>
这里已经讨论过了。
基本上,你需要定义你的基本函数(就像你对doSearch
所做的那样(,然后定义新的去抖动函数:
public doSearchDebounced = _.debounce(this.doSearch, 2000)
现在yu只需要调用doSearchDebounced
而不是doSearch
虽然上面已经回答了,但我认为我们应该在vue-class-component
中充分利用createDecorator
,并集成lodash
来简化Debounce和Throttle的使用。
创建装饰器.ts
import { createDecorator } from "vue-class-component";
import _ from "lodash";
export const Debounce = (waitMs: number) =>
createDecorator((options, key) => {
if (options.methods && options.methods[key]) {
const originalMethod = options.methods[key];
const debounceMethod = _.debounce(originalMethod, waitMs, {
leading: false,
trailing: true,
});
options.methods[key] = async function (...args: any) {
await debounceMethod.apply(this, args);
};
}
});
export const Throttle = (waitMs: number) =>
createDecorator((options, key) => {
if (options.methods && options.methods[key]) {
const originalMethod = options.methods[key];
const throttleMethod = _.throttle(originalMethod, waitMs, {
leading: true,
trailing: false,
});
options.methods[key] = async function (...args: any) {
await throttleMethod.apply(this, args);
};
}
});
重构代码并使用decorator。
<template>
<input
v-model="searchQuery"
@keydown="doSearch"
>
</template>
<script lang="ts">
import axios from 'axios';
import { Component, Vue } from 'vue-property-decorator';
import { Debounce } from "@/decorator";
@Component
export default class FooSearch extends Vue {
// data
searchQuery = '';
results = [];
// add the Debounce annotation
@Debounce(1500)
async doSearch() {
try {
const response = await axios.get('https://api.example.org/search', {
params: {
query: this.searchQuery,
}
});
this.results = response.data.results;
} catch(error) {
console.log('error');
console.log(error);
}
}
</script>
你可以像那样做
<script lang='ts'>
import { debounce } from 'decko'
@debounce(1000)
async doSearch() {
....
}
</script>