vue-final / vue-final-modal

🍕Vue Final Modal is a tiny, renderless, mobile-friendly, feature-rich modal component for Vue.js.
https://vue-final-modal.org
MIT License
864 stars 95 forks source link

feat: add helper function `defineLazyMountComponent` #381

Closed Mini-ghost closed 7 months ago

Mini-ghost commented 11 months ago

Modal are often not opened immediately when entering a website. They usually require some action, like click button to trigger their appearance.

To handle this, we can use defineAsyncComponent to load the modal component dynamically:

<script setup lang="ts">
import { defineAsyncComponent, ref } from 'vue'

const LazyCustomModal = defineAsyncComponent(() => import('@/components/CustomModal.vue'));

const isActive = ref(false)
</script>

<template>
  <LazyCustomModal v-model="isActive"  />
</template>

However, this approach only splits the component into a separate chunk, which will still be loaded when entering the page, even if we don't open it.

To achieve delayed loading, we can implement the following:

<script setup lang="ts">
import { defineAsyncComponent, ref } from 'vue'

const LazyCustomModal = defineAsyncComponent(() => import('@/components/CustomModal.vue'));

const isActive = ref(false)
</script>

<template>
  <template v-if="isActive">
    <LazyCustomModal v-model="isActive"  />
  </template>
</template>

But a problem with this method is that the component will be unloaded when the modal is closed. So we need to do something special to handle this:

<script setup lang="ts">
import { defineAsyncComponent, ref } from 'vue'

const LazyCustomModal = defineAsyncComponent(() => import('@/components/CustomModal.vue'));

const isActive = ref(false)
const isModalMounted = ref(false)
</script>

<template>
  <template v-if="isActive || isModalMounted">
    <LazyCustomModal 
      v-model="isActive"
      @vnode-mounted="isModalMounted = true"
    />
  </template>
</template>

This solution might seem a bit wordy, so I attempted to add a new method called defineLazyMountCompone to encapsulate the above logic:

<script setup lang="ts">
import { ref } from 'vue'
import { defineLazyMountComponent } from 'vue-final-modal'

const LazyCustomModal = defineLazyMountComponent(() => import('@/components/CustomModal.vue'));

const isActive = ref(false)
</script>

<template>
  <LazyCustomModal v-model="isActive"  />
</template>

I hope this simplified explanation is easier to understand. If you have any questions, feel free to ask!

hunterliu1003 commented 11 months ago

@Mini-ghost May I ask you to add at least one use case for defineLazyMountComponent() inside of the /viteplay? I like the defineLazyMountComponent(), but I think it should be more easy to use the function. Is it possible to have a lazy prop supported by VueFinalModal.vue?

如果你有空的話,可以新增一個範例在 /viteplay 裡嗎? 我希望 defineLazyMountComponent() 可以更方便使用,因為目前使用 VFM 主流的兩種方式應該是使用 useModal() 和在 Template 中使用 VueFinalModal。definLazyMountComponent() 使用在 useModal() 上會怎麼樣我還不確定

Mini-ghost commented 11 months ago

@hunterliu1003 In my case, I often encapsulate modals into components, such as drawers. For these kinds of components, I won't use useModal, but I will explore how to integrate them.

Mini-ghost commented 11 months ago

Usually useModal I would use with asnyc component, it will be loaded as needed, so I think useModal is not needed when using defineLazyMountComponent, defineAsyncComponent is enough