2
0
mirror of https://github.com/tenrok/vue-meta.git synced 2026-05-30 12:34:04 +03:00

support for client tag updates

This commit is contained in:
Declan de Wet
2016-11-03 08:08:43 +02:00
parent f7e793d025
commit bb98313007
5 changed files with 86 additions and 6 deletions
+21
View File
@@ -1,10 +1,23 @@
import updateTitle from './updaters/updateTitle'
import updateTagAttributes from './updaters/updateTagAttributes'
import updateTags from './updaters/updateTags'
import { SERVER_RENDERED_ATTRIBUTE } from '../shared/constants'
// tags to watch
const tags = [
'meta',
'link',
'base',
'style',
'script',
'noscript'
]
// hoisted vars but only in the browser
if (typeof window !== 'undefined' && window !== null) {
var htmlTag = document.getElementsByTagName('html')[0]
var bodyTag = document.getElementsByTagName('body')[0]
var headTag = document.getElementsByTagName('head')[0]
}
/**
@@ -23,6 +36,14 @@ export default function updateClientMetaInfo (newInfo, $root) {
// update <body> attrs
updateTagAttributes(newInfo.bodyAttrs, bodyTag)
// update tags
for (let i = 0, len = tags.length; i < len; i++) {
const tag = tags[i]
if (newInfo[tag]) {
updateTags(tag, newInfo[tag], headTag)
}
}
} else {
htmlTag.removeAttribute(SERVER_RENDERED_ATTRIBUTE)
}
+59
View File
@@ -0,0 +1,59 @@
import { VUE_META_ATTRIBUTE } from '../../shared/constants'
// borrow the slice method
const toArray = Function.prototype.call.bind(Array.prototype.slice)
/**
* Updates meta tags inside <head> on the client. Borrowed from `react-helmet`:
* https://github.com/nfl/react-helmet/blob/004d448f8de5f823d10f838b02317521180f34da/src/Helmet.js#L195-L245
*
* @param {('meta'|'base'|'link'|'style'|'script'|'noscript')} type - the name of the tag
* @param {(Array<Object>|Object)} tags - an array of tag objects or a single object in case of base
* @return {Object} - a representation of what tags changed
*/
export default function updateTags (type, tags, headTag) {
const nodes = headTag.querySelectorAll(`${type}[${VUE_META_ATTRIBUTE}]`)
const oldTags = toArray(nodes)
const newTags = []
let indexToDelete
if (tags && tags.length) {
tags.forEach((tag) => {
const newElement = document.createElement(type)
for (const attribute in tag) {
if (tag.hasOwnProperty(attribute)) {
if (attribute === 'innerHTML') {
newElement.innerHTML = tag.innerHTML
} else if (attribute === 'cssText') {
if (newElement.styleSheet) {
newElement.styleSheet.cssText = tag.cssText
} else {
newElement.appendChild(document.createTextNode(tag.cssText))
}
} else {
const value = (typeof tag[attribute] === 'undefined') ? '' : tag[attribute]
newElement.setAttribute(attribute, value)
}
}
}
newElement.setAttribute(VUE_META_ATTRIBUTE, 'true')
// Remove a duplicate tag from domTagstoRemove, so it isn't cleared.
if (oldTags.some((existingTag, index) => {
indexToDelete = index
return newElement.isEqualNode(existingTag)
})) {
oldTags.splice(indexToDelete, 1)
} else {
newTags.push(newElement)
}
})
}
oldTags.forEach((tag) => tag.parentNode.removeChild(tag))
newTags.forEach((tag) => headTag.appendChild(tag))
return { oldTags, newTags }
}
-5
View File
@@ -10,11 +10,6 @@ import { VUE_META_ATTRIBUTE } from '../../shared/constants'
export default function tagGenerator (type, tags) {
return {
text () {
// there can only be one `base` tag on a page, so we give it special treatment
if (type === 'base') {
tags = Object.keys(tags).length ? [tags] : []
}
// build a string containing all tags of this type
return tags.reduce((tagsStr, tag) => {
// build a string containing all attributes of this tag
+1 -1
View File
@@ -21,7 +21,7 @@ export default function inject () {
noscript: [],
style: [],
link: [],
base: {}
base: []
}, getMetaInfo(this.$root))
// generate server injectors
+5
View File
@@ -31,5 +31,10 @@ export default function getMetaInfo (component) {
info.title = info.titleTemplate.replace(/%s/g, info.titleChunk)
}
// convert base tag to an array
if (info.base) {
info.base = Object.keys(info.base).length ? [info.base] : []
}
return info
}