nuxt / ui

A UI Library for Modern Web Apps, powered by Vue & Tailwind CSS.
https://ui.nuxt.com
MIT License
4.13k stars 544 forks source link

[v3] `Carousel` autoplay doesn't work after switching pages with pageTransition #2517

Closed BasoAlter closed 2 days ago

BasoAlter commented 3 weeks ago

Environment

Version

v3.0.0-alpha.7

Reproduction

  1. Clone the repository https://github.com/BasoAlter/nuxt-carousel-transition
  2. Run the server, then on the main page has autoplay carousel and a link to other page
  3. Click the other page link. At other page, it has a link to main page, then click it
  4. The autoplay carousel will not work after that and no error log

Description

The autoplay still works when I don't use the pageTransition in nuxt.config.ts. But when I do use it, somehow it doesn't work again after changing the page.

Additional context

No response

Logs

No response

benjamincanac commented 2 weeks ago

Have you tried calling the play method yourself?

BasoAlter commented 2 weeks ago

You mean from the carousel's ref, right? Unfortunately, the plugins method returns an empty object before I reach the play method, even though the type hint lists autoplay and its play method. I've tried calling it in both onMounted and watch. Here's the code:

<script setup lang="ts">
const items = [
  'https://picsum.photos/640/640?random=0',
  'https://picsum.photos/640/640?random=1',
  'https://picsum.photos/640/640?random=2',
  'https://picsum.photos/640/640?random=3',
]
const carouselRef = useTemplateRef('carouselRef')

onMounted(() => {
  if (carouselRef.value?.emblaApi) {
    const plugins = carouselRef.value.emblaApi.plugins()

    console.log(
      'onMounted',
      // plugins() returns an empty object
      plugins,
      // type hint displays `autoplay` and `play` without optional chaining
      // but it throws an undefined error
      plugins.autoplay.play(),
    )
  }
})

watch(carouselRef, (newValue) => {
  if (newValue?.emblaApi) {
    // same result as above
    console.log('watch', newValue.emblaApi.plugins())
  }
}, { deep: true })
</script>

<template>
  <main>
    <ULink to="/other">other page</ULink>
    <UCarousel v-slot="{ item }" :items="items" dots loop autoplay ref="carouselRef">
      <img :src="item" width="320" height="320" class="rounded-lg" />
    </UCarousel>
  </main>
</template>
BasoAlter commented 2 days ago

I think the issue can be solved temporarily by defining a boolean ref that is set to true inside the onMounted, and then passing it to the autoplay prop. Here's the code:

<script setup lang="ts">
const items = [
  'https://picsum.photos/640/640?random=0',
  'https://picsum.photos/640/640?random=1',
  'https://picsum.photos/640/640?random=2',
  'https://picsum.photos/640/640?random=3',
]
const isMounted = ref(false)

onMounted(() => {
  isMounted.value = true
})
</script>

<template>
  <main>
    <ULink to="/other">other page</ULink>
    <UCarousel v-slot="{ item }" :items="items" dots loop :autoplay="isMounted">
      <img :src="item" width="320" height="320" class="rounded-lg" />
    </UCarousel>
  </main>
</template>

Updated code on my repository https://github.com/BasoAlter/nuxt-carousel-transition/blob/master/pages/index.vue#L8-L18