使用 vue-router 时如何更改页面标题?

Posted

技术标签:

【中文标题】使用 vue-router 时如何更改页面标题?【英文标题】:How to change page titles when using vue-router? 【发布时间】:2019-01-09 09:54:03 【问题描述】:

如果可能,我想在路线定义中指定我的头衔。通常在<head><title> 中指定并显示在浏览器标题栏中的内容。

我的项目设置如下:

ma​​in.js

import Vue from 'vue'
import App from './App.vue'
import VeeValidate from 'vee-validate';
import router from './router'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';

Vue.use(VeeValidate);
Vue.use(ElementUI);
Vue.config.productionTip = false

new Vue(
    router,
    render: h => h(App)
).$mount('#app')

router.js

import Vue from 'vue'
import Router from 'vue-router'
import Skills from './components/Skills.vue'
import About from './components/About.vue'

Vue.use(Router)

export default new Router(
  routes: [
    
      path: '/',
      name: 'skills',
      component: Skills,
      meta:  title: 'Skills - MyApp'  // <- I would to use this one
    ,
    
      path: '/about/:name',  // Add /:name here
      name: 'about',
      component: About,
      meta:  title: 'About - MyApp' 
    
  ]
)

最好是,我想要一个自动系统,而不是在每个组件的创建功能上更改页面标题。谢谢。

【问题讨论】:

【参考方案1】:

您可以在路由器定义中使用导航守卫:

import Vue from 'vue';

const DEFAULT_TITLE = 'Some Default Title';
router.afterEach((to, from) => 
    // Use next tick to handle router history correctly
    // see: https://github.com/vuejs/vue-router/issues/914#issuecomment-384477609
    Vue.nextTick(() => 
        document.title = to.meta.title || DEFAULT_TITLE;
    );
);

您需要将导出更改为:

const router = new Router( ... );
...
export default router;

或者你可以在你的根组件上使用即时观察器:

export default 
    name: 'App',
    watch: 
        $route: 
            immediate: true,
            handler(to, from) 
                document.title = to.meta.title || 'Some Default Title';
            
        ,
    
;

【讨论】:

使用beforeEach不是更好吗? 啊,明白了!不错的信息。我正在使用beforeEach,所以我必须调用next(),就像在doc 中一样。 我认为我认为afterEach 在这种情况下是更好的做法,因为它不是必须在导航发生之前发生的事情(例如身份验证检查进入beforeEach,因为它们有可能取消导航,在导航已被确认时更新afterEach 中的视觉内容),但我认为它在性能或任何方面没有任何区别,如果这是你唯一需要做的事情。 很好,但是我最初如何设置标题(当页面通过地址栏中的 url 手动打开时,而不是通过导航)? (目前我只测试了watch 方法,在这种情况下它没有设置标题,这是可以预测的) @CatoMinor 我更新了我的答案。从测试来看,没有nextTick,watcher 方法似乎可以正常工作。【参考方案2】:

高级变体

使用 vue-meta

第一次运行 npm install vue-meta

并将其包含在您的 ma​​in.js 中;

import VueMeta from 'vue-meta'
Vue.use(VueMeta)

这样做之后,您可以为每个 vue 组件添加一个metaInfo() 方法,处理元数据;

metaInfo() 
        return  
            title: "Epiloge - Build your network in your field of interest",
            meta: [
                 name: 'description', content:  'Epiloge is about connecting in your field of interest. Our vision is to help people share their knowledge, work, projects, papers and ideas and build their network through what they do rather where they live, study or work.',
                 property: 'og:title', content: "Epiloge - Build your network in your field of interest",
                 property: 'og:site_name', content: 'Epiloge',
                property: 'og:type', content: 'website',    
                name: 'robots', content: 'index,follow' 
            ]
        
    

此外,这可用于动态元信息

export default
    name: 'SingleUser',
    data()
        return
            userData: ,
            ...
            aws_url: process.env.AWS_URL,
        
    ,  
    metaInfo() 
        return 
            title: `$this.userData.name - Epiloge`,
            meta: [
                 name: 'description', content: 'Connect and follow ' + this.userData.name + ' on Epiloge - ' + this.userData.tagline,
                 property: 'og:title', content: this.userData.name + ' - Epiloge',
                 property: 'og:site_name', content: 'Epiloge',
                 property: 'og:description', content: 'Connect and follow ' + this.userData.name + ' on Epiloge - ' + this.userData.tagline,
                property: 'og:type', content: 'profile',
                property: 'og:url', content: 'https://epiloge.com/@' + this.userData.username,
                property: 'og:image', content: this.aws_url + '/users/' + this.userData.profileurl + '-main.jpg'     
            ]
        
    ,
    ...

来源:Medium - How to add dynamic meta-tags to your Vue.js app for Google SEO

【讨论】:

我遵循了这个例子,但这只是更新了标题,而不是 OG 标签。我有什么遗漏吗? OG标签是什么意思? @nonNumericalFloat 很可能是 OpenGraph 元标记,例如 Facebook 用于从链接构建嵌入。【参考方案3】:

我想补充一点,上面并没有真正保留历史。请参阅https://github.com/vuejs/vue-router/issues/914#issuecomment-384477609 以获得更好的答案,该答案实际上会处理历史(尽管有点老套)。

【讨论】:

这似乎很重要。 TBH,我不明白为什么这没有受到更多关注。 (在编辑之后)接受的答案已经解决了这个问题(通过使用 afterEach 并调用 nextTick)。【参考方案4】:

实际上,根据我对 Steven B. 解决方案的实验,我想出了一些更好的方法。事情是这样的

watch: 
    $route(to, from) 
        document.title = to.meta.title || 'Some Default Title';
    ,

当我们最初访问页面时不起作用(通过浏览器的地址栏导航)。相反,我们可以像这样创建一个 getter:

computed: 
    pageTitle: function() 
        return this.$route.meta.title;
    

现在就我而言,我正在寻找设置“模板”的标题(这样子路由就不会打扰它),就是这样;对于您的情况,您可能想知道如何在计算属性后设置文档的标题,并且有 some ways。根据这些答案,您甚至可以这样做:

created () 
    document.title = this.$route.meta.title;

但我会在生产中使用之前重新访问同一页面(不确定是否每次都创建组件)的情况下对此进行测试。

【讨论】:

将“立即”属性添加到被监视的属性是一个更好的选择。请参阅上面的其他答案 @JoeGalind 感谢您的指点,但您能详细说明一下“更好”吗? router.afterEach 方法会在初始导航时触发【参考方案5】:

2021 年最新工作方式-Vue3:

.\router\index.js中添加相关组件的行名

  
  path: '/',
  name: 'Home page'
  ,

Load it in BeforeEach 这个函数也写在.\router\index.js

router.beforeEach((to, from, next) => 
  document.title = to.name;
  next();
);

【讨论】:

【参考方案6】:

我发现这个解决方案使用 mixins 并且需要最少的代码。

https://medium.com/@Taha_Shashtari/the-easy-way-to-change-page-title-in-vue-6caf05006863 原来是https://github.com/vuejs/vue-hackernews-2.0/blob/master/src/util/title.js

我喜欢它,因为您可以在视图组件中定义标题而不是路由:

在 src/mixins 目录中创建一个名为 titleMixin.js 的新文件,其内容如下。它正在检查组件的 'title' 属性的值是否是变量或函数,并返回 title 变量的值或 title() 的返回值功能。

function getTitle (vm) 
  const  title  = vm.$options
  if (title) 
    return typeof title === 'function'
      ? title.call(vm)
      : title
  
export default 
  created () 
    const title = getTitle(this)
    if (title) 
      document.title = title
    
  

在您的 ma​​in.js 中全局注册 mixin。在创建 Vue 实例之前添加:

import titleMixin from './mixins/titleMixin'

Vue.mixin(titleMixin)

最后,在视图组件文件(例如 Home.vue )中使用名为 title 的属性来定义页面的标题。

export default 
  name: 'Home',
  title: 'Homepage Title',
  components: 
    ...
  

一个小缺陷:mixin 是全局注册的,这使得 mixin 可用于 所有 组件,即使对于没有意义的 non view 组件也是如此。

【讨论】:

【参考方案7】:

我正在寻找编辑标题,但不一定要使用路由器。我发现使用mounted方法也可以做到。

new Vue(
  mounted: function() 
    document.title = 'WOW VUE TITLE'
  
)

【讨论】:

【参考方案8】:

对于 vue 3:

Navigation Guards

import  createRouter, createWebHistory  from 'vue-router';

const router = createRouter(
  history: createWebHistory(config.publicPath),
  routes,
);

const DEFAULT_TITLE = 'Some Default Title';
router.beforeEach((to) => 
  document.title = to.meta.title || DEFAULT_TITLE;
);

【讨论】:

您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center。 最好将 afterEach 替换为 beforeEach,这样在页面完全重新加载之前您就不会看到旧标题

以上是关于使用 vue-router 时如何更改页面标题?的主要内容,如果未能解决你的问题,请参考以下文章

vue-router 不会在路由更改时渲染新组件

Vue 在页面更改时注入

如何通过路由器名称将 Vuetify 选项卡与 vue-router 一起使用

vuejs vue-router 不适用于 Firebase 托管

VueJs:使用 vue-router 的两个独立且独立的路由/视图

如何以编程方式更改 Vuetify 选项卡和 vue-router