【问题标题】:How can I bind the html <title> content in vuejs?如何在 vuejs 中绑定 html <title> 内容?
【发布时间】:2016-08-05 09:38:48
【问题描述】:

我正在尝试在 vuejs 上进行演示。现在我想让 html 标题绑定一个 vm 字段。

以下是我尝试过的:

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

但标题似乎没有限制,如何使它工作?

【问题讨论】:

  • 试试el: document.documentElement
  • 我总是将 Vue 绑定到 body,然后在需要更新时设置 document.title。从概念上讲,这似乎是可能的,但我从未见过这种方式。
  • 在我的例子中'hello'是计算出来的。我使用 v-bind:title="hello"

标签: javascript html mvvm frontend vue.js


【解决方案1】:

基本上有两种方法可以解决。

使用现有的包

例如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>

创建自己的组件

创建一个包含以下内容的 vue 文件:

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

使用注册组件

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

然后你可以在你的模板中使用它,例如

<vue-title title="Static Title"></vue-title>
<vue-title :title="dynamic.something + ' - Static'"></vue-title>

【讨论】:

  • +1 我会这样做,因为将 Vue 实例安装到 html 标记(而不是正文中的隔离包装器)被认为是不好的做法。
  • 在 vue 2 中是 mounted 而不是 created
  • @Jared 不,不是。两者实际上都是有效的lifecycle hooks,但createdmounted 之前被调用。
  • @str 是对的,我的错。只是在我的用例中(与 OP 略有不同)created 没有成功——我不得不改用mounted
  • 太棒了!为我工作! Bur 我对描述有一个小问题(不工作)。我在我的模板中添加了元描述标签来解决这个问题。
【解决方案2】:

您可以使用 App.vue 文件中的 1 行来完成,如下所示:

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

或者更改public/index.html中的&lt;title&gt;标签内容

<!DOCTYPE html>
<html>
  <head>
    <title>Look Ma!</title> <!- ------ Here ->
  </head>
...

【讨论】:

  • 这种方法对SEO真的有用吗?如果我右键单击我的网站并选择View Page Source,我会看到标题、描述、关键字不会改变。我看起来怀疑这种方式是否正确
  • 第一个对你没有好处。第二个稍微好一点,但它不会为您提供真正深度优化的全部好处。请注意,OP 问题与 SEO 无关。
  • @positivethinking 现代网络爬虫将加载 JavaScript 并等待整个网页呈现后再检查它。更改文档的标题属性时会影响 HTML 内容,但通常“查看源代码”中的源代码在初始页面加载后不会更改。您检查一下 HTML 是否发生了如下变化:document.title = 'whatever'; document.querySelector('title').innerHTML 您还可以使用开发者控制台删除页面的全部内容,然后在“查看源代码”中查看它是否仍然存在。
【解决方案3】:

此答案适用于 vue 1.x

使用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>

你可以像这样使用 ready 函数来设置初始值并观察数据变化时的更新。

<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>

我也根据您的原始代码尝试了这个,它可以工作

<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>

【讨论】:

  • 干得好,谢谢,我终于发现我失败了,因为el元素设置不正确(实际上我设置为'body')。所以在html元素上绑定vm就可以了!
  • 你也可以只限定 元素,执行 el: 'title'
  • 您在 Vue 2.4.2 中收到警告:[Vue warn]: Do not mount Vue to &lt;html&gt; or &lt;body&gt; - mount to normal elements instead.
  • @Damian C 这种方法对 SEO 真的有用吗?如果我右键单击我的网站并选择View Page Source,我会看到标题、描述、关键字不会改变。我看起来怀疑这种方式是否正确
【解决方案4】:

只是在这里插话。我读过 VueJS 不想与元数据有任何关系,所以我会在“VueJS”领域之外做这些事情。

基本上制作一个普通的 js 服务,如下所示。在这里,您可以添加所有函数来处理元数据内容,例如 Open Graph 数据。

meta.js

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

现在我们可以在 main 中导入服务,然后将其提供给应用程序中需要它的任何组件。我什至可以在使用 React 或 Angular 等不同框架的其他项目中使用我的 meta 服务。便携性太棒了!

main.js

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

组件在这里注入它想要使用的元服务。

someView.vue

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

这样元服务就与应用解耦了,因为不同的父组件可以provide不同版本的meta服务。现在您可以实施各种策略来查看哪种策略适合您,甚至每个组件的不同策略。

基本上,注入沿着组件层次结构向上走,并从提供它的第一个父级获取meta 服务。只要元服务遵循正确的界面,您就是黄金。

用 DI 解耦超级爽?

【讨论】:

    【解决方案5】:

    标题和元标记可以异步编辑和更新。

    您可以使用状态管理,使用 vuex 为 SEO 创建一个商店并相应地更新每个部分。

    或者你可以自己轻松更新元素

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

    【讨论】:

      【解决方案6】:

      如果您正在使用 Vuex 并希望 &lt;title&gt; 成为您的应用程序状态的一部分,那么:

      • 在 Vuex 中创建 pageTitle 状态变量
      • 使用mapState()将状态映射到模板
      • watch 在模板中,可能添加immediate: true 以立即触发观察者
      • 在观察者中,document.title = pageTitle

      这将允许您使用 Vuex 管理标题并使它们保持同步。我发现它对 SPA 很有用。

      通过这样做,您不必弄乱原始 HTML 模板,因为大多数时候 Vue 根模板位于 &lt;body&gt; 中。

      这是针对 Vue 2.x 的。

      【讨论】:

        【解决方案7】:
        router.beforeEach((to, from, next) => {
          let mohican = to.path; if (mohican == '/') mohican = 'Home'
          document.title =  mohican.replace('/','');
          next();
         return;
        });
        

        【讨论】:

          【解决方案8】:

          我有一个应用程序工具栏组件,它对我的​​ SPA 网站的所有页面都是通用的,并且嵌套在 App.vue 中。在每个页面中,我都会使用 Vuex 商店在页面的 created 挂钩中更新我的常用工具栏标题:

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

          为了自动更新网站标题(连同工具栏标题),我在商店中使用了这个突变:

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

          同样,我使用相同的机制进行更新,例如SEO元数据

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2017-04-18
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-08-09
            • 1970-01-01
            • 2014-05-31
            相关资源
            最近更新 更多