vue.js - ¿Cómo implementar debounce en Vue2?
vuejs2 debouncing (10)
Tengo un cuadro de entrada simple en una plantilla Vue y me gustaría usar debounce más o menos así:
<input type="text" v-model="filterKey" debounce="500">
Sin embargo, la propiedad
debounce
ha quedado
en desuso en Vue 2
.
La recomendación solo dice: "use v-on: input + función de rebote de terceros".
¿Cómo lo implementas correctamente?
Intenté implementarlo usando lodash , v-on: input y v-model , pero me pregunto si es posible prescindir de la variable adicional.
En plantilla:
<input type="text" v-on:input="debounceInput" v-model="searchInput">
En script:
data: function () {
return {
searchInput: '''',
filterKey: ''''
}
},
methods: {
debounceInput: _.debounce(function () {
this.filterKey = this.searchInput;
}, 500)
}
La clave de filtro se usa luego en accesorios
computed
.
Tenga en cuenta que publiqué esta respuesta antes de la respuesta aceptada. No es correcto. Es solo un paso adelante de la solución en la pregunta. He editado la pregunta aceptada para mostrar tanto la implementación del autor como la implementación final que había utilizado.
Según los comentarios y el vuejs.org/v2/guide/… , he realizado algunos cambios en el código:
En plantilla:
<input type="text" v-on:input="debounceInput" v-model="searchInput">
En script:
watch: {
searchInput: function () {
this.debounceInput();
}
},
Y el método que establece la clave de filtro permanece igual:
methods: {
debounceInput: _.debounce(function () {
this.filterKey = this.searchInput;
}, 500)
}
Parece que hay una llamada menos (solo el
v-model
, y no la entrada
v-on:input
.
Asignar un rebote en los
methods
puede ser un problema.
Entonces, en lugar de esto:
// Bad
methods: {
foo: _.debounce(function(){}, 1000)
}
Puedes probar:
// Good
created () {
this.foo = _.debounce(function(){}, 1000);
}
Se convierte en un problema si tiene varias instancias de un componente, similar a la forma en que los
data
deberían ser una función que devuelve un objeto.
Cada instancia necesita su propia función antirrebote si se supone que debe actuar de forma independiente.
Aquí hay un ejemplo del problema:
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>
En caso de que necesite aplicar un retraso dinámico con la función antirrebote de
debounce
:
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) {
// ...
}
}
Y la plantilla:
<template>
//...
<input type="text" v-model="search" @input="valueChanged" />
//...
</template>
NOTA:
en el ejemplo anterior, hice un ejemplo de entrada de búsqueda que puede llamar a la API con un retraso personalizado que se proporciona en
props
Estoy usando el paquete debounce NPM e implementado así:
<input @input="debounceInput">
methods: {
debounceInput: debounce(function (e) {
this.$store.dispatch(''updateInput'', e.target.value)
}, config.debouncers.default)
}
Usando lodash y el ejemplo en la pregunta, la implementación se ve así:
<input v-on:input="debounceInput">
methods: {
debounceInput: _.debounce(function (e) {
this.filterKey = e.target.value;
}, 500)
}
Muy simple sin lodash
handleScroll: function() {
if (this.timeout) clearTimeout(this.timeout);
this.timeout = setTimeout(() => {
// your action
}, 200);
}
Podemos hacerlo usando pocas líneas de código JS:
if(typeof window.LIT !== ''undefined'') {
clearTimeout(window.LIT);
}
window.LIT = setTimeout(() => this.updateTable(), 1000);
¡Solución simple! Trabajo perfecto! Espero que sea útil para ustedes.
Reutilizable y sin profundidad:
helpers.js
module.exports = 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)
}
}
.vue
<script>
import debounce from ''./helpers''
export default {
data () {
return {
input: '''',
debouncedInput: ''''
}
},
watch: {
input: debounce(function (newVal) {
this.debouncedInput = newVal
}, 500)
}
}
</script>
(crédito a pequeño rebote )
Si está usando Vue, también puede usar
v.model.lazy
lugar de
debounce
pero recuerde que
v.model.lazy
no siempre funcionará ya que Vue lo limita para componentes personalizados.
Para componentes personalizados, debe usar
:value
junto con
@change.native
<b-input :value="data" @change.native="data = $event.target.value" ></b-input>
Si necesita un enfoque muy minimalista para esto, hice uno (originalmente bifurcado de vuejs-tips para que también sea compatible con IE) que está disponible aquí: https://www.npmjs.com/package/v-debounce
Uso:
<input v-model.lazy="term" v-debounce="delay" placeholder="Search for something" />
Luego en su componente:
<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>
Tuve el mismo problema y esto funcionó sin complementos .
Dado que
<input v-model="xxxx">
es exactamente lo mismo que
<input
v-bind:value="xxxx"
v-on:input="xxxx = $event.target.value"
>
(source)
Pensé que podría establecer una función antirrebote en la asignación de xxxx en
xxxx = $event.target.value
Me gusta esto
<input
v-bind:value="xxxx"
v-on:input="debounceSearch($event.target.value)"
>
métodos:
debounceSearch(val){
if(search_timeout) clearTimeout(search_timeout);
var that=this;
search_timeout = setTimeout(function() {
that.xxxx = val;
}, 400);
},