在将参数传递给去抖函数时限制或去抖 Vue 2 中的异步调用

Throttle or debounce async calls in Vue 2 while passing arguments to debounced function

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

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

现在 select 每次击键都会触发更改事件,但我想限制它(EG with 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)
  }
}

问题:当用户在 select 框中输入时,出现错误:

TypeError: Cannot read property 'filter' of undefined

这是因为 this.worksListundefinedthrottle 函数中。

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

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

  1. 我如何限制此调用,并有适当的 this 上下文来更新我的 this.works 列表?编辑:这在
  2. 中有解释
  3. 我还需要从 multiselect 小部件捕获用户的查询字符串以传递给 API 调用。

Vue 2 中的正确模式是什么?

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

我没有做过的有用的事情,为什么

可以直接使用JavaScript DOM查询获取值,也可以深入到多选组件的结构中获取值。第一个解决方案绕过框架,第二个解决方案取决于多选组件的未记录属性。我避免使用这两种解决方案,因为它们不合惯用且脆弱。

我目前的解决方案

  1. 只要搜索框中有更改事件,就会更新组件的属性。这使我能够捕获用户的查询字符串。
  2. 从事件侦听器内部调用了我的节流异步函数。
  3. 将常规 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>

我 运行 在使用 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)
  }
}

希望对您有所帮助!