How to change page titles when using vue-router?

Solution 1:

You can use a navigation guard with the router definition:

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;
    });
});

You'll need to change your export to:

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

Or you can use an immediate watcher on your root component:

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

Solution 2:

Advanced variant

Using vue-meta

first run npm install vue-meta

and include it into your main.js;

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

after doing so you can add a metaInfo() method to every vue component, handling meta data;

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'} 
            ]
        }
    }

Furthermore this can be used for dynamic meta info;

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' }    
            ]
        }
    },
    ...
}

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

Solution 3:

I'd like to add that above doesn't really preserve history as it should. See https://github.com/vuejs/vue-router/issues/914#issuecomment-384477609 for a better answer that actually takes care of the history (albeit a little bit hacky).

Solution 4:

Actually, based on my experiments with Steven B.'s solution, I've came up with something a bit better. The thing is this

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

doesn't work when we visit the page initially (by navigating via brower's address bar). Instead, we can create a getter like this:

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

Now in my case I was looking to set the "template"'s header (so that children routes don't bother about it) so that was it; for your case you may wonder how to set document's title once you have computed property, and there are some ways. Based on those answers, you can even do:

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

but I'd test this for the case of revisiting the same page (not sure if the component is created each time) before using in production.

Solution 5:

Latest Works way in 2021- Vue3:

Add the line name for related Component in .\router\index.js

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

Load it in BeforeEach this function also write it in .\router\index.js

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