• Head 管理

    Head 管理

    类似于资源注入,Head 管理遵循相同的理念:我们可以在组件的生命周期中,将数据动态地追加到渲染上下文 (render context),然后在模板中的占位符替换为这些数据。

    在 2.3.2+ 的版本,你可以通过 this.$ssrContext 来直接访问组件中的服务器端渲染上下文(SSR context)。在旧版本中,你必须通过将其传递给 createApp() 并将其暴露于根实例的 $options 上,才能手动注入服务器端渲染上下文(SSR context) - 然后子组件可以通过 this.$root.$options.ssrContext 来访问它。

    我们可以编写一个简单的 mixin 来完成标题管理:

    1. // title-mixin.js
    2. function getTitle (vm) {
    3. // 组件可以提供一个 `title` 选项
    4. // 此选项可以是一个字符串或函数
    5. const { title } = vm.$options
    6. if (title) {
    7. return typeof title === 'function'
    8. ? title.call(vm)
    9. : title
    10. }
    11. }
    12. const serverTitleMixin = {
    13. created () {
    14. const title = getTitle(this)
    15. if (title) {
    16. this.$ssrContext.title = title
    17. }
    18. }
    19. }
    20. const clientTitleMixin = {
    21. mounted () {
    22. const title = getTitle(this)
    23. if (title) {
    24. document.title = title
    25. }
    26. }
    27. }
    28. // 可以通过 `webpack.DefinePlugin` 注入 `VUE_ENV`
    29. export default process.env.VUE_ENV === 'server'
    30. ? serverTitleMixin
    31. : clientTitleMixin

    现在,路由组件可以利用以上 mixin,来控制文档标题 (document title):

    1. // Item.vue
    2. export default {
    3. mixins: [titleMixin],
    4. title () {
    5. return this.item.title
    6. },
    7. asyncData ({ store, route }) {
    8. return store.dispatch('fetchItem', route.params.id)
    9. },
    10. computed: {
    11. item () {
    12. return this.$store.state.items[this.$route.params.id]
    13. }
    14. }
    15. }

    然后模板中的内容将会传递给 bundle renderer:

    1. <html>
    2. <head>
    3. <title>{{ title }}</title>
    4. </head>
    5. <body>
    6. ...
    7. </body>
    8. </html>

    注意:

    • 使用双花括号(double-mustache)进行 HTML 转义插值(HTML-escaped interpolation),以避免 XSS 攻击。

    • 你应该在创建 context 对象时提供一个默认标题,以防在渲染过程中组件没有设置标题。


    使用相同的策略,你可以轻松地将此 mixin 扩展为通用的头部管理工具 (generic head management utility)。