javascript - 在输入中键入清除文本时更新Vue组件
问题描述
我认为这是更新组件时的反应性问题。基本上,如果我在输入中快速键入并且父数据被更新,则文本有时会丢失。
最好在下面尝试一下,只需快速输入,您就会看到字母消失。
const search = Vue.component('search', {
props: [ "suggestions", "settings", "search" ],
template: `
<div>
<input type="text" placeholder="Search..." :value="search" @keyup="$emit('update:search', $event.target.value)">
<p v-for="suggestion in suggestions">{{ suggestion }}</p>
</div>
`
})
new Vue({
data: {
settings: {},
state: {
autocompletedSuggestions: []
},
search: ""
},
watch: {
search(value) {
const dummyData = [ 'test1', 'test2', 'test3', 'test4', 'test5', 'test6', 'test7', 'test8' ]
window.setTimeout(() => {
let random = Math.round(Math.random() * (dummyData.length - 0) + 0);
let suggestions = [];
for (let i = 0; i < random; i++) {
suggestions.push(dummyData[Math.round(Math.random() * (dummyData.length - 1) + 0)])
}
this.state.autocompletedSuggestions = suggestions
}, 100)
}
}
}).$mount('#app')
p {
padding: 0;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<search :suggestions="state.autocompletedSuggestions"
:settings="settings"
:search.sync="search"></search>
</div>
我怎样才能阻止这种情况发生?
解决方案
这只是由以下原因引起的时间问题:
keyup
事件有很大的延迟(我的机器上在 50 到 80 毫秒之间 - 我猜也取决于键盘)- 在您的示例中非常“方便地”选择了“超时”值
setTimeout
(如果您尝试明显更短的东西 - 例如 10 毫秒 - 或更长的时间(例如 1000 毫秒),所描述的不当行为的机会将会减少)
怎么了:
- 输入的第一个“a”字母 -> 事件
keyup
事件search
更新为“a”+观察者设置超时- 组件已更新
- 键入的第二个“a”字母
- 超时函数执行更新
this.state.autocompletedSuggestions
- 组件更新 - “a”作为
search
道具推送 - 有效地将输入值从“aa”更改为“a” keyup
事件(对于“aa”) - 但$event.target.value
已经设置为“a”
如何修复它:
- 不要使用
keyup
事件。改为使用input
。它被更快地触发(在用户输入之后)。keyup
当用户使用上下文菜单粘贴并为每个不是您想要的键(包括 Shift、Alt 等)触发时不会触发 - 使用某种去抖动 - 仅在用户停止输入后触发搜索请求。400 毫秒对我来说很棒。
setTimeout
在您的示例中用于模拟 ajax 调用实际上对此很有用(请参阅我的示例) - 每当您发起新的搜索请求时,请务必取消之前的搜索请求(如果有的话)。或者只是在请求期间禁用输入...
const search = Vue.component('search', {
props: ["suggestions", "settings", "search"],
template: `
<div>
<input type="text" placeholder="Search..." :value="search" @keyup="onKeyup" @input="onInput">
<p v-for="suggestion in suggestions">{{ suggestion }}</p>
</div>
`,
methods: {
onKeyup(ev) {
console.log(`Keyup event - Value: ${ev.target.value}`)
},
onInput(ev) {
console.log(`Input event - Value: ${ev.target.value}`)
this.$emit('update:search', ev.target.value)
}
},
updated() {
console.log("Updated")
}
})
new Vue({
data: {
settings: {},
state: {
autocompletedSuggestions: []
},
search: "",
timeout: 0,
debounceTime: 400
},
watch: {
search(value) {
console.log("Search:", value)
clearTimeout(this.timeout) // cancel previous timeout if any
this.timeout = window.setTimeout(async () => {
this.state.autocompletedSuggestions = await this.getSuggestionsAsync()
console.log("Suggestions loaded")
}, this.debounceTime)
}
},
methods: {
getSuggestionsAsync() {
return new Promise((resolve) => {
const dummyData = ['test1', 'test2', 'test3', 'test4', 'test5', 'test6', 'test7', 'test8']
let random = Math.round(Math.random() * (dummyData.length - 0) + 0);
let suggestions = [];
for (let i = 0; i < random; i++) {
suggestions.push(dummyData[Math.round(Math.random() * (dummyData.length - 1) + 0)])
}
// to simulate async call
setTimeout(() => resolve(suggestions), 100)
})
}
}
}).$mount('#app')
p {
padding: 0;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<pre>{{ search }}</pre>
<search :suggestions="state.autocompletedSuggestions" :settings="settings" :search.sync="search"></search>
</div>
推荐阅读
- ios - 在 NSData 的 UnsafeRawPointer 上使用 deallocate 时内存泄漏?
- vue.js - 单个视图的Vue背景颜色
- c - 打破冒泡排序循环
- powershell - 带有重定向文件夹的第 3 方模块中的行为不一致
- python - 有没有办法用 OpenCV 从图像中删除复杂的线条?
- authentication - Microsoft Teams Auth Flow 跨源错误
- java - Spring Cloud Gateway 未找到微服务(未找到 404 错误)
- c++ - 为什么 C++ 中强制 RVO 需要公共析构函数?
- node.js - 消息已发送但未接收到客户端的 socket.on(...)
- javascript - 在传递给新的新可观察对象之前等待异步调用完成