UNPKG

@morr/vue3-head

Version:

Manipulating the meta information of the head tag, a simple and easy way

269 lines (245 loc) 6.24 kB
/* eslint-disable */ ;(() => { 'use strict' const opt = { complement: window.document.title, separator: '|' } const diffTitle = {} let els = [] let diffEls = [] let installed = false const util = { /** * Shorthand * @type {Object} */ shorthand: { ch: 'charset', tg: 'target', n: 'name', he: 'http-equiv', ip: 'itemprop', c: 'content', p: 'property', sc: 'scheme', r: 'rel', h: 'href', sz: 'sizes', t: 'type', s: 'src', a: 'async', d: 'defer', i: 'inner' }, /** * This function return the element by tagName * @type {Function} * @return {Object} */ getPlace (place) { return window.document.getElementsByTagName(place)[0] }, /** * Undo the window.document title for previous state * @type {Function} * @param {Object} state */ undoTitle (state) { if (!state.before) return window.document.title = state.before }, /** * Undo elements to its previous state * @type {Function} */ undo () { if (!els.length) return els.forEach(el => el.parentElement.removeChild(el)) els = [] }, /** * Set attributes in element * @type {Function} * @param {Object} obj * @param {HTMLElement} el * @return {HTMLElement} with defined attributes */ prepareElement (obj, el) { Object.keys(obj).forEach(prop => { let sh = (this.shorthand[prop] || prop) if (sh.match(/(body|undo|replace)/g)) return if (sh === 'inner') { el.textContent = obj[prop] return } el.setAttribute(sh, obj[prop]) }) return el }, /** * Change window.document title * @type {Function} * @param {Object} val */ title (val) { if (!val) return diffTitle.before = opt.complement const complement = obj.complement === '' ? obj.complement : (obj.complement || opt.complement) const separator = obj.separator === '' ? obj.separator : (obj.separator || opt.separator) const title = `${val.inner} ${separator} ${complement}` window.document.title = title.trim() }, update () { if (!els.length) return els.forEach((el, key) => { if (diffEls[key] && !diffEls[key].isEqualNode(el)) { el.parentElement.replaceChild(diffEls[key], els[key]) els.splice(key, 1, diffEls[key]) return } }) diffEls = [] }, add (obj, el, parent) { parent.appendChild(el) // Fixed elements that do not suffer removal if (obj.undo !== undefined && !obj.undo) return // Elements which are removed els.push(el) }, /** * Handle of create elements * @type {Function} * @param {Array} arr * @param {String} tag - style, link, meta, script, base * @param {String} place - Default 'head' * @param {Boolean} update */ handle (arr, tag, place, update) { if (!arr) return arr.forEach(obj => { let parent = (obj.body) ? this.getPlace('body') : this.getPlace(place) let el = window.document.getElementById(obj.id) if (!el) { el = window.document.createElement(tag) update = false } // Elements that will substitute data if (el.hasAttribute('id')) { this.prepareElement(obj, el) return } // Other elements this.prepareElement(obj, el) // Updated elements if (update) { diffEls.push(el) return } // Add elements in Node this.add(obj, el, parent) }) } } /** * Plugin | vue-head * @param {Function} Vue * @param {Object} options */ const VueHead = (Vue, options) => { if (installed) return installed = true if (options) { Vue.util.extend(opt, options) } function init (update) { let head = (typeof this.$options.head === 'function') ? this.$options.head.bind(this)() : this.$options.head if (!head) return Object.keys(head).forEach(key => { let prop = head[key] if (!prop) return let obj = (typeof prop === 'function') ? head[key].bind(this)() : head[key] if (key === 'title') { util[key](obj) return } util.handle(obj, key, 'head', update) }) // this.$emit('okHead') } function destroy () { if (!this.$options.head) return util.undoTitle(diffTitle) util.undo() } // v3 if (!Vue.version || Vue.version.match(/[3].(.)+/g)) { Vue.mixin({ created: function () { var self = this self.$on && self.$on('updateHead', function () { init.call(this, true) util.update() }) }, mounted: function () { init.call(this) }, beforeUnmount: function () { destroy.call(this) } }) } // v1 else if (Vue.version.match(/[1].(.)+/g)) { Vue.mixin({ ready () { init.call(this) }, destroyed () { destroy.call(this) }, events: { updateHead () { init.call(this, true) util.update() } } }) } // v2 else if (Vue.version.match(/[2].(.)+/g)) { Vue.mixin({ created () { this.$on('updateHead', () => { init.call(this, true) util.update() }) }, mounted () { init.call(this) }, beforeDestroy () { destroy.call(this) } }) } } VueHead.version = '3.0.0' // auto install if (typeof Vue !== 'undefined') { Vue.use(VueHead) } if(typeof exports === 'object' && typeof module === 'object') { module.exports = VueHead } else if(typeof define === 'function' && define.amd) { define(function () { return VueHead }) } else if (typeof window !== 'undefined') { window.VueHead = VueHead } })()