详解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 相关文章推荐
javascript限制用户只能输汉字中文的方法
Nov 20 Javascript
angularJS中$apply()方法详解
Jan 07 Javascript
JavaScript动态加载样式表的方法
Mar 21 Javascript
轻松学习jQuery插件EasyUI EasyUI创建CRUD应用
Nov 30 Javascript
javascript表单处理具体实现代码(表单、链接、按钮)
May 07 Javascript
AngularJS框架中的双向数据绑定机制详解【减少需要重复的开发代码量】
Jan 19 Javascript
JavaScript获取当前时间向前推三个月的方法示例
Feb 04 Javascript
xmlplus组件设计系列之按钮(2)
Apr 26 Javascript
原生js实现拖拽功能基本思路详解
Apr 18 Javascript
vue实现图片预览组件封装与使用
Jul 13 Javascript
jQuery实现高度灵活的表单验证功能示例【无UI】
Apr 30 jQuery
Vue 事件的$event参数=事件的值案例
Jan 29 Vue.js
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
PHP JS Ip地址及域名格式检测代码
2013/09/27 PHP
PHP 面向对象程序设计(oop)学习笔记 (二) - 静态变量的属性和方法及延迟绑定
2014/06/12 PHP
php防止恶意刷新与刷票的方法
2014/11/21 PHP
Yii框架小部件(Widgets)用法实例详解
2020/05/15 PHP
php框架CI(codeigniter)自动加载与自主创建对象操作实例分析
2020/06/06 PHP
PHP大文件及断点续传下载实现代码
2020/08/18 PHP
用JQuery 实现AJAX加载XML并解析的脚本
2009/07/25 Javascript
JS对象与JSON格式数据相互转换
2012/02/20 Javascript
{}与function(){}选用空对象{}来存放keyValue
2012/05/23 Javascript
js自动生成的元素与页面原有元素发生堆叠的解决方法
2013/10/24 Javascript
javascript实现状态栏中文字动态显示的方法
2015/10/20 Javascript
javascript删除html标签函数cIsHTML
2017/01/09 Javascript
原生js仿淘宝网商品放大镜效果
2017/02/28 Javascript
详解js静态资源文件请求的处理
2017/08/01 Javascript
React Native 搭建开发环境的方法步骤
2017/10/30 Javascript
vue.js项目nginx部署教程
2018/04/05 Javascript
浅析JS中回调函数及用法
2018/07/25 Javascript
React通过redux-persist持久化数据存储的方法示例
2019/02/14 Javascript
详解一些适用于Node.js的命名约定
2019/12/08 Javascript
封装Vue Element的table表格组件的示例详解
2020/08/19 Javascript
[43:35]EG vs Winstrike 2018国际邀请赛小组赛BO2 第一场 8.18
2018/08/19 DOTA
Python二分查找详解
2015/09/13 Python
Python函数中的函数(闭包)用法实例
2016/03/15 Python
Python标准库之collections包的使用教程
2017/04/27 Python
利用nohup来开启python文件的方法
2019/01/14 Python
python实现把二维列表变为一维列表的方法分析
2019/10/08 Python
python matplotlib画盒图、子图解决坐标轴标签重叠的问题
2020/01/19 Python
Keras实现将两个模型连接到一起
2020/05/23 Python
Python爬虫requests库多种用法实例
2020/05/28 Python
Python虚拟环境的创建和包下载过程分析
2020/06/19 Python
python中if嵌套命令实例讲解
2021/02/25 Python
关于css中margin的值和垂直外边距重叠问题
2020/10/27 HTML / CSS
2014入党积极分子批评与自我批评思想报告
2014/10/06 职场文书
酒店财务总监岗位职责
2015/04/03 职场文书
公司出差管理制度范本
2015/08/05 职场文书
python实现进度条的多种实现
2021/04/29 Python