在 Vue 中有很多 API 都有很实用的地方,只是需要挖掘适用的场景,这里整理出了 $once
的两个小技巧,也是在平常工作中用的比较多的,分享给大家,希望对大家能有帮助。
定时器大家用的应该也不少,像我一开始一般都是这样写的,在 created
中创建定时器,在 beforeDestroy
中销毁定时器。
开始的时候也没有发现有什么问题,没啥毛病。
后面慢慢的了解了更多,才发现里面确实是有几个问题存在的:
定时器的创建和销毁放在了两个生命周期中,很容易就忘记在beforeDestroy
中去销毁,从而导致内存的不必要消耗,并且可读性太差了,后续维护变困难;如果定时器的创建和销毁在同一个生命周期中的话,那么 timer
其实也就没必要使用响应式了,可以减少性能的浪费,直接在 created
中定义一个变量即可;在要销毁的时候,只是清空了定时器,但是却没有把 timer
重置为 null
,用完重置是个好习惯(定时器返回的值可以理解为这个定时器的 ID
,通过这个 ID
来销毁这个定时器)。
优化后的版本是这样的,可读性好了很多,有点 composition API 那味儿了:),示例可以戳这里
export default {
name: "OnceTimer",
data() {
return {
count: 0,
};
},
created() {
let timer = setInterval(() => {
this.count++;
}, 1000);
this.$once("hook:beforeDestroy", () => {
clearInterval(timer);
timer = null;
});
},
};
$once/$emit
+ async/await
实现 Dialog 同步执行
需求背景是这样的:在全局有一个配置项showDialog,在点击 查询 的时候,如果这个配置项为 true
,则需要 dialog d框让用户填写一些数据,当这个 dialog d框关闭之后,才能发出 confirm 的接口给后端,配置项为 false
时,则直接发送 confirm 的请求。
这里会有两个问题:
这个d框和confirm
这个 *** 作并不是强相关,我不能把 confirm 的请求逻辑放置在 dialog d框里;当控制d框显示的变量 visible
设为 true
时,js 逻辑会继续往下执行,即把 confirm 的请求逻辑执行完了,请求就发送出去了,这不是我想要的结果。
我们来模拟一下这个过程,如下图所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gKVYW0Gj-1652258294211)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/47939cf751ee4792b6651cdbc808afd2~tplv-k3u1fbpfcp-zoom-in-crop-mark:1956:0:0:0.image)]
在点击查询之后,先输出了 form submit
(用来模拟点击查询后的发出请求),然后在点击 dialog
d框的确定之后,才输出了 dialog confirm
。可以看到点击查询的接口先发出,点击 dialog
d框 确认的接口后发出。
解决这个问题可以从以下两个方面入手:
dialog
的确认逻辑 与 confirm
发送请求的逻辑要解耦,不能写在一起,不利于复用confirm
的发送请求逻辑,要等 dialog
关闭之后,才能执行,那我们就需要知道 dialog
d框是什么时候关闭的。
有了这两点之后,就可以想到可以利用 $once/$emit
+ promise
+ async/ await
来实现这一逻辑。
通过 $once/$emit
来进行通信,告知 dialog
关闭,通过 promise + async/ await
来使逻辑从异步变同步
我们来看下具体的代码:
// dialog 组件
这是一段信息
取 消
确 定
查询
效果如下:
在点击查询之后,我刻意的停留的一下,就是为了显示点击dialog确认的逻辑在点击查询的请发逻辑之前执行。
详细代码具体分析,可以看到主要的逻辑就是在 dialog
关闭之前,$emit
出一个事件,来告诉父组件,dialog
要关闭了。
// dialog 组件
close() {
// 通知父组件dialog要关闭了
this.$emit("before-dialog-close");
// 关闭 dialog
this.$emit("update:dialogVisible", false);
},
在父组件中,创建一个 promise
,通过 $once
来等到 dialog
关闭的信号 。
// 发出信号
在 confirm
的点击逻辑中,用一个 await
来保证 promsie
结束后,才往下继续执行。
async onSubmit() {
// 当配置为 true 时,需要 dialog d框
if (this.showDialog) {
this.visible = true;
}
// promise 结束后,才会继续往下执行,否则就一直等待
await this.awaitDialogClose();
setTimeout(() => {
console.log("form submit!");
}, 1000);
},
至此,功能就完成了,这个功能适用场景还是很广的(我也是请教了大佬才学会的),大家有兴趣的也可以挖掘一些其他的使用场景。具体代码在这里,有兴趣的可以看一看呀。
可是在 Vue3
中,$once
被移除了,不过没关系,Vue 官方也提出了可以替代的方法。
事件总线模式可以被替换为使用外部的、实现了事件触发器接口的库,例如 mitt 或 tiny-emitter。
import emitter from 'tiny-emitter/instance'
export default {
$once: (...args) => emitter.once(...args),
$emit: (...args) => emitter.emit(...args),
}
总结
没有无用的 API,只是没有找到适用的场景。如果大家有更好的解决方法,也可以在评论区告诉我,让我学习学习。如果这篇文章对大家有帮助,还请抬起你的小手点个赞呀,谢谢大家。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)