Làm thế nào để thực hiện gỡ lỗi trong Vue2?


143

Tôi có một hộp nhập đơn giản trong mẫu Vue và tôi muốn sử dụng gỡ lỗi ít nhiều như thế này:

<input type="text" v-model="filterKey" debounce="500">

Tuy nhiên, debouncetài sản đã bị phản đối trong Vue 2 . Đề xuất chỉ nói: "sử dụng v-on: đầu vào + chức năng gỡ lỗi của bên thứ 3".

Làm thế nào để bạn thực hiện chính xác nó?

Tôi đã cố gắng thực hiện nó bằng cách sử dụng lodash , v-on: inputv-model , nhưng tôi tự hỏi liệu có thể làm được nếu không có biến phụ.

Trong mẫu:

<input type="text" v-on:input="debounceInput" v-model="searchInput">

Trong kịch bản:

data: function () {
  return {
    searchInput: '',
    filterKey: ''
  }
},

methods: {
  debounceInput: _.debounce(function () {
    this.filterKey = this.searchInput;
  }, 500)
}

Bộ lọc sau đó được sử dụng sau này trong computedđạo cụ.



3
Tôi muốn đề nghị đọc kỹ: vuejs.org/v2/guide/ Kẻ
Marek Urbanowicz

3
Có một ví dụ trong hướng dẫn: vuejs.org/v2/guide/computing.html#Watchers
Bengt

Câu trả lời:


158

Tôi đang sử dụng debounce gói NPM và thực hiện như thế này:

<input @input="debounceInput">

methods: {
    debounceInput: debounce(function (e) {
      this.$store.dispatch('updateInput', e.target.value)
    }, config.debouncers.default)
}

Sử dụng lodash và ví dụ trong câu hỏi, việc thực hiện trông như thế này:

<input v-on:input="debounceInput">

methods: {
  debounceInput: _.debounce(function (e) {
    this.filterKey = e.target.value;
  }, 500)
}

10
Cảm ơn vì điều đó. Tôi đã tìm thấy một ví dụ tương tự trong một số tài liệu Vue khác: vuejs.org/v2/examples/index.html (trình chỉnh sửa markdown)
MartinTeeVarga

5
Giải pháp đề xuất có vấn đề khi có một số trường hợp thành phần trên trang. Vấn đề được mô tả và giải pháp được trình bày ở đây: forum.vuejs.org/t/issues-with-vuejs-component-and-debounce/7224/ Lỗi
Valera

e.cienTarget được ghi đè lên null theo cách này
ness-EE

1
Muốn giới thiệu thêm một v-model=your_input_variableđầu vào và trong vue của bạn data. Vì vậy, bạn không dựa vào e.targetmà sử dụng Vue để bạn có thể truy cập this.your_input_variablethay vìe.target.value
DominikAngerer

1
Đối với những người sử dụng ES6, điều quan trọng là nhấn mạnh việc sử dụng chức năng ẩn danh ở đây: nếu bạn sử dụng chức năng mũi tên, bạn sẽ không thể truy cập thistrong chức năng.
Polosson

68

Chỉ định gỡ lỗi trong methodscó thể là rắc rối. Vì vậy, thay vì điều này:

// Bad
methods: {
  foo: _.debounce(function(){}, 1000)
}

Bạn có thể thử:

// Good
created () {
  this.foo = _.debounce(function(){}, 1000);
}

Nó trở thành một vấn đề nếu bạn có nhiều phiên bản của một thành phần - tương tự như cách datanên là một hàm trả về một đối tượng. Mỗi trường hợp cần chức năng gỡ lỗi riêng nếu chúng được cho là hành động độc lập.

Đây là một ví dụ về vấn đề:

Vue.component('counter', {
  template: '<div>{{ i }}</div>',
  data: function(){
    return { i: 0 };
  },
  methods: {
    // DON'T DO THIS
    increment: _.debounce(function(){
      this.i += 1;
    }, 1000)
  }
});


new Vue({
  el: '#app',
  mounted () {
    this.$refs.counter1.increment();
    this.$refs.counter2.increment();
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.min.js"></script>

<div id="app">
  <div>Both should change from 0 to 1:</div>
  <counter ref="counter1"></counter>
  <counter ref="counter2"></counter>
</div>


1
Bạn có thể giải thích tại sao việc gán gỡ lỗi trong các phương thức có thể gặp rắc rối không?
MartinTeeVarga

12
Xem ví dụ liên kết dễ bị thối liên kết. Tốt hơn là giải thích vấn đề trong câu trả lời - nó sẽ làm cho nó có giá trị hơn cho độc giả.
MartinTeeVarga

Cảm ơn bạn rất phù hợp, tôi đã có một thời gian tồi tệ để cố gắng hiểu tại sao dữ liệu hiển thị trên bảng điều khiển là đúng nhưng không được áp dụng trên ứng dụng ...

@ sm4 vì thay vì sử dụng cùng một thể hiện đã được chia sẻ cho hàm mong muốn của bạn, nó sẽ tạo lại nó mỗi lần, do đó giết chết việc sử dụng gỡ lỗi là chủ yếu.
Mike Sheward

1
Chỉ cần thêm nó vào data()sau đó của bạn .
Su-Au Hwang

44

cập nhật năm 2020

Tùy chọn 1: Có thể sử dụng lại, không có deps

(Được khuyến nghị nếu cần nhiều hơn một lần trong dự án của bạn)

helpers.js

export function debounce (fn, delay) {
  var timeoutID = null
  return function () {
    clearTimeout(timeoutID)
    var args = arguments
    var that = this
    timeoutID = setTimeout(function () {
      fn.apply(that, args)
    }, delay)
  }
}

Thành phần.vue

<script>
  import {debounce} from './helpers'

  export default {
    data () {
      return {
        input: '',
        debouncedInput: ''
      }
    },
    watch: {
      input: debounce(function (newVal) {
        this.debouncedInput = newVal
      }, 500)
    }
  }
</script>

Codepen


Tùy chọn 2: Trong thành phần, không có deps

(Khuyến nghị nếu sử dụng một lần hoặc trong dự án nhỏ)

Thành phần.vue

<template>
    <input type="text" v-model="input" />
</template>

<script>
  export default {
    data: {
      debouncedInput: ''
    },
    computed: {
     input: {
        get() {
          return this.debouncedInput
        },
        set(val) {
          if (this.timeout) clearTimeout(this.timeout)
          this.timeout = setTimeout(() => {
            this.debouncedInput = val
          }, 300)
        }
      }
    }
  }
</script>

Codepen


4
bạn là anh hùng thực sự
Ashtonian

4
Tôi thích tùy chọn này vì có lẽ tôi không cần gói npm cho 11 dòng mã ....
Ben Winding

3
Đây phải là câu trả lời được đánh dấu, điều này hoạt động thực sự tốt và gần như không có không gian. Cảm ơn!
Alexander Kludt

29

Rất đơn giản mà không cần lodash

  handleScroll: function() {
   if (this.timeout) clearTimeout(this.timeout); 
   this.timeout = setTimeout(() => {
     // your action
   }, 200);
  }

4
Nhiều như tôi yêu thích lodash, đây rõ ràng là câu trả lời tốt nhất cho một lần ra mắt. Dễ nhất để thực hiện cũng như hiểu.
Michael chào

2
cũng là một điều tốt để thêm destroyed() { clearInterval(this.timeout) }vào để không có thời gian chờ sau khi bị phá hủy.
pikilon

13

Tôi đã có cùng một vấn đề và đây là một giải pháp hoạt động mà không cần plugin.

<input v-model="xxxx">nó giống hệt như

<input
   v-bind:value="xxxx"
   v-on:input="xxxx = $event.target.value"
>

(nguồn)

Tôi hình dung tôi có thể thiết lập chức năng gỡ lỗi khi gán xxxx trong xxxx = $event.target.value

như thế này

<input
   v-bind:value="xxxx"
   v-on:input="debounceSearch($event.target.value)"
>

phương pháp:

debounceSearch(val){
  if(search_timeout) clearTimeout(search_timeout);
  var that=this;
  search_timeout = setTimeout(function() {
    that.xxxx = val; 
  }, 400);
},

1
nếu trường đầu vào của bạn cũng có @input="update_something"hành động thì hãy gọi nó sauthat.xxx = val that.update_something();
neon22

1
trong phần phương thức của tôi, tôi đã sử dụng một cú pháp hơi khác với tôi:debounceSearch: function(val) { if (this.search_timeout) clearTimeout(this.search_timeout); var that=this; this.search_timeout = setTimeout(function() { that.thread_count = val; that.update_something(); }, 500); },
neon22

Điều này là ổn nếu bạn có một hoặc rất ít trường hợp bạn cần gỡ lỗi đầu vào. Tuy nhiên, bạn sẽ nhanh chóng nhận ra rằng bạn sẽ cần chuyển thư viện này sang thư viện hoặc tương tự nếu ứng dụng phát triển và chức năng này là cần thiết ở nơi khác. Giữ mã của bạn KHÔ.
Coreus

5

Xin lưu ý rằng tôi đã đăng câu trả lời này trước khi câu trả lời được chấp nhận. Nó không chính xác. Đó chỉ là một bước tiến từ giải pháp trong câu hỏi. Tôi đã chỉnh sửa câu hỏi được chấp nhận để hiển thị cả cách thực hiện của tác giả và việc thực hiện cuối cùng mà tôi đã sử dụng.


Dựa trên các nhận xét và tài liệu di chuyển được liên kết , tôi đã thực hiện một vài thay đổi đối với mã:

Trong mẫu:

<input type="text" v-on:input="debounceInput" v-model="searchInput">

Trong kịch bản:

watch: {
  searchInput: function () {
    this.debounceInput();
  }
},

Và phương thức đặt khóa bộ lọc giữ nguyên:

methods: {
  debounceInput: _.debounce(function () {
    this.filterKey = this.searchInput;
  }, 500)
}

Điều này có vẻ như có một cuộc gọi ít hơn (chỉ v-model, và không phải v-on:input).


Điều này sẽ không gọi debounceInput()hai lần cho mỗi thay đổi? v-on:sẽ phát hiện các thay đổi đầu vào và gỡ lỗi cuộc gọi, VÀ vì mô hình bị ràng buộc, chức năng theo dõi của searchInput cũng sẽ gọi debounceInput... đúng không?
mix3d

@ mix3d Đừng xem xét câu trả lời này. Đó chỉ là cuộc điều tra của tôi mà tôi không muốn đặt câu hỏi. Bạn rất có thể đúng. Kiểm tra câu trả lời được chấp nhận. Đó là chính xác và tôi đã chỉnh sửa nó để phù hợp với câu hỏi.
MartinTeeVarga

Sai lầm của tôi ... Tôi không nhận ra bạn đã trả lời câu hỏi của riêng bạn, ha!
mix3d

5

Nếu bạn cần một cách tiếp cận rất tối giản cho vấn đề này, tôi đã thực hiện một (ban đầu được chia từ vuejs-tips để hỗ trợ IE) có sẵn tại đây: https://www.npmjs.com/package/v-debounce

Sử dụng:

<input v-model.lazy="term" v-debounce="delay" placeholder="Search for something" />

Sau đó, trong thành phần của bạn:

<script>
export default {
  name: 'example',
  data () {
    return {
      delay: 1000,
      term: '',
    }
  },
  watch: {
    term () {
      // Do something with search term after it debounced
      console.log(`Search term changed to ${this.term}`)
    }
  },
  directives: {
    debounce
  }
}
</script>

Có lẽ đây là giải pháp được chấp nhận, với hơn 100 lượt bình chọn. OP đã yêu cầu một giải pháp nhỏ gọn như thế này và nó giải mã một cách độc đáo logic gỡ lỗi.
Barney

1

Trong trường hợp bạn cần áp dụng độ trễ động với debouncechức năng của lodash :

props: {
  delay: String
},

data: () => ({
  search: null
}),

created () {
     this.valueChanged = debounce(function (event) {
      // Here you have access to `this`
      this.makeAPIrequest(event.target.value)
    }.bind(this), this.delay)

},

methods: {
  makeAPIrequest (newVal) {
    // ...
  }
}

Và mẫu:

<template>
  //...

   <input type="text" v-model="search" @input="valueChanged" />

  //...
</template>

LƯU Ý: trong ví dụ trên tôi đã tạo một ví dụ về đầu vào tìm kiếm có thể gọi API với độ trễ tùy chỉnh được cung cấp trongprops


1

Mặc dù khá nhiều câu trả lời ở đây đã chính xác, nhưng nếu có ai đang tìm kiếm một giải pháp nhanh chóng thì tôi có một chỉ thị cho việc này. https://www.npmjs.com/package/vue-lazy-input

Nó áp dụng cho @input và v-model, hỗ trợ các thành phần tùy chỉnh và các thành phần DOM, gỡ lỗi và điều tiết.

Vue.use(VueLazyInput)
  new Vue({
    el: '#app', 
    data() {
      return {
        val: 42
      }
    },
    methods:{
      onLazyInput(e){
        console.log(e.target.value)
      }
    }
  })
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/lodash/lodash.min.js"></script><!-- dependency -->
<script src="https://unpkg.com/vue-lazy-input@latest"></script> 

<div id="app">
  <input type="range" v-model="val" @input="onLazyInput" v-lazy-input /> {{val}}
</div>


0

Nếu bạn đang sử dụng Vue, bạn cũng có thể sử dụng v.model.lazythay vì debouncenhưng hãy nhớv.model.lazy sẽ không luôn hoạt động vì Vue giới hạn nó cho các thành phần tùy chỉnh.

Đối với các thành phần tùy chỉnh, bạn nên sử dụng :valuecùng với@change.native

<b-input :value="data" @change.native="data = $event.target.value" ></b-input>


0

Nếu bạn có thể di chuyển thực thi hàm gỡ lỗi sang một phương thức lớp nào đó, bạn có thể sử dụng một trình trang trí từ utils-decorators lib ( npm install --save utils-decorators):

import {debounce} from 'utils-decorators';

class SomeService {

  @debounce(500)
  getData(params) {
  }
}

-1

Chúng tôi có thể làm với bằng cách sử dụng một vài dòng mã JS:

if(typeof window.LIT !== 'undefined') {
      clearTimeout(window.LIT);
}

window.LIT = setTimeout(() => this.updateTable(), 1000);

Giải pháp đơn giản! Làm việc hoàn hảo! Hy vọng, sẽ hữu ích cho các bạn.


2
Chắc chắn ... nếu bạn muốn làm ô nhiễm không gian toàn cầu và làm cho nó chỉ có 1 yếu tố có thể sử dụng nó tại một thời điểm. Đây là một câu trả lời khủng khiếp.
Lai web dev

-1
 public debChannel = debounce((key) => this.remoteMethodChannelName(key), 200)

vue-property-decorator


2
Bạn có thể vui lòng thêm thông tin về giải pháp này?
rocha

2
Xin hãy giải thích thêm một chút. Ngoài ra, lưu ý rằng đây là một chủ đề cũ với các câu trả lời được thiết lập tốt, vì vậy bạn có thể làm rõ cách giải pháp của bạn phù hợp hơn cho vấn đề không?
jpnadas

Nó giúp nhiều hơn nếu bạn cung cấp một lời giải thích tại sao đây là giải pháp ưa thích và giải thích cách thức hoạt động của nó. Chúng tôi muốn giáo dục, không chỉ cung cấp mã.
Tin Man
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.