目的
防止重复提交表单,所以设置了一个loading值来控制。 代码修改如下。
function setLoading(loading) {
return function(target, name, descriptor) {
const old = descriptor.value;
descriptor.value = function() {
// 获取vue/react 组件的isLoading属性
const isLoading = this.data[loading];
if(isLoading) return;
this.data[loading] = true;
old.apply(this, arguments);
// 重置loading
this.data[loading] = false;
// 更新data到dom
this.$update();
};
return descriptor;
}
}
@setLoading('isLoading')
async getUserList() {
// 请求后台接口
const res = await backend.getUserList();
if(res) {
// 请求成功后的业务逻辑
}
}
有两个问题:
- 不知道我这个setLoading装饰器写的是不是对的。我看别人都是最后得return old.apply(this, arguments);但是我得将原来函数中间的逻辑在中间执行呃。。
- 由于getUserList是异步的函数,所以装饰器中的this.$update()这一步会提前backend.getUserList执行了。。最终导致数据请求回来了,但是dom无法更新了。
求大佬解答一下。。我在想可不可以在装饰器中加一个settimeout。。强行延迟this.$update(),不过感觉这样太low了
第三个问题: 我想基于上面的setLoading代码,实现如果请求时间大于300ms,才会显示loading的效果。
function setLoading(loading) {
let timer = null;
return function(target, name, descriptor) {
const old = descriptor.value;
descriptor.value = function() {
// 获取vue/react 组件的isLoading属性
const isLoading = this.data[loading];
if(isLoading) return;
// 这里设置一个300ms的定时器
timer = setTimeout(() => this.data[loading] = true, 300);
old.apply(this, arguments);
// 重置loading与定时器timer
clearTimeout(timer);
this.data[loading] = false;
// 更新data到dom
this.$update();
};
return descriptor;
}
}
然后我试了一下,手动把chrome网速调为slow 3g(网速很慢,请求时间 > 300ms). 效果符合预期,dom在loading结束后更新了data。但是正常网速下(请求时间<<<300ms),loading不会出现,数据也请求到了,但是dom的data并没有更新。
方法装饰器简单介绍
方法的装饰器是通过修改原有的描述对象,返回新的描述对象来替换原有的方法.
解答
old.apply(this, arguments)
,如果不需要有返回值,那就可以不用返回因为原来的方法是异步的,所以如果想要让
update
在后面执行的话,第一种方法用async await
关键词,让原来的方法变为同步的.第二种方法就是把update
放在原先方法的then
里面执行补充
不会更新 dom 的话,你可以试试看分别在
getUserList
和update
输出看看是谁先执行的.你评论里提到了
react
,我猜测你是用react
的,getUserList
没有返回值,那可能是通过state
来同步你的数据的,而setState
是一个异步操作,如果你在getUserList
里面用了setState
的话,也需要加上await
来等待setState
执行完成.否则更新的速度比较快,state
还没来得及更改,所以 dom 不更新.只是一般
react
都是直接用setState
来触发渲染的,而你还有个update
所以不太确定.设置延时代码,你是要等请求之后等待 300ms 的,所以
setTimeout
应该写在后面,另外要添加async
和await
关键词,setTimeout
是执行一次就销毁的,一般也不用去清理一点小经验
当修改的方法为箭头函数的时候,描述符对象会不一样,需要做别的适配,因为太麻烦了,所以我一般都是直接用
function
,但是又不想每次用方法的时候都用myclass.myFun()
的方式去调用,而是想直接用myFun()
去调用,那就需要在外层在调用一个装饰器用来绑定this
了,这样就不会丢失this
,core-decorators
的autobind
很好用.参考文章