Vue router:如何动态生成动态路由的页面标题?

nic*_*ish 5 vue.js vue-router vue-cli

我有一个使用 Vue CLI 创建的简单的基于 Vue 的网站,我正在尝试弄清楚如何使用动态路由为视图动态生成页面标题。该网站正在从无头 CMS 中提取 JSON 数据,并且我为“项目”内容类型的详细视图设置了动态路由。我的动态路由设置如下:

// single project vue (dynamic)
{
    path: "/projects/:project_name_slug",
    name: "single-project",
    component: () =>
        import(
            /* webpackChunkName: "single-project" */ "./views/SingleProject.vue"
        ),
    meta: {
        title: "project detail",
    }
}
Run Code Online (Sandbox Code Playgroud)

我添加了以下内容,适用于添加静态页面标题:

// show page titles
const DEFAULT_TITLE = "my blog";
router.afterEach((to, from) => {
    // document.title = to.meta.title || DEFAULT_TITLE;
    document.title = "my blog - " + to.meta.title || DEFAULT_TITLE;
});
Run Code Online (Sandbox Code Playgroud)

目前,在访问项目详细信息视图时,标题将显示为“我的博客 - 项目详细信息”;但是,我希望它从 JSON/字段数据中提取实际的项目名称project_name(就像路由路径正在使用一样project_name_slug),但到目前为止我尝试过的任何方法都不起作用。例如,使用meta: { title: (route) => route.params.project_name }just 会导致原始函数文本显示在“我的博客 - ”之后。因此,对于这些动态视图,我想to.meta.title解析为项目名称,创建“我的博客 - {项目名称}”。感谢您在此提供的任何帮助,如果我需要提供更多详细信息,请告诉我。

*注意:这个问题与此 SO 线程中提出的问题不同,因为我的案例涉及使用通过 Axios 请求的 JSON 数据的动态路由

Ohg*_*why 7

我假设您在初始化组件之前询问如何执行此操作,因为您有 SEO 问题,否则就像从 axios 请求中的 JSON 响应中提取它并document.title = myJson.page_title在组件中使用一样简单。

如果您的最终目标是消除由于 SEO 问题而产生的恐惧(这是完全有效的),那么您需要更改方法,以便在组件渲染之前使 JSON 数据可用。

我建议在路线导航防护中发出 axios 请求,并提前对路线属性进行水化,以便您实际上可以访问页面标题。观察:

更新您的路线以接受新的元属性:

meta: {
  title: "project detail",
  content: []
}
Run Code Online (Sandbox Code Playgroud)

axios在包含导航防护的文件中导入并执行 axios 请求以获取和混合content. 改为从 迁移afterEach到 ,beforeEach以便您可以阻止组件的渲染,直到收到数据为止:

import axios from 'axios'

router.beforeEach(async(to, from, next) => {
  const { response } = await axios.get(`/my/cms/endpoint/${to.params.project_name_slug}`)

  document.title = `my blog - ${response.data.title}`

  to.meta.content = response.data.content

  next()
})
Run Code Online (Sandbox Code Playgroud)

我对上面的响应的形状做了一些假设,您需要对其进行修改以适应您的服务器响应。

现在在您的组件中,您将能够访问this.$route.meta.content并且可以在生命周期中利用它mounted来水合本地属性,或者使用 getter 来返回它,我假设您已经在做类似的事情:

export default {
  get pageContent () {
    return this.$route.meta.content
  }
}
Run Code Online (Sandbox Code Playgroud)


Dan*_*Dan 5

meta在路由器的导航守卫中设置beforeEach

router.beforeEach((to, from, next) => {
  to.meta.title = to.params.project_name_slug;
  next();
});
Run Code Online (Sandbox Code Playgroud)

-或者-

您可以使用beforeRouteEnterbeforeRouteUpdate 组件内防护

export default {
  ...
  beforeRouteEnter(to, from, next) {
    to.meta.title = to.params.project_name_slug;
    next();
  },
  beforeRouteUpdate(to, from, next) {
    to.meta.title = to.params.project_name_slug;
    next();
  }
}
Run Code Online (Sandbox Code Playgroud)

afterEach您可以像静态元一样使用它,因为它已经被设置:

const DEFAULT_TITLE = "my blog";
router.afterEach((to, from) => {
    // document.title = to.meta.title || DEFAULT_TITLE;
    document.title = "my blog - " + to.meta.title || DEFAULT_TITLE;
});
Run Code Online (Sandbox Code Playgroud)

注意:在路由定义中使用beforeEnter是不够的,因为从一个动态参数转到另一个动态参数时它不会触发。甚至在更改参数时也<router-view :key="$route.fullPath"></router-view>不会触发beforeEnter。)


Dav*_*ave 5

这是旧的,但以防万一它对任何人有帮助,我刚刚遇到了这个问题,我发现使用 router.afterEach 进行静态标题的组合与动态标题的 mixin 结合使用。

在OP解释的情况下,我将从路由器和afterEach中的任何动态页面中删除title属性,只需检查meta.title

router.afterEach(to => {
  if (to.meta.title) {
    document.title = `${to.meta.title} - my blog`;
  }
});
Run Code Online (Sandbox Code Playgroud)

然后为其他页面创建一个简单的 mixin,如下所示:

export default {
  methods: {
    setTitle(str) {
        document.title = `${str} - my blog`
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

然后,在这些动态页面中,一旦从服务器加载动态数据,您只需使用任何动态数据调用 this.setTitle() 即可。我知道这看起来太容易了,但它确实有效。我在使用您在 SO 上找到的所有 beforeEach 方法时遇到了麻烦。

注意:这不适用于 SEO 或网络爬虫(对此我推荐 prerenderSpa),但确实为您提供了漂亮的标题、后退按钮历史记录和书签。