まとめ
setTimeoutで処理をタイマー設定しておき、onMounted内での処理は全て終わったように見せることで対応した。
onMounted(() => {
setTimeout(() => {
isOpen.value = true; // ここにmounted直後に呼び出す処理を記述
}, 0);
});
追記:コメントでアドバイスいただきました
1. queueMicrotask
マイクロタスク (microtask) とは、現在のタスクが完了し実行コンテキストの制御がブラウザーのイベントループへ戻る前、他に保留中のコードがなくなった時点で走る短い関数です。
現在のイベントループ内でのタスク完了後に自動で処理を走らせてくれる。
setTimeoutよりも軽量。
onMounted(() => {
queueMicroTask(() => {
isOpen.value = true; // ここにmounted直後に呼び出す処理を記述
});
});
2. nextTick
onMounted(async () => {
await nextTick();
isOpen.value = true; // ここにmounted直後に呼び出す処理を記述
});
3. Promise.resolve
onMounted(async () => {
await Promise.resolve();
isOpen.value = true; // ここにmounted直後に呼び出す処理を記述
});
経緯
vuetifyのv-navigation-drawerを使用し動的に増えるドロワーを実装していた際、ドロワー表示アニメーションを呼び出そうとしていた。
<template>
<SampleDrawer
v-for="drawer in drawers"
:item="drawer.item"
@open-new-drawer="openDrawer"
@close-drawer="closeDrawer">
</SampleDrawer>
</template>
<script setup lang="ts">
const drawers = ref<any[]>([]); // リストにドロワーを追加する度ドロワーが増える
</script>
<v-navigation-drawer v-model="isOpen"></v-navigation-drawer>
1. mounted時に呼び出し
create時にはfalseで、mounted時にtrueへ切り替えることによりアニメーションを表示させようとした。
isOpen = ref(false);
onMounted(() => {
isOpen.value = true; // false状態で生成後、マウント時にtrueに変更
});
しかし、表示アニメーションはmounted時には呼び出されず更新時に呼び出される様で、結果としてアニメーション無しで表示されることとなってしまった。
2. mounted直後に呼び出し
そこで、mounted後に呼び出されるフックがあるかと思い(afterMount的な?)探したが残念ながら見つからず、下記の方法を試すこととした。
onMounted(() => {
setTimeout(() => {
isOpen.value = true; // onMounted自体はsetTimeoutの実行が完了した段階で完了し、
}, 0); // onMounted完了直後にタイマー設定しておいたフラグ変更処理が走る
});
結果として無事アニメーションを表示することに成功した。
おまけ
ちなみに閉じるアニメーションについては分かりやすく、Unmountedでアニメーションが再生開始してから閉じるまで待った後に親からコンポーネントを削除する、といった形で解決した。
const closeDrawer = () => {
setTimeout(() => {
drawers.value.pop(); // アニメーション再生終了を待ってコンポーネント削除
}, 500);
};
感想
明らかに外法な気がするので正しい方法があるならそちらを使いたい…