详解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 相关文章推荐
js 设置选中行的样式的实现代码
May 24 Javascript
关于JavaScript中原型继承中的一点思考
Jul 25 Javascript
jQuery基本选择器选择元素使用介绍
Apr 18 Javascript
showModelDialog弹出文件下载窗口的使用示例
Nov 19 Javascript
jQuery实现鼠标划过修改样式的方法
Apr 14 Javascript
AngularJS ng-bind-html 指令详解及实例代码
Jul 30 Javascript
正则 js分转元带千分符号详解
Mar 08 Javascript
vue货币过滤器的实现方法
Apr 01 Javascript
实时监控input框,实现输入框与下拉框联动的实例
Jan 23 Javascript
基于Vue实现拖拽效果
Apr 27 Javascript
angular使用md5,CryptoJS des加密的方法
Jun 03 Javascript
js get和post请求实现代码解析
Feb 06 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
Codeigniter+PHPExcel实现导出数据到Excel文件
2014/06/12 PHP
ThinkPHP模板循环输出Volist标签用法实例详解
2016/03/23 PHP
js getElementsByTagName的简写方式
2010/06/27 Javascript
JS/FLASH实现复制代码到剪贴板(兼容所有浏览器)
2013/05/27 Javascript
jquery和css3实现的炫酷时尚的菜单导航
2014/09/01 Javascript
JavaScript实现将UPC转换成ISBN的方法
2015/05/26 Javascript
JavaScript中的数组遍历forEach()与map()方法以及兼容写法介绍
2016/05/19 Javascript
简洁实用的BootStrap jQuery手风琴插件
2016/08/31 Javascript
Bootstrap中的fileinput 多图片上传及编辑功能
2016/09/05 Javascript
javascript鼠标跟随运动3种效果(眼球效果,苹果菜单,方向跟随)
2016/10/27 Javascript
解决vue单页使用keep-alive页面返回不刷新的问题
2018/03/13 Javascript
nodejs语言实现验证码生成功能的示例代码
2019/10/13 NodeJs
微信小程序定义和调用全局变量globalData的实现
2019/11/01 Javascript
Vue自定义指令结合阿里云OSS优化图片的实现方法
2019/11/12 Javascript
在vue中利用v-html按分号将文本换行的例子
2019/11/14 Javascript
[01:04:29]DOTA2-DPC中国联赛 正赛 Phoenix vs XG BO3 第二场 1月31日
2021/03/11 DOTA
详解Python 模拟实现生产者消费者模式的实例
2017/08/10 Python
Request的中断和ErrorHandler实例解析
2018/02/12 Python
python3解析库pyquery的深入讲解
2018/06/26 Python
python matlibplot绘制3D图形
2018/07/02 Python
python爬虫开发之使用python爬虫库requests,urllib与今日头条搜索功能爬取搜索内容实例
2020/03/10 Python
解决导入django_filters不成功问题No module named 'django_filter'
2020/07/15 Python
pandas按照列的值排序(某一列或者多列)
2020/12/13 Python
浅谈matplotlib默认字体设置探索
2021/02/03 Python
python中threading和queue库实现多线程编程
2021/02/06 Python
iRobot官网:改变生活的家用机器人品牌
2016/09/20 全球购物
VIVOBAREFOOT赤脚鞋:让您的脚做自然的事情
2017/06/01 全球购物
使用索引(Index)有哪些需要考虑的因素
2016/10/19 面试题
《世界多美呀》教学反思
2014/03/02 职场文书
私人会所最新创业计划书范文
2014/03/24 职场文书
机械加工与数控专业自荐书
2014/06/04 职场文书
医院领导班子整改方案
2014/10/01 职场文书
国庆节慰问信
2015/02/15 职场文书
中国梦党课学习心得体会
2016/01/05 职场文书
Nginx反爬虫策略,防止UA抓取网站
2021/03/31 Servers
在 HTML 页面中使用 React的场景分析
2022/01/18 Javascript