使用 v-debounce 覆盖突变的输入值
Input value overridden on mutation with v-debounce
考虑以下示例:
https://codesandbox.io/s/vdebounce-input-override-ej4nz
它是大型应用程序的简化版(大部分是模拟版),使用 Observables 根据用户输入从多个 API 获取过滤结果。我需要去抖输入。
在应用程序中,去抖动值较大,因此问题不太明显,但我在示例中降低了它,以便更容易发现问题。我还尝试模拟服务器响应时间的随机性。
问题是每当我收到回复时,如果我正在输入,我会丢失一些字符,具体取决于我输入的速度。
如果我删除 v-debounce
指令(或 .lazy
修饰符),问题就消失了,但没有去抖动。
我也在 v-debounce 回购中提出了它。
我知道我可以完全放弃 v-debounce
并在手表内使用 lodash 的去抖动,但我希望我不必那样做(因为 v-debounce
应该是为 Vue 服务,对吧!?)。到目前为止,我已经尽量保持 "Vue" 的水平。
重要编辑:(在回答后)似乎有两个包定义了一个 v-debounce
指令。好的在这里:npm, github.
npm i vue-debounce
我使用的是 v-debounce
并覆盖输入。
了解问题
您遇到的问题是 标记渲染 和 事件去抖动 之间的相互作用(这可能是 v-debounce 或预期的行为意见可能会有所不同):
- 您正在对输入元素上 change 事件 的触发进行去抖动
- 去抖动事件触发调用时的输入值(也就是说,它在去抖动调用中没有调用数据的记忆)
- 另外(在每次实际调用去抖动时)你有一个异步操作(模拟服务器搜索)改变组件的状态,并触发一个组件re-render
- 这个 re-render 检查整个组件 DOM,"corrects" 它认为输入值是错误的
- 当异步操作后触发去抖动更改事件时,它会使用 当前 DOM 输入值 触发,该值现在已经过时(甚至有些混乱) , 如果你一直打字)
可能的解决方案
这里的主要问题是应该跟踪实际搜索值。您想要去抖搜索操作,而不是值更改本身(当然也不是输入更改事件)
我们自己处理去抖
Here is an alternative to your app,执行以下操作:
- 保持 v-model -
search
- 无去抖动
- 关于 v-model 的更改:
- 如果当前正在进行搜索,会立即取消
- 触发 去抖动搜索操作(只有在输入停止时才会真正开始)
[...]
mounted() {
this.debouncedSearch = _.debounce(this.search, 500);
},
methods: {
search() {
this.loading = true;
this.$searchTimeout = setTimeout(() => {
store.albums = albums.filter(
album => album.title.indexOf(this.term) > -1
);
store.searchTerm = this.term;
this.loading = false;
}, Math.floor(Math.random() * 1000 + 300));
}
},
watch: {
term() {
if (this.$searchTimeout) {
this.loading = false;
clearTimeout(this.$searchTimeout);
delete this.$searchTimeout;
}
this.debouncedSearch();
}
}
不影响v-model
的去抖指令
Here is another solution 使用自定义指令去抖动输入事件处理程序, 不会弄乱 v-model 绑定到 change
这里是应用程序:
- 保持 v-model -
search
- 无去抖动
- 更改上述 v-model,如果当前正在进行搜索,立即取消
- 使用v-debounce指令
触发去抖动搜索操作(只有在输入停止时才会真正开始)
<input
v-model="term"
v-debounce="{ delay: 500, handler: search}"
@input="clearSearch">
考虑以下示例:
https://codesandbox.io/s/vdebounce-input-override-ej4nz
它是大型应用程序的简化版(大部分是模拟版),使用 Observables 根据用户输入从多个 API 获取过滤结果。我需要去抖输入。
在应用程序中,去抖动值较大,因此问题不太明显,但我在示例中降低了它,以便更容易发现问题。我还尝试模拟服务器响应时间的随机性。
问题是每当我收到回复时,如果我正在输入,我会丢失一些字符,具体取决于我输入的速度。
如果我删除 v-debounce
指令(或 .lazy
修饰符),问题就消失了,但没有去抖动。
我也在 v-debounce 回购中提出了它。
我知道我可以完全放弃 。v-debounce
并在手表内使用 lodash 的去抖动,但我希望我不必那样做(因为 v-debounce
应该是为 Vue 服务,对吧!?)。到目前为止,我已经尽量保持 "Vue" 的水平
重要编辑:(在回答后)似乎有两个包定义了一个 v-debounce
指令。好的在这里:npm, github.
npm i vue-debounce
我使用的是 v-debounce
并覆盖输入。
了解问题
您遇到的问题是 标记渲染 和 事件去抖动 之间的相互作用(这可能是 v-debounce 或预期的行为意见可能会有所不同):
- 您正在对输入元素上 change 事件 的触发进行去抖动
- 去抖动事件触发调用时的输入值(也就是说,它在去抖动调用中没有调用数据的记忆)
- 另外(在每次实际调用去抖动时)你有一个异步操作(模拟服务器搜索)改变组件的状态,并触发一个组件re-render
- 这个 re-render 检查整个组件 DOM,"corrects" 它认为输入值是错误的
- 当异步操作后触发去抖动更改事件时,它会使用 当前 DOM 输入值 触发,该值现在已经过时(甚至有些混乱) , 如果你一直打字)
可能的解决方案
这里的主要问题是应该跟踪实际搜索值。您想要去抖搜索操作,而不是值更改本身(当然也不是输入更改事件)
我们自己处理去抖
Here is an alternative to your app,执行以下操作:
- 保持 v-model -
search
- 无去抖动 - 关于 v-model 的更改:
- 如果当前正在进行搜索,会立即取消
- 触发 去抖动搜索操作(只有在输入停止时才会真正开始)
[...]
mounted() {
this.debouncedSearch = _.debounce(this.search, 500);
},
methods: {
search() {
this.loading = true;
this.$searchTimeout = setTimeout(() => {
store.albums = albums.filter(
album => album.title.indexOf(this.term) > -1
);
store.searchTerm = this.term;
this.loading = false;
}, Math.floor(Math.random() * 1000 + 300));
}
},
watch: {
term() {
if (this.$searchTimeout) {
this.loading = false;
clearTimeout(this.$searchTimeout);
delete this.$searchTimeout;
}
this.debouncedSearch();
}
}
不影响v-model
的去抖指令
Here is another solution 使用自定义指令去抖动输入事件处理程序, 不会弄乱 v-model 绑定到 change
这里是应用程序:
- 保持 v-model -
search
- 无去抖动- 更改上述 v-model,如果当前正在进行搜索,立即取消
- 使用v-debounce指令 触发去抖动搜索操作(只有在输入停止时才会真正开始)
<input
v-model="term"
v-debounce="{ delay: 500, handler: search}"
@input="clearSearch">