You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Nuxt动态路由适配:基于CMS slug与页面类型映射实现路由

我之前也遇到过类似的CMS自定义slug和Nuxt路由匹配的问题,给你分享几个亲测可行的实现思路:

实现思路与步骤

1. 创建统一动态路由入口

首先在pages目录下创建[slug].vue文件,作为所有自定义slug页面的统一入口——它会匹配所有/xxx形式的URL(注意:Nuxt路由优先级是固定路由>动态路由,建议删掉原来的portfolio、contact固定页面,统一用动态路由处理)。

2. 根据页面类型动态渲染组件

在[slug].vue中,通过异步方法从Wagtail API获取当前slug对应的页面类型,再根据类型动态导入并渲染对应的组件。

Nuxt 2 示例代码:

<template>
  <div>
    <component :is="pageComponent" v-if="pageComponent" />
    <div v-else>404 页面不存在</div>
  </div>
</template>

<script>
export default {
  async asyncData({ params, error }) {
    // 从Wagtail API获取页面信息(包含pageType)
    const pageData = await fetch(`你的WagtailAPI地址/pages?slug=${params.slug}`)
      .then(res => res.json())
      .catch(err => {
        error({ statusCode: 500, message: '页面数据加载失败' })
        return null
      })

    if (!pageData) {
      error({ statusCode: 404, message: '页面不存在' })
      return {}
    }

    // 根据页面类型匹配对应组件
    let pageComponent
    switch (pageData.pageType) {
      case 'portfolio.PortfolioIndexPage':
        pageComponent = () => import('~/pages/portfolio/index.vue') // 原portfolio页面内容迁移到这里
        break
      case 'contact.ContactPage':
        pageComponent = () => import('~/pages/contact/index.vue') // 原contact页面内容迁移到这里
        break
      default:
        error({ statusCode: 404, message: '未知页面类型' })
    }

    return { pageComponent, pageData }
  }
}
</script>

Nuxt 3 示例代码:

<template>
  <div>
    <component :is="pageComponent" v-if="pageComponent" />
    <div v-else>404 页面不存在</div>
  </div>
</template>

<script setup>
const route = useRoute()
const { data: pageData, error: fetchError } = await useAsyncData('pageData', () => {
  return $fetch(`你的WagtailAPI地址/pages?slug=${route.params.slug}`)
})

let pageComponent = null
if (pageData.value) {
  switch (pageData.value.pageType) {
    case 'portfolio.PortfolioIndexPage':
      pageComponent = await import('~/pages/portfolio/index.vue')
      break
    case 'contact.ContactPage':
      pageComponent = await import('~/pages/contact/index.vue')
      break
    default:
      throw createError({ statusCode: 404, message: '未知页面类型' })
  }
}

if (fetchError.value) {
  throw createError({ statusCode: 500, message: '页面数据加载失败' })
}
</script>

3. 优化nuxt-link跳转逻辑

你提到的理想写法需要调整,Nuxt路由名称基于文件结构,动态路由[slug].vue的默认名称是[slug](Nuxt2)或slug(Nuxt3)。建议传递slug参数的同时带上pageType,避免重复请求API:

Nuxt 2 跳转示例:

<nuxt-link 
  :to="{ 
    name: '[slug]', 
    params: { 
      slug: item.slug, 
      pageType: item.pageType 
    } 
  }"
>
  {{ item.title }}
</nuxt-link>

然后在[slug].vue的asyncData里优先使用传递的pageType:

async asyncData({ params, error }) {
  let pageData, pageType
  // 如果从nuxt-link传入了pageType,直接复用
  if (params.pageType) {
    pageType = params.pageType
    pageData = await fetch(`你的WagtailAPI地址/pages?slug=${params.slug}`).then(res => res.json())
  } else {
    // 否则从API获取
    pageData = await fetch(`你的WagtailAPI地址/pages?slug=${params.slug}`).then(res => res.json())
    pageType = pageData.pageType
  }
  // ...后续组件匹配逻辑不变
}

Nuxt 3 跳转示例:

<NuxtLink 
  :to="{ 
    name: 'slug', 
    params: { 
      slug: item.slug, 
      pageType: item.pageType 
    } 
  }"
>
  {{ item.title }}
</NuxtLink>

4. 进阶优化:路由中间件统一处理

如果页面类型较多,可以用路由中间件统一处理页面类型的获取和验证,减少重复代码。比如创建middleware/pageType.js:

Nuxt 2 中间件示例:

export default async function({ params, error, store }) {
  if (!params.pageType) {
    const pageData = await fetch(`你的WagtailAPI地址/pages?slug=${params.slug}`).then(res => res.json())
    if (!pageData) {
      error({ statusCode: 404, message: '页面不存在' })
      return
    }
    params.pageType = pageData.pageType
    store.commit('setPageData', pageData)
  }
}

然后在[slug].vue中启用该中间件:

export default {
  middleware: 'pageType'
}

5. SEO 适配

别忘了根据页面类型和数据设置对应的SEO标签:

Nuxt 2:

head() {
  return {
    title: this.pageData?.title || '默认标题',
    meta: [
      { hid: 'description', name: 'description', content: this.pageData?.description || '默认描述' }
    ]
  }
}

Nuxt 3:

useHead({
  title: pageData.value?.title || '默认标题',
  meta: [
    { name: 'description', content: pageData.value?.description || '默认描述' }
  ]
})

这样就能完美实现:URL显示自定义slug,根据CMS返回的页面类型渲染对应组件,同时支持高效的nuxt-link跳转。

内容的提问来源于stack exchange,提问作者Enquest

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 09:28:39