【Nuxt3系列八】切换Transitions

279 阅读4分钟

Nuxt利用Vue的<Transition>组件在页面和布局之间应用过渡。

页面之间切换

可以在nuxt.config.ts中配置全局的自动的切换动画

export default defineNuxtConfig({
  app: {
    pageTransition: { name: 'page', mode: 'out-in' }
  },
})

如果布局和页面同时切换,则页面的切换动画将不会生效。需要设置布局的切换

下面是一个切换的例子

app.vue

<template>
  <NuxtPage />
</template>

<style>
.page-enter-active,
.page-leave-active {
  transition: all 0.4s;
}
.page-enter-from,
.page-leave-to {
  opacity: 0;
  filter: blur(1rem);
}
</style>

想要单独的为某个页面设置切换效果,可以这么设置 在definePageMate中,设置一个pageTransition属性,指定名称

<script setup lang="ts">
definePageMeta({
  pageTransition: {
    name: 'rotate'
  }
})
</script>

然后在app.vue中,定义好转换的css样式

<template>
  <NuxtPage />
</template>

<style>
/* ... */
.rotate-enter-active,
.rotate-leave-active {
  transition: all 0.4s;
}
.rotate-enter-from,
.rotate-leave-to {
  opacity: 0;
  transform: rotate3d(1, 1, 1, 15deg);
}
</style>

由上面两个例子可以看出来,切换的样式命名格式为 [name]-enter-active[name]-enter-active[name]-enter-from[name]-leave-to

布局之间切换

同理,可以在nuxt.config.ts中设置默认的布局切换效果

export default defineNuxtConfig({
  app: {
    layoutTransition: { name: 'layout', mode: 'out-in' }
  },
})

同理,在app.vue中,设置好css

<template>
  <NuxtLayout>
    <NuxtPage />
  </NuxtLayout>
</template>

<style>
.layout-enter-active,
.layout-leave-active {
  transition: all 0.4s;
}
.layout-enter-from,
.layout-leave-to {
  filter: grayscale(1);
}
</style>

命名则是layout加上后缀。

如果需要单独设置,同样的,在vue文件中,设置layoutTransition,然后在app.vue中设置css

<script setup lang="ts">
definePageMeta({
  layout: 'orange',
  layoutTransition: {
    name: 'slide-in'
  }
})
</script>

全局设置

可以在nuxt.config.ts中同时设置pageTransitionlayoutTransition

export default defineNuxtConfig({
  app: {
    pageTransition: {
      name: 'fade',
      mode: 'out-in' // default
    },
    layoutTransition: {
      name: 'slide',
      mode: 'out-in' // default
    }
  }
})

在单独的页面中,也可以随时通过definePageMate进行覆盖设置。

禁止切换效果

在页面单独设置

<script setup lang="ts">
definePageMeta({
  pageTransition: false,
  layoutTransition: false
})
</script>

在配置文件中,全局设置

export default defineNuxtConfig({
 app: {
   pageTransition: false,
   layoutTransition: false
 }
})

JavaScript Hooks

可以通过hooks,自定义一些高级的切换效果。例如可以引入GSAP这种三方库

<script setup lang="ts">
definePageMeta({
  pageTransition: {
    name: 'custom-flip',
    mode: 'out-in',
    onBeforeEnter: (el) => {
      console.log('Before enter...')
    },
    onEnter: (el, done) => {},
    onAfterEnter: (el) => {}
  }
})
</script>

动态设置的切换效果

这个例子,最好到官网看看效果。文字描述不如视频来的直观

官方视频

假设页面通过翻页器来进行切换。

那么想要为上一页设置一个从左到右的动画,为下一页设置一个从右到左的动画

那么我们可以通过内联的路由中间件,设置对应的pageTransition

<script setup lang="ts">
definePageMeta({
  pageTransition: {
    name: 'slide-right',
    mode: 'out-in'
  },
  middleware (to, from) {
    if (to.meta.pageTransition && typeof to.meta.pageTransition !== 'boolean')
      to.meta.pageTransition.name = +to.params.id! > +from.params.id! ? 'slide-left' : 'slide-right'
  }
})
</script>

<template>
  <h1>#{{ $route.params.id }}</h1>
</template>

<style>
.slide-left-enter-active,
.slide-left-leave-active,
.slide-right-enter-active,
.slide-right-leave-active {
  transition: all 0.2s;
}
.slide-left-enter-from {
  opacity: 0;
  transform: translate(50px, 0);
}
.slide-left-leave-to {
  opacity: 0;
  transform: translate(-50px, 0);
}
.slide-right-enter-from {
  opacity: 0;
  transform: translate(-50px, 0);
}
.slide-right-leave-to {
  opacity: 0;
  transform: translate(50px, 0);
}
</style>

NuxtPage使用切换效果

当app.vue中使用<NuxtPage />的时候,可以直接在它上面定义全局的切换效果

<template>
  <div>
    <NuxtLayout>
      <NuxtPage :transition="{
        name: 'bounce',
        mode: 'out-in'
      }" />
    </NuxtLayout>
  </div>
</template>

记住,这个转换不能被页面内的definePageMeta覆盖

视图切换api(View Transitions API)(实验性)

这个是利用Web Api来实现的,详情说明可以看MDN的说明

最终实现个什么效果呢?类似PPT中的平滑切换。保持相同的元素不动或者平移,不同的元素渐入渐出

详情可以看demo源代码.

首先,开启这个实验性的功能

nuxt.config.ts

export default defineNuxtConfig({
  experimental: {
    viewTransition: true
  }
})

viewTransition可以设置为true,false,'alway'。当设置true的时候,应用会去检查浏览器的设置是否为prefers-reduced-motion: reduce,如果是则应用效果。如果是alway,则不会去匹配这个效果。

可以在页面内覆盖这个值

(如果不在nuxt.config.ts开启这个api,只是在这里设置,是无法开启的)

<script setup lang="ts">
definePageMeta({
  viewTransition: false
})
</script>

如果你同时使用基于vue的<Transition>实现的pageTransitionlayoutTransition来实现和View Transitions API相同的效果。当浏览器支持这个原生的View Transitions API的时候,你可能想要禁用重复的Vue的transition仙姑过。你可以通过创建以下的disable-vue-trasitions.global.ts中间件来实现禁用

export default defineNuxtRouteMiddleware(to => {
  if (import.meta.server || !document.startViewTransition) { return }

  // Disable built-in Vue transitions
  to.meta.pageTransition = false
  to.meta.layoutTransition = false
})

已知问题 如果你在vue的setup中执行数据获取的操作,你可能需要重新考虑是否使用这个功能。(按照设计,View Transitions 在进行过程中会完全冻结 DOM 更新。)我们正在研究将 View Transition 限制在 <Suspense> 解析前的最后一刻,但在过渡期间,如果您的情况符合上述描述,您可能需要仔细考虑是否采用此特性。

总结,这个api不太适用于企业后台的展示。