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:
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -21,7 +21,7 @@ export default function inject () {
|
||||
noscript: [],
|
||||
style: [],
|
||||
link: [],
|
||||
base: {}
|
||||
base: []
|
||||
}, getMetaInfo(this.$root))
|
||||
|
||||
// generate server injectors
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user