详解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 相关文章推荐
DOM2非标准但却支持很好的几个属性小结
Jan 21 Javascript
js页面跳转的常用方法整理
Oct 18 Javascript
jQuery取得select选择的文本与值的示例
Dec 09 Javascript
JS模仿编辑器实时改变文本框宽度和高度大小的方法
Aug 17 Javascript
Bootstrap每天必学之弹出框(Popover)插件
Apr 25 Javascript
JS之获取样式的简单实现方法(推荐)
Sep 13 Javascript
jQuery自定义组件(导入组件)
Nov 08 Javascript
详解如何用typescript开发koa2的二三事
Nov 13 Javascript
从零到一详聊创建Vue工程及遇到的常见问题
Apr 25 Javascript
微信小程序下拉菜单效果的实例代码
May 14 Javascript
微信小程序wx.request的简单封装
Nov 13 Javascript
解决Vue 移动端点击出现300毫秒延迟的问题
Jul 21 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
php截取utf-8中文字符串乱码的解决方法
2010/03/29 PHP
PHP中的float类型使用说明
2010/07/27 PHP
Yii实现简单分页的方法
2016/04/29 PHP
php页面跳转session cookie丢失导致不能登录等问题的解决方法
2016/12/12 PHP
php实现base64图片上传方式实例代码
2017/02/22 PHP
thinkPHP5.0框架配置格式、加载解析与读取方法
2017/03/17 PHP
jQuery学习4 浏览器的事件模型
2010/02/07 Javascript
非阻塞动态加载javascript广告实现代码
2010/11/17 Javascript
基于jQuery的简单的列表导航菜单
2011/03/02 Javascript
『JavaScript』限制Input只能输入数字实现思路及代码
2013/04/22 Javascript
event对象获取方法总结在google浏览器下测试
2013/11/03 Javascript
js采用map取到id集合组并且实现点击一行选中一行
2013/12/16 Javascript
jQuery操作表格(table)的常用方法、技巧汇总
2014/04/12 Javascript
jQuery实现异步获取json数据的2种方式
2014/08/29 Javascript
原生JS实现响应式瀑布流布局
2015/04/02 Javascript
jQuery插件fullPage.js实现全屏滚动效果
2016/12/02 Javascript
利用jQuery插件imgAreaSelect实现图片上传裁剪(放大缩小)
2016/12/02 Javascript
Vue Transition实现类原生组件跳转过渡动画的示例
2017/08/19 Javascript
vue.js实现格式化时间并每秒更新显示功能示例
2018/07/07 Javascript
jQuery AJAX应用实例总结
2020/05/19 jQuery
原生js生成图片验证码
2020/10/11 Javascript
[15:35]教你分分钟做大人:天怒法师
2014/10/30 DOTA
Python中的os.path路径模块中的操作方法总结
2016/07/07 Python
python之pymysql模块简单应用示例代码
2019/12/16 Python
django中嵌套的try-except实例
2020/05/21 Python
PyCharm设置注释字体颜色以及是否倾斜的操作
2020/09/16 Python
什么是View State?
2013/01/27 面试题
保证书范文大全
2014/04/28 职场文书
山东省召开党的群众路线教育实践活动总结大会新闻稿
2014/10/21 职场文书
武夷山导游词
2015/02/03 职场文书
检讨书范文大全
2015/05/07 职场文书
朋友离别感言
2015/08/04 职场文书
Oracle 数据仓库ETL技术之多表插入语句的示例详解
2021/04/12 Oracle
python 如何做一个识别率百分百的OCR
2021/05/29 Python
详解如何用Python实现感知器算法
2021/06/18 Python
win11自动弹出虚拟键盘怎么关闭? Win11关闭虚拟键盘的技巧
2023/01/09 数码科技