在将参数传递给去抖动函数时,在Vue 2中调节或去抖异步调用

时间:2018-04-20 18:51:50

标签: javascript vue.js vuejs2 throttling

我有一个Vue 2应用程序,它使用一组对象来支持vue-multiselect提供的搜索/多选小部件。

我看过Vue 1 - > 2 debouncing calls上的迁移指南,但它们提供的示例并没有将参数从DOM元素传播到业务逻辑。

现在,每次按键时,选择会触发更改事件,但是我想对此进行限制(EG使用lodash#throttle),这样我就不会在他们打字的时候每几毫秒点击一次我的API。 / p>

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)
  }
}

问题:当用户在选择框中输入内容时,出现错误:

TypeError: Cannot read property 'filter' of undefined

正在发生这种情况,因为this.worksList undefined函数中throttlethis.worksList

奇怪的是,当我使用开发工具调试器时,this具有我需要取消引用的值,this引用了Vue组件。

目前我没有从组件中调用API,但问题仍然存在:

  1. 如何限制此调用,并使用正确的this.works上下文来更新我的function列表?编辑:这在Vue Watch doesnt Get triggered when using axios
  2. 中有解释
  3. 我还需要从多选小部件中捕获用户的查询字符串以传递给API调用。
  4. Vue 2中的正确模式是什么?

2 个答案:

答案 0 :(得分:0)

我无法在SO(或任何地方)找到答案,但我最终通过反复试验,以及此处和文档中的相关材料将它拼凑在一起。

有效的事情,我没有做,以及为什么

可以使用JavaScript DOM查询直接获取值,也可以深入了解多选组件的结构并获取值。第一种解决方案绕过框架,第二种解决方案取决于多选组件的未记录属性。我避免这两种解决方案都是非惯用和脆弱的。

我目前的解决方案

  1. 只要搜索框中出现更改事件,就会更新组件上的属性。这使我能够捕获用户的查询字符串。
  2. 从事件监听器内部调用我的限制异步函数。
  3. 将常规throttle而不是箭头功能传递给this,后者提供了正确的<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> (Vue组件)。
  4. 如果有人建议在Vue 2中采用更好的方式做到这一点,那么我全心全意。

    这是我的解决方案最终的样子:

    | id    | name                                                                                  |
    |-------|---------------------------------------------------------------------------------------|
    | a1xy  | [  {  "event": "sports",   "start": "100"},  {  "event": "lunch",  "start": "121" } ] |
    | a7yz  | [  {  "event": "lunch",   "start": "109"},  {  "event": "movie",  "start": "97" } ]   |
    | bx4y  | [  {  "event": "dinner",   "start": "78"},  {  "event": "sleep",  "start": "25" } ]   |
    

答案 1 :(得分:0)

使用lodash.debounce时遇到了同样的问题。我是箭头语法的忠实粉丝,但我发现它导致_.throttle()_.debounce()等失败。

显然我的代码与你的代码有所不同,但我做了以下工作并且有效:

export default {
   ...,
   methods: {
     onClick: _.debounce(function() {
       this.$emit('activate', this.item)
     }, 500)
  }
}

即使我在这里没有使用箭头语法,this仍引用去抖动函数内的组件。

在您的代码中,它看起来像这样:

export default {
  ...,
  methods: {
    getWorksAsync: throttle(function(term) {
      // the plan is to replace this with an API call
      this.works = this.worksList.filter(work => titleMatches(work, term));
    }, 200)
  }
}

希望有所帮助!