详解vue-meta如何让你更优雅的管理头部标签


Posted in Javascript onJanuary 18, 2018

在 Vue SPA 应用中,如果想要修改HTML的头部标签,或许,你会在代码里,直接这么做:

// 改下title
document.title = 'what?'
// 引入一段script
let s = document.createElement('script')
s.setAttribute('src', './vconsole.js')
document.head.appendChild(s)
// 修改meta信息,或者给html标签添加属性...
// 此处省略一大坨代码...

今天给大家介绍一种更优雅的方式,去管理头部标签 vue-meta

vue-meta介绍

Manage page meta info in Vue 2.0 components. SSR + Streaming supported. Inspired by react-helmet.

借用vue-meta github 上的介绍,基于Vue 2.0 的 vue-meta 插件,主要用于管理HMTL头部标签,同时也支持SSR。

vue-meta有以下特点:

  1. 在组件内设置 metaInfo,便可轻松实现头部标签的管理
  2. metaInfo 的数据都是响应的,如果数据变化,头部信息会自动更新
  3. 支持 SSR

如何使用

在介绍如何使用之前,先和大家普及一个最近很火的名词 服务端渲染(SSR, Server Side Render),简单来讲,就是在访问某个页面时,服务端会把渲染好的页面,直接返回给浏览器。

我们知道 vue-meta 是支持SSR的,下面的介绍分成两部分:

Client 客户端

在入口文件中,install vue-meta plugin

import Vue from 'vue'
import VueRouter from 'vue-router'
import VueMeta from 'vue-meta'

Vue.use(VueRouter)
Vue.use(VueMeta)

/* eslint-disable no-new */
new Vue({
 el: '#app',
 router,
 template: '<App/>',
 components: { App }
})

然后就可以在组件中使用了

export default {
 data () {
  return {
   myTitle: '标题'
  }
 },
 metaInfo: {
  title: this.myTitle,
  titleTemplate: '%s - by vue-meta',
  htmlAttrs: {
   lang: 'zh'
  },
  script: [{innerHTML: 'console.log("hello hello!")', type: 'text/javascript'}],
  __dangerouslyDisableSanitizers: ['script']
 },
 ...
}

可以看一下页面显示

详解vue-meta如何让你更优雅的管理头部标签

熟悉 Nuxt.js 的同学,会发现配置 meta info 的 keyName 不一致。可以通过下面的配置方法来修改:

// vue-meta configuration 
Vue.use(Meta, {
 keyName: 'head', // the component option name that vue-meta looks for meta info on.
 attribute: 'data-n-head', // the attribute name vue-meta adds to the tags it observes
 ssrAttribute: 'data-n-head-ssr', // the attribute name that lets vue-meta know that meta info has already been server-rendered
 tagIDKeyName: 'hid' // the property name that vue-meta uses to determine whether to overwrite or append a tag
})

更加全面详细的api,可以参考vue-meta github

Server 服务端

Step 1. 将 $meta 对象注入到上下文中

server-entry.js:

import app from './app'

const router = app.$router
const meta = app.$meta() // here

export default (context) => {
 router.push(context.url)
 context.meta = meta // and here
 return app
}

$meta 主要提供了,inject 和 refresh 方法。inject 方法,用在服务端,返回设置的metaInfo ;refresh 方法,用在客户端,作用是更新meta信息。

Step 2. 使用 inject() 方法 输出页面

server.js:

app.get('*', (req, res) => {
 const context = { url: req.url }
 renderer.renderToString(context, (error, html) => {
  if (error) return res.send(error.stack)
  const bodyOpt = { body: true }
  const {
   title, htmlAttrs, bodyAttrs, link, style, script, noscript, meta
  } = context.meta.inject()
  return res.send(`
   <!doctype html>
   <html data-vue-meta-server-rendered ${htmlAttrs.text()}>
    <head>
     ${meta.text()}
     ${title.text()}
     ${link.text()}
     ${style.text()}
     ${script.text()}
     ${noscript.text()}
    </head>
    <body ${bodyAttrs.text()}>
     ${html}
     <script src="/assets/vendor.bundle.js"></script>
     <script src="/assets/client.bundle.js"></script>
     ${script.text(bodyOpt)}
    </body>
   </html>
  `)
 })
})

源码分析

前面说了 vue-meta 的使用方法,或许大家会想这些功能是怎么实现的,那下面就和大家分享一下源码。

怎么区分 client 和 server渲染?

vue-meta 会在 beforeCreate() 钩子函数中,将组件中设置的 metaInfo ,放在 this.$metaInfo 中。我们可以在其他生命周期中,访问 this.$metaInfo 下的属性。

if (typeof this.$options[options.keyName] === 'function') {
 if (typeof this.$options.computed === 'undefined') {
  this.$options.computed = {}
 }
 this.$options.computed.$metaInfo = this.$options[options.keyName]
}

vue-meta 会在created等生命周期的钩子函数中,监听 $metaInfo 的变化,如果发生改变,就调用 $meta 下的 refresh 方法。这也是 metaInfo 做到响应的原因。

created () {
 if (!this.$isServer && this.$metaInfo) {
  this.$watch('$metaInfo', () => {
   batchID = batchUpdate(batchID, () => this.$meta().refresh())
  })
 }
},

Server端,主要是暴露 $meta 下的 inject 方法,调用 inject 方法,会返回对应的信息。

client 和 server端 是如何修改标签的?

client端 修改标签,就是本文开头提到的 通过原生js,直接修改

return function updateTitle (title = document.title) {
 document.title = title
}

server端,就是通过 text方法,返回string格式的标签

return function titleGenerator (type, data) {
 return {
  text () {
   return `<${type} ${attribute}="true">${data}</${type}>`
  }
 }
}

__dangerouslyDisableSanitizers 做了什么?

vue-meta 默认会对特殊字符串进行转义,如果设置了 __dangerouslyDisableSanitizers,就不会对再做转义处理。

const escapeHTML = (str) => typeof window === 'undefined'
 // server-side escape sequence
 ? String(str)
  .replace(/&/g, '&')
  .replace(/</g, '<')
  .replace(/>/g, '>')
  .replace(/"/g, '"')
  .replace(/'/g, ''')
 // client-side escape sequence
 : String(str)
  .replace(/&/g, '\u0026')
  .replace(/</g, '\u003c')
  .replace(/>/g, '\u003e')
  .replace(/"/g, '\u0022')
  .replace(/'/g, '\u0027')

最后

最开始接触 vue-meta 是在 Nuxt.js 中。如果想了解 Nuxt.js,欢迎大家阅读Nuxt.js实战 和 Nuxt.js踩坑分享。文中有任何表述不清或不当的地方,欢迎大家批评指正。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
jquery 缓存问题的几个解决方法
Nov 11 Javascript
使用jquery实现的一个图片延迟加载插件(含图片延迟加载原理)
Jun 05 Javascript
jQuery+CSS3实现树叶飘落特效
Feb 01 Javascript
jquery的checkbox,radio,select等方法小结
Aug 30 Javascript
jquery css实现邮箱自动补全
Nov 14 Javascript
vuejs指令详解
Feb 07 Javascript
Bootstrap弹出框(Popover)被挤压的问题小结
Jul 11 Javascript
Vue数据双向绑定原理及简单实现方法
May 18 Javascript
微信小程序之下拉列表实现方法解析(附完整源码)
Aug 23 Javascript
Vue通过WebSocket建立长连接的实现代码
Nov 05 Javascript
vue实现pdf文档在线预览功能
Nov 26 Javascript
微信小程序 button样式设置为图片的方法
Jun 19 Javascript
Nuxt.js踩坑总结分享
Jan 18 #Javascript
Nuxt.js实战详解
Jan 18 #Javascript
React Native 真机断点调试+跨域资源加载出错问题的解决方法
Jan 18 #Javascript
ajax请求data遇到的问题分析
Jan 18 #Javascript
angular.js和vue.js中实现函数去抖示例(debounce)
Jan 18 #Javascript
vue-scroller记录滚动位置的示例代码
Jan 17 #Javascript
基于vue监听滚动事件实现锚点链接平滑滚动的方法
Jan 17 #Javascript
You might like
默默简单的写了一个模板引擎
2007/01/02 PHP
php设计模式 Bridge (桥接模式)
2011/06/26 PHP
PHP Session机制简介及用法
2014/08/19 PHP
用PHP生成excel文件到指定目录
2015/06/22 PHP
yii2实现根据时间搜索的方法
2016/05/25 PHP
PHP实现深度优先搜索算法(DFS,Depth First Search)详解
2017/09/16 PHP
用js判断页面刷新或关闭的方法(onbeforeunload与onunload事件)
2012/06/22 Javascript
基于jQuery的JavaScript模版引擎JsRender使用指南
2014/12/29 Javascript
28个常用JavaScript方法集锦
2015/01/14 Javascript
用JS实现图片轮播效果代码(一)
2016/06/26 Javascript
jQuery实现可展开折叠的导航效果示例
2016/09/12 Javascript
Angular.js中angular-ui-router的简单实践
2017/07/18 Javascript
javascript流程控制语句集合
2017/09/18 Javascript
JS点击动态添加标签、删除指定标签的代码
2018/04/18 Javascript
vue使用自定义icon图标的方法
2018/05/14 Javascript
Vue+axios实现统一接口管理的方法
2018/07/23 Javascript
详解Vue SSR( Vue2 + Koa2 + Webpack4)配置指南
2018/11/13 Javascript
详解@Vue/Cli 3 Invalid Host header 错误解决办法
2019/01/02 Javascript
JS Thunk 函数的含义和用法实例总结
2020/04/08 Javascript
JavaScript async/await原理及实例解析
2020/12/02 Javascript
Python BeautifulSoup中文乱码问题的2种解决方法
2014/04/22 Python
浅析Python中的getattr(),setattr(),delattr(),hasattr()
2016/06/14 Python
python数据清洗系列之字符串处理详解
2017/02/12 Python
解决.ui文件生成的.py文件运行不出现界面的方法
2019/06/19 Python
Python中使用__new__实现单例模式并解析
2019/06/25 Python
python print出共轭复数的方法详解
2019/06/25 Python
Python GUI学习之登录系统界面篇
2019/08/21 Python
在PyTorch中使用标签平滑正则化的问题
2020/04/03 Python
Django 解决由save方法引发的错误
2020/05/21 Python
部门年终奖分配方案
2014/05/07 职场文书
中专生自荐信
2014/06/25 职场文书
教师拔河比赛广播稿
2014/10/14 职场文书
市场总监岗位职责
2015/02/11 职场文书
HAM-2000摩机图
2021/04/22 无线电
关于python中模块和重载的问题
2021/11/02 Python
Go 内联优化让程序员爱不释手
2022/06/21 Golang