Vue文本框每次按键触发XHR请求页面重载,setTimeout设置报错如何解决
问题描述
我有一个用于输入描述的文本框,每次按键都会触发如下日志且页面发生重载:
XHR finished loading: PATCH "http://localhost:3000/ccenter/attachments/51".
我打算给值的设置添加防抖来减少请求次数,刚接触JS还没找到合适的实现方式,尝试的写法抛出了如下错误:
[Vue warn]: Error in render: "TypeError: Setter must be a function: 3" attachmentAccepted: { get: function () { return !this.attachment.ignoreAttachment; }, set: setTimeout(function (val) { return this.updateAttachment([this.attachment.id, { ignoreAttachment: !val }]); }, 3000) },
错误原因
计算属性的set要求赋值为函数类型,但setTimeout执行后返回的是数字类型的定时器ID,不符合setter的类型要求,因此抛出错误。
第一次修改后问题
调整set的写法后不再触发重载,但出现新错误,文本输入框的值无法正常注册:
set: function (val) { setTimeout(function(){ return this.updateAttachment([this.attachment.id, { strValue: val }]) }, 3000) },
报错信息:
Uncaught TypeError: Cannot read properties of undefined (reading 'id')
错误原因
setTimeout内的普通函数执行时会丢失上层作用域的this指向,此时函数内的this指向全局对象(浏览器环境下为window),全局对象不存在attachment属性,因此读取id时报未定义错误。
最终解决方案
通过变量暂存上层作用域的this,在定时器回调内使用暂存的变量访问组件实例即可:
set: function (val) { let self = this; setTimeout(function(){ /* 业务代码,所有原本用this访问的属性都替换为self访问 */ self.updateAttachment([self.attachment.id, { strValue: val }]) }, 3000) }
你也可以使用箭头函数简化写法,箭头函数的this会继承上层作用域的指向,无需额外暂存:
set: function (val) { setTimeout(() => { this.updateAttachment([this.attachment.id, { strValue: val }]) }, 3000) }
注意:以上写法仅实现了延迟执行,没有真正的防抖效果(多次触发会生成多个定时器,等待时间结束后还是会全部执行),如果需要完整防抖功能,可以提前存储定时器ID,每次触发set时先清空上一个定时器:
set: function (val) { // 清空上一次的定时器 clearTimeout(this.updateTimer) // 存储新的定时器ID this.updateTimer = setTimeout(() => { this.updateAttachment([this.attachment.id, { strValue: val }]) }, 300) }
内容的提问来源于stack exchange,提问作者user16741832
相关产品推荐
相关产品推荐

