Vue中$once的兩個(gè)實(shí)用小技巧分享
前言
在 Vue 中有很多 API 都有很實(shí)用的地方,只是需要挖掘適用的場景,這里整理出了 $once 的兩個(gè)小技巧,也是在平常工作中用的比較多的,分享給大家,希望對大家能有幫助。
清除定時(shí)器
定時(shí)器大家用的應(yīng)該也不少,像我一開始一般都是這樣寫的,在 created 中創(chuàng)建定時(shí)器,在 beforeDestroy 中銷毀定時(shí)器。
<script> export default { name: "Timer", data() { return { timer: null, count: 0, }; }, created() { this.timer = setInterval(() => { this.count++; }, 1000); }, beforeDestroy() { clearInterval(this.timer); }, }; </script>
開始的時(shí)候也沒有發(fā)現(xiàn)有什么問題,沒啥毛病。
后面慢慢的了解了更多,才發(fā)現(xiàn)里面確實(shí)是有幾個(gè)問題存在的:
- 定時(shí)器的創(chuàng)建和銷毀放在了兩個(gè)生命周期中,很容易就忘記在 beforeDestroy 中去銷毀,從而導(dǎo)致內(nèi)存的不必要消耗,并且可讀性太差了,后續(xù)維護(hù)變困難;
- 如果定時(shí)器的創(chuàng)建和銷毀在同一個(gè)生命周期中的話,那么 timer 其實(shí)也就沒必要使用響應(yīng)式了,可以減少性能的浪費(fèi),直接在 created 中定義一個(gè)變量即可;
- 在要銷毀的時(shí)候,只是清空了定時(shí)器,但是卻沒有把 timer 重置為 null,用完重置是個(gè)好習(xí)慣(定時(shí)器返回的值可以理解為這個(gè)定時(shí)器的 ID,通過這個(gè) ID 來銷毀這個(gè)定時(shí)器)。
優(yōu)化后的版本是這樣的,可讀性好了很多,有點(diǎn) 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 實(shí)現(xiàn) Dialog 同步執(zhí)行
需求背景是這樣的:在全局有一個(gè)配置項(xiàng)showDialog,在點(diǎn)擊 查詢 的時(shí)候,如果這個(gè)配置項(xiàng)為 true,則需要 dialog 彈框讓用戶填寫一些數(shù)據(jù),當(dāng)這個(gè) dialog 彈框關(guān)閉之后,才能發(fā)出 confirm 的接口給后端,配置項(xiàng)為 false 時(shí),則直接發(fā)送 confirm 的請求。
這里會有兩個(gè)問題:
- 這個(gè)彈框和 confirm 這個(gè)操作并不是強(qiáng)相關(guān),我不能把 confirm 的請求邏輯放置在 dialog 彈框里;
- 當(dāng)控制彈框顯示的變量 visible 設(shè)為 true 時(shí),js 邏輯會繼續(xù)往下執(zhí)行,即把 confirm 的請求邏輯執(zhí)行完了,請求就發(fā)送出去了,這不是我想要的結(jié)果。
我們來模擬一下這個(gè)過程,如下圖所示:
在點(diǎn)擊查詢之后,先輸出了 form submit(用來模擬點(diǎn)擊查詢后的發(fā)出請求),然后在點(diǎn)擊 dialog 彈框的確定之后,才輸出了 dialog confirm。可以看到點(diǎn)擊查詢的接口先發(fā)出,點(diǎn)擊 dialog 彈框 確認(rèn)的接口后發(fā)出。
解決這個(gè)問題可以從以下兩個(gè)方面入手:
- dialog 的確認(rèn)邏輯 與 confirm 發(fā)送請求的邏輯要解耦,不能寫在一起,不利于復(fù)用
- confirm 的發(fā)送請求邏輯,要等 dialog 關(guān)閉之后,才能執(zhí)行,那我們就需要知道 dialog 彈框是什么時(shí)候關(guān)閉的。
有了這兩點(diǎn)之后,就可以想到可以利用 $once/$emit + promise + async/ await 來實(shí)現(xiàn)這一邏輯。
通過 $once/$emit 來進(jìn)行通信,告知 dialog 關(guān)閉,通過 promise + async/ await 來使邏輯從異步變同步
我們來看下具體的代碼:
// dialog 組件 <template> <el-dialog title="提示" :visible.sync="dialogVisible" width="30%" :before-close="close" > <span>這是一段信息</span> <span slot="footer" class="dialog-footer"> <el-button @click="close">取 消</el-button> <el-button type="primary" @click="confirm">確 定</el-button> </span> </el-dialog> </template> <script> export default { props: ["dialogVisible"], data() { return {}; }, methods: { close() { this.$emit("before-dialog-close"); this.$emit("update:dialogVisible", false); }, confirm() { console.log("dialog confirm"); this.close(); }, }, }; </script>
<template> <div> <el-form :inline="true" :model="formInline" class="demo-form-inline"> <el-form-item label="審批人"> <el-input v-model="formInline.user" placeholder="審批人"></el-input> </el-form-item> <el-form-item label="活動區(qū)域"> <el-select v-model="formInline.region" placeholder="活動區(qū)域"> <el-option label="區(qū)域一" value="shanghai"></el-option> <el-option label="區(qū)域二" value="beijing"></el-option> </el-select> </el-form-item> <el-form-item> <el-button type="primary" @click="onSubmit">查詢</el-button> </el-form-item> </el-form> <Dialog :dialogVisible.sync="visible" @before-dialog-close="() => this.$emit('beforeDialogClose')" /> </div> </template> <script> import Dialog from "./dialog"; export default { name: "Promise", components: { Dialog, }, data() { return { formInline: { user: "", region: "", }, // 控制 dialog 的展示 visible: false, // 在業(yè)務(wù)中這是一個(gè)配置項(xiàng) showDialog: true, }; }, methods: { awaitDialogClose() { return new Promise((resolve) => { if (!this.visible) { resolve(null); } this.$once("beforeDialogClose", () => { resolve(null); }); }); }, async onSubmit() { if (this.showDialog) { this.visible = true; } await this.awaitDialogClose(); setTimeout(() => { console.log("form submit!"); }, 1000); }, }, }; </script>
效果如下:
在點(diǎn)擊查詢之后,我刻意的停留的一下,就是為了顯示點(diǎn)擊dialog確認(rèn)的邏輯在點(diǎn)擊查詢的請發(fā)邏輯之前執(zhí)行。
詳細(xì)代碼具體分析,可以看到主要的邏輯就是在 dialog 關(guān)閉之前,$emit 出一個(gè)事件,來告訴父組件,dialog 要關(guān)閉了。
// dialog 組件 close() { // 通知父組件dialog要關(guān)閉了 this.$emit("before-dialog-close"); // 關(guān)閉 dialog this.$emit("update:dialogVisible", false); },
在父組件中,創(chuàng)建一個(gè) promise,通過 $once 來等到 dialog 關(guān)閉的信號 。
// 發(fā)出信號 <Dialog :dialogVisible.sync="visible" @before-dialog-close="() => this.$emit('beforeDialogClose')" /> // 接收信號 awaitDialogClose() { return new Promise((resolve) => { // 當(dāng) dialog 沒彈框的時(shí)候,走這個(gè)邏輯,promise 直接結(jié)束 if (!this.visible) { resolve(null); } // 當(dāng) dialog 要關(guān)閉的時(shí)候,$once 接收到了信號,promise 結(jié)束 this.$once("beforeDialogClose", () => { resolve(null); }); }); },
在 confirm 的點(diǎn)擊邏輯中,用一個(gè) await 來保證 promsie 結(jié)束后,才往下繼續(xù)執(zhí)行。
async onSubmit() { // 當(dāng)配置為 true 時(shí),需要 dialog 彈框 if (this.showDialog) { this.visible = true; } // promise 結(jié)束后,才會繼續(xù)往下執(zhí)行,否則就一直等待 await this.awaitDialogClose(); setTimeout(() => { console.log("form submit!"); }, 1000); },
至此,功能就完成了,這個(gè)功能適用場景還是很廣的(我也是請教了大佬才學(xué)會的),大家有興趣的也可以挖掘一些其他的使用場景。具體代碼在這里,有興趣的可以看一看呀。
可是在 Vue3 中,$once 被移除了,不過沒關(guān)系,Vue 官方也提出了可以替代的方法。
事件總線模式可以被替換為使用外部的、實(shí)現(xiàn)了事件觸發(fā)器接口的庫,例如 mitt 或 tiny-emitter。
import emitter from 'tiny-emitter/instance' export default { $once: (...args) => emitter.once(...args), $emit: (...args) => emitter.emit(...args), } 復(fù)制代碼
總結(jié)
沒有無用的 API,只是沒有找到適用的場景。如果大家有更好的解決方法,也可以在評論區(qū)告訴我,讓我學(xué)習(xí)學(xué)習(xí)。
到此這篇關(guān)于Vue中$once實(shí)用小技巧的文章就介紹到這了,更多相關(guān)Vue $once小技巧內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue框架實(shí)現(xiàn)將側(cè)邊欄完全隱藏
這篇文章主要介紹了vue框架實(shí)現(xiàn)將側(cè)邊欄完全隱藏,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08element表單驗(yàn)證如何清除校驗(yàn)提示語
本文主要介紹了element表單驗(yàn)證如何清除校驗(yàn)提示語,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10vue組件實(shí)現(xiàn)移動端九宮格轉(zhuǎn)盤抽獎
這篇文章主要為大家詳細(xì)介紹了vue組件實(shí)現(xiàn)移動端九宮格轉(zhuǎn)盤抽獎,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-10-10vue使用axios實(shí)現(xiàn)動態(tài)追加數(shù)據(jù)
在vuejs中使用axios時(shí),有時(shí)候需要追加數(shù)據(jù),比如,移動端下拉觸底加載,分頁加載,滑動滾動條等,下面小編就來為大家介紹一下如何使用使用axios實(shí)現(xiàn)動態(tài)追加數(shù)據(jù)吧2023-10-10vue-cli是什么及創(chuàng)建vue-cli項(xiàng)目的方法
vue-cli是 vue 官方提供的、快速生成 vue 工程化項(xiàng)目的工具,支持創(chuàng)建vue2和vue3的項(xiàng)目,本文給大家詳細(xì)講解vue-cli是什么及創(chuàng)建vue-cli項(xiàng)目的方法,感興趣的朋友跟隨小編一起看看吧2023-04-04