Nuxt3中NuxtPage与slot的区别、用法及pages页面跳转实现方案
Nuxt3 中 NuxtPage 与 slot 的核心差异
两者根本不是一个层面的组件/API,核心区别可以直接归为三点:
- 服务场景完全不同:
NuxtPage是Nuxt专属的路由出口组件,唯一作用是渲染文件路由匹配到的页面组件;slot是Vue原生的内容分发API,作用是解决父子组件之间的自定义内容传递,和路由逻辑没有任何关联。 - 渲染逻辑触发源不同:
NuxtPage渲染什么内容完全由当前访问的URL路径决定,和上层组件传了什么参数没关系;slot渲染什么内容完全由父组件传入的插槽内容决定,和当前URL是什么没有关系。 - 内置能力不同:
NuxtPage默认自带页面过渡动画、页面级keepalive缓存、滚动位置还原这些路由相关的内置能力;slot就是纯Vue原生的内容占位,没有任何额外的路由相关逻辑。
二者的正确使用方式
NuxtPage 正确用法
它的使用场景非常固定,只有两个地方需要放:
- 全局布局文件(
layouts/目录下的所有布局组件)里,作为整个站点页面内容的渲染出口。很多新手刚接触的时候会在布局里写默认slot想接页面内容,这是错的,必须放<NuxtPage />才能渲染路由匹配到的页面,示例代码:
<!-- layouts/default.vue --> <template> <SiteNav /> <!-- 全局公共导航,所有页面共用 --> <NuxtPage /> <!-- 所有路由匹配到的页面都会渲染在这 --> <SiteFooter /> <!-- 全局公共页脚,所有页面共用 --> </template>
- 嵌套路由的父页面中,作为子路由的渲染出口。比如你有
pages/user.vue作为父路由,对应的子路由是pages/user/profile.vue、pages/user/settings.vue,那就要在user.vue里留<NuxtPage />的位置,子路由页面才会正常渲染。
注意:不要在普通业务组件里随便加NuxtPage,没有匹配的嵌套路由的话,加了也不会渲染任何内容。
slot 正确用法
slot只用于父子组件的内容透传,和路由完全无关。比如你封装一个通用的弹窗、卡片、按钮这类可复用组件,需要让调用方自定义部分区域的内容时,就用slot占位。举个通用卡片组件的例子:
<!-- components/CommonCard.vue --> <template> <div class="card-wrapper"> <!-- 头部具名插槽,调用方可以自定义卡片头部内容 --> <div class="card-header"> <slot name="header" /> </div> <!-- 默认插槽,放卡片主体内容 --> <div class="card-body"> <slot /> </div> <!-- 底部具名插槽,自定义底部按钮区域 --> <div class="card-footer"> <slot name="footer" /> </div> </div> </template>
其他组件调用这个卡片的时候,直接往对应插槽塞自定义内容就行,不需要关心路由是什么。
pages目录路由体系下的页面跳转正确方案
基于pages目录生成路由时,不要自己手动引入vue-router写路由配置,Nuxt会自动按文件结构生成路由表,跳转只用官方提供的两种方案就行,别用原生a标签,会触发整页刷新,丢了SPA的体验。
声明式跳转(模板中使用)
直接用内置的NuxtLink组件,用法和vue-router的RouterLink一致,示例:
<template> <!-- 固定路径跳转 --> <NuxtLink to="/">回到首页</NuxtLink> <!-- 带动态路由参数跳转,推荐用路由名写法,避免路径写错 --> <NuxtLink :to="{ name: 'post-id', params: { id: 1001 } }">查看1001号文章</NuxtLink> <!-- 带查询参数跳转 --> <NuxtLink :to="{ path: '/goods', query: { category: 'book', sort: 'price' } }">图书分类商品</NuxtLink> </template>
编程式跳转(JS逻辑中使用)
用自动导入的navigateTo工具方法,或者useRouter组合式API,适合接口请求完成、表单校验通过这类需要在js逻辑里触发跳转的场景,示例:
<script setup> // 提交表单后跳转 const submitForm = async () => { await validateForm() // 表单校验 await createPostApi() // 调用创建文章的接口 // 跳转到文章列表页 await navigateTo('/post/list') } // 需要做回退、替换历史记录这类操作时用useRouter const router = useRouter() // 返回上一页 const backPrev = () => router.back() // 替换当前历史记录,不会产生新的浏览记录 const replaceToLogin = () => router.replace('/login') </script>
踩坑提示:跳转动态路由传params的时候,不要用path+params的写法,params会被忽略,要么写完整路径,要么用name+params的写法。
内容的提问来源于stack exchange,提问作者DenicioCode
相关产品推荐
相关产品推荐

