How can I bind the html <title> content in vuejs?
Asked Answered
L

10

85

I'm trying a demo on vuejs. Now I want the html title to bind a vm field.

The below is what I tried:

index.html

<!DOCTYPE html>
<html id="html">
<head>
    <title>{{ hello }}</title>
    <script src="lib/requirejs/require.min.js" data-main="app"></script>
</head>
<body>
{{ hello }}
<input v-model="hello" title="hello" />
</body>
</html>

app.js

define([
    'jquery', 'vue'
], function ($, Vue) {
    var vm = new Vue({
        el: 'html',
        data: {
            hello: 'Hello world'
        }
    });
});

But the title seemed not bounded, how to make it work?

Lugworm answered 14/4, 2016 at 2:33 Comment(3)
Try el: document.documentElementPodite
I've always bound Vue to the body and then set document.title when I needed to update it. Conceptually this seems possible but I've never seen it this way.Caviar
in my case 'hello' is computed. i use v-bind:title="hello"Weksler
L
117

There are essentially two ways to solve it.

Use an existing Package

For example, vue-meta:

<template>
  <div id="app">
    <router-view></router-view>
  </div>
</template>

<script>
  export default {
    name: 'App',
    metaInfo: {
      // if no subcomponents specify a metaInfo.title, this title will be used
      title: 'Default Title',
      // all titles will be injected into this template
      titleTemplate: '%s | My Awesome Webapp'
    }
  }
</script>

Create your own Component

Create a vue file containing:

<script>
    export default {
        name: 'vue-title',
        props: ['title'],
        watch: {
            title: {
                immediate: true,
                handler() {
                    document.title = this.title;
                }
            }
        },
        render () {
        },
    }
</script>

Register the component using

import titleComponent from './title.component.vue';
Vue.component('vue-title', titleComponent);

Then you can use it in your templates, e.g.

<vue-title title="Static Title"></vue-title>
<vue-title :title="dynamic.something + ' - Static'"></vue-title>
Latency answered 2/11, 2016 at 19:23 Comment(14)
+1 I'd go with this since it's considered bad practise mounting your Vue instance to the html tag (instead of an isolated wrapper in body).Entrap
In vue 2 it's mounted instead of createdPlasmodium
@Plasmodium No, it's not. Both are actually valid lifecycle hooks but created is called before mounted.Latency
@Latency is right, my bad. It was just that in my use case (slightly different than OP's) created didn't work out - I had to use mounted instead.Plasmodium
awesome! work for me! Bur I Have a small problem with description (dont work). I add meta description tag to my template for solving this.Eniwetok
@Latency Maybe you can help me. Look at this : #59113111Escapement
@Latency The title content is change. But if I right-click on the website and select View Page Source, I see the title, description and keywords is don't changeEscapement
@SuccessMan Yes that is how JavaScript DOM manipulations work. If that is not what you need, you have to change the meta data on the backend.Latency
@Latency What do you mean "change the meta data on the backend"?Escapement
@SuccessMan The backend sends the source code to the browser and that is what "View Page Source" will show. JavaScript can only change the content after is has been sent to the browser.Latency
@Latency Do you have a reference on how to do that?Escapement
@SuccessMan No because that highly depends on the technologies you are using and what exactly you want to do with it.Latency
@Latency I use vuetify. I want my website to support SEO. Each time a page is accessed, the title and description changes according to the page title and descriptionEscapement
@Latency metaInfo can be also dynamic, declaring metaInfo() in child instance.Acceptation
E
68

You can do it with 1 line in the App.vue file, like this:

<script>
    export default {
        name: 'app',
        created () {
            document.title = "Look Ma!";
        }
    }
</script>

Or change the <title> tag content in public/index.html

<!DOCTYPE html>
<html>
  <head>
    <title>Look Ma!</title> <!- ------ Here ->
  </head>
...
Empiricism answered 4/4, 2018 at 4:37 Comment(3)
Is this method really useful for SEO? if I right-click on my website and select View Page Source, I see the title, description, keywords don't change. I look doubtful this way is correctEscapement
The first one will not do you good. The second is a little better but it will not give you the full benefit of a true in depth optimization. Please note the OP question was NOT about SEO.Empiricism
@positivethinking Modern web crawlers will load JavaScript and wait for the whole webpage to render before examining it. The HTML content is affected when the title property of the document is changed, but typically the source in "view source" never changes after the initial page load. You check to see the HTML changed like this: document.title = 'whatever'; document.querySelector('title').innerHTML You can also delete the entire contents of the page using the developer console and see that it's still there in "view source".Miocene
V
6

This answer is for vue 1.x

using requirejs.

define([
  'https://cdn.jsdelivr.net/vue/latest/vue.js'
], function(Vue) {
  var vm = new Vue({
    el: 'html',
    data: {
      hello: 'Hello world'
    }
  });
});
<!DOCTYPE html>
<html id="html">

<head>
  <title>{{ hello }}</title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.2.0/require.js" data-main="app"></script>
</head>

<body>
  {{ hello }}
  <input v-model="hello" title="hello" />
</body>

</html>

you can do it like this using the ready function to set the initial value and watch to update when the data changes.

<html>
<head>
<title>Replace Me</title>
</head>
<body>
<script src="https://cdn.jsdelivr.net/vue/latest/vue.js"></script>

<div id="app">
  <input v-model="title">
</div>


<script>
new Vue({
    el: '#app',
    ready: function () {
        document.title = this.title
    },
    data: {
        title: 'My Title'
    },
    watch: {
        title: function (val, old) {
            document.title = val
        }
    }
})
</script>

</body>
</html>

also i tried this based on your original code and it works

<html>
<head>
<title>{{ title }}</title>
</head>
<body>
<script src="https://cdn.jsdelivr.net/vue/latest/vue.js"></script>

<div id="app">
  <input v-model="title">
</div>

<script>
new Vue({
    el: 'html',
    data: {
        title: 'My Title'
    }
})
</script>

</body>
</html>
Villosity answered 14/4, 2016 at 5:55 Comment(4)
Well done, thank you, and I finally found that I was failed because the el element is not set correctly(I set it to 'body' in fact). So binding the vm on html element can work well!Lugworm
You can also scope to just the <title> element, doing el: 'title'Ruction
You get a warning in Vue 2.4.2 : [Vue warn]: Do not mount Vue to <html> or <body> - mount to normal elements instead.Citole
@Damian C Is this method really useful for SEO? if I right-click on my website and select View Page Source, I see the title, description, keywords don't change. I look doubtful this way is correctEscapement
H
5

Just to chime in here. I have read that VueJS wants nothing to do with the meta stuff so I would do such things outside of the "VueJS" realm.

Basically make a plain vanilla js service like below. Here you could add all the functions to handle the meta data stuff such as the Open Graph data.

meta.js

export setTitle(title) {
    document.title = title  
}

Now we can import the service in main and then provide it to any component in the app who wants it. I could even use my meta service in other projects too which use different frameworks like React or Angular. Portability is super cool!

main.js

import meta from './meta'
new Vue({
    router,
    render: h => h(App),
    provide: {
        meta: meta
    }
}).$mount('#app')

Here the component injects the meta service it wants to use.

someView.vue

export default {
    name: 'someView',
    inject: ['meta'],
    data: function() {
        returns {
            title: 'Cool title'
        }
    },
    created: function() {
        this.meta.setTitle(this.title);
    }
}

This way the meta service is decoupled from the app because different parent components can provide different versions of the meta service. Now you can implement various strategies to see which one is right for you or even different strategies per component.

Basically the inject walks up the component hierarchy and takes the meta service from the first parent who provides it. As long as the meta service follows a proper interface, you're golden.

Decoupling with DI is super cool 😃

Haymo answered 13/3, 2019 at 18:30 Comment(0)
O
3

Title and meta tags can be edited and updated asynchronously.

You can use state management, create a store for SEO using vuex and update each part accordingly.

Or you can update the element by yourself easily

created: function() {  

  ajax().then(function(data){
     document.title = data.title  
     document.head.querySelector('meta[name=description]').content = data.description
  })

}
Ohmage answered 2/4, 2017 at 12:49 Comment(0)
P
2

If you are using Vuex and want <title> to be part of your application state, then:

  • create a pageTitle state variable in Vuex
  • map the state to the template using mapState()
  • watch it in template, probably add immediate: true to trigger the watcher right away
  • in watcher, document.title = pageTitle

This will allow you to manage title with Vuex and keep them in sync. I found it useful for SPAs.

By doing this you don't have to mess with your original HTML template, as most of the time Vue root template resides inside <body>.

This is for Vue 2.x.

Pastiche answered 31/12, 2020 at 2:29 Comment(0)
S
1

I have an application toolbar component which is common for all pages of my SPA website and is nested in App.vue. In every page I update my common toolbar title in the created hook of the page using Vuex store:

//in every page.vue
created() {
  this.$store.commit('toolBar', { pageTitle: this.pageTitle, ...  })
},

To automatically update the website title (along with the toolbar title) I use this mutation in the store:

//store.js
toolBar(state,val){
  document.title = val.pageTitle
  state.toolBar = val
},

Similarly, I use the same mechanism to update e.g. SEO metadata

Sunda answered 4/7, 2021 at 13:47 Comment(0)
D
0
router.beforeEach((to, from, next) => {
  let mohican = to.path; if (mohican == '/') mohican = 'Home'
  document.title =  mohican.replace('/','');
  next();
 return;
});
Dvandva answered 17/3, 2021 at 7:27 Comment(0)
L
0

just pass

:title="data.name"

Lynch answered 10/12, 2022 at 13:12 Comment(0)
D
0

You can use Vue Router with meta tag.

import { createRouter } from "vue-router";

const router = createRouter({
    routes: [
        {
            path: "/",
            name: "Intro",
            component: () =>
            import(/* webpackChunkName: "Intro" */ "../views/Intro.vue"),
            meta: {
                disableIfLoggedIn: true,
                title: "J6 Cafe",
            },
        }
    ]
});

router.beforeEach((to, from, next) => {
    //return meta title or else return My Default title
    document.title = to.meta.title ?? "My Default title";
});

Source: https://mokkapps.de/vue-tips/dynamically-change-page-title

Dichromatism answered 15/2 at 6:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.