mirror of
https://github.com/tenrok/vue-meta.git
synced 2026-06-24 22:50:34 +03:00
implement fix for #9 edge-case
This commit is contained in:
@@ -5,7 +5,7 @@ import Router from 'vue-router'
|
|||||||
Vue.use(Router)
|
Vue.use(Router)
|
||||||
Vue.use(VueMeta)
|
Vue.use(VueMeta)
|
||||||
|
|
||||||
const ChildComponent = () => ({
|
const ChildComponent = {
|
||||||
name: `child-component`,
|
name: `child-component`,
|
||||||
props: ['page'],
|
props: ['page'],
|
||||||
template: `<h3>You're looking at the <strong>{{ page }}</strong> page</h3>`,
|
template: `<h3>You're looking at the <strong>{{ page }}</strong> page</h3>`,
|
||||||
@@ -14,13 +14,16 @@ const ChildComponent = () => ({
|
|||||||
return this.page
|
return this.page
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
|
// this wrapper function is not a requirement for vue-router,
|
||||||
|
// just a demonstration that render-function style components also work.
|
||||||
|
// See https://github.com/declandewet/vue-meta/issues/9 for more info.
|
||||||
function view (page) {
|
function view (page) {
|
||||||
return {
|
return {
|
||||||
name: `section-${page}`,
|
name: `section-${page}`,
|
||||||
render (h) {
|
render (h) {
|
||||||
return h(ChildComponent(), {
|
return h(ChildComponent, {
|
||||||
props: { page }
|
props: { page }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-13
@@ -9,20 +9,8 @@ import generateServerInjector from './generateServerInjector'
|
|||||||
* @return {Object} - server meta info with `toString` methods
|
* @return {Object} - server meta info with `toString` methods
|
||||||
*/
|
*/
|
||||||
export default function inject () {
|
export default function inject () {
|
||||||
const Vue = this.constructor
|
|
||||||
|
|
||||||
// get meta info with sensible defaults
|
// get meta info with sensible defaults
|
||||||
const info = Vue.util.extend({
|
const info = getMetaInfo(this.$root)
|
||||||
title: '',
|
|
||||||
htmlAttrs: {},
|
|
||||||
bodyAttrs: {},
|
|
||||||
meta: [],
|
|
||||||
script: [],
|
|
||||||
noscript: [],
|
|
||||||
style: [],
|
|
||||||
link: [],
|
|
||||||
base: []
|
|
||||||
}, getMetaInfo(this.$root))
|
|
||||||
|
|
||||||
// generate server injectors
|
// generate server injectors
|
||||||
for (let key in info) {
|
for (let key in info) {
|
||||||
|
|||||||
@@ -23,12 +23,6 @@ export default function getComponentOption (opts, result = {}) {
|
|||||||
const data = $options[option]
|
const data = $options[option]
|
||||||
|
|
||||||
if (typeof data === 'object') {
|
if (typeof data === 'object') {
|
||||||
// bind context of option methods (if any) to this component
|
|
||||||
Object.keys(data).forEach((key) => {
|
|
||||||
const value = data[key]
|
|
||||||
data[key] = typeof value === 'function' ? value.bind(component) : value
|
|
||||||
})
|
|
||||||
|
|
||||||
// merge with existing options
|
// merge with existing options
|
||||||
result = deepmerge(result, data, {
|
result = deepmerge(result, data, {
|
||||||
clone: true,
|
clone: true,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import deepmerge from 'deepmerge'
|
import deepmerge from 'deepmerge'
|
||||||
import getComponentOption from './getComponentOption'
|
import getComponentOption from './getComponentOption'
|
||||||
|
import mergeComponentData from './mergeComponentData'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the correct meta info for the given component
|
* Returns the correct meta info for the given component
|
||||||
@@ -55,12 +56,6 @@ export default function getMetaInfo (component) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// if any info options are a function, coerce them to the result of a call
|
|
||||||
Object.keys(info).forEach((key) => {
|
|
||||||
const val = info[key]
|
|
||||||
info[key] = typeof val === 'function' && key !== 'changed' ? val() : val
|
|
||||||
})
|
|
||||||
|
|
||||||
// backup the title chunk in case user wants access to it
|
// backup the title chunk in case user wants access to it
|
||||||
if (info.title) {
|
if (info.title) {
|
||||||
info.titleChunk = info.title
|
info.titleChunk = info.title
|
||||||
@@ -77,5 +72,16 @@ export default function getMetaInfo (component) {
|
|||||||
info.base = Object.keys(info.base).length ? [info.base] : []
|
info.base = Object.keys(info.base).length ? [info.base] : []
|
||||||
}
|
}
|
||||||
|
|
||||||
return deepmerge(defaultInfo, info)
|
const metaInfo = deepmerge(defaultInfo, info)
|
||||||
|
const componentData = mergeComponentData(component)
|
||||||
|
|
||||||
|
// inject component context into functions & call to normalize data
|
||||||
|
Object.keys(metaInfo).forEach((key) => {
|
||||||
|
const val = metaInfo[key]
|
||||||
|
if (typeof val === 'function') {
|
||||||
|
metaInfo[key] = val.call(componentData)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return metaInfo
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* Recursively shallow-merges component object with it's children component objects.
|
||||||
|
* This function is responsible for obtaining the `this` context of metaInfo props when
|
||||||
|
* declared in function form.
|
||||||
|
*
|
||||||
|
* @param {Object} component - the component object
|
||||||
|
* @return {Object} - the merged data
|
||||||
|
*/
|
||||||
|
export default function mergeComponentData (component) {
|
||||||
|
if (component.$children.length) {
|
||||||
|
return component.$children.reduce((data, child) => {
|
||||||
|
return Object.assign({}, data, mergeComponentData(child))
|
||||||
|
}, component)
|
||||||
|
}
|
||||||
|
return component
|
||||||
|
}
|
||||||
@@ -26,9 +26,10 @@ export default function VueMeta (Vue) {
|
|||||||
|
|
||||||
requestId = window.requestAnimationFrame(() => {
|
requestId = window.requestAnimationFrame(() => {
|
||||||
requestId = null
|
requestId = null
|
||||||
|
const info = getMetaInfo(this.$root)
|
||||||
|
|
||||||
// update the meta info
|
// update the meta info
|
||||||
updateClientMetaInfo(getMetaInfo(this.$root))
|
updateClientMetaInfo(info)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -19,21 +19,6 @@ describe('getComponentOption', () => {
|
|||||||
expect(fetchedOption).to.eql('foo')
|
expect(fetchedOption).to.eql('foo')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('binds option method context to the component instance', () => {
|
|
||||||
component = new Vue({
|
|
||||||
data: {
|
|
||||||
age: 44
|
|
||||||
},
|
|
||||||
foo: {
|
|
||||||
bar () {
|
|
||||||
return this.age
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
const fetchedOption = getComponentOption({ component, option: 'foo' })
|
|
||||||
expect(fetchedOption.bar()).to.equal(44)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('fetches deeply nested component options and merges them', () => {
|
it('fetches deeply nested component options and merges them', () => {
|
||||||
Vue.component('merge-child', { template: '<div></div>', foo: { bar: 'baz' } })
|
Vue.component('merge-child', { template: '<div></div>', foo: { bar: 'baz' } })
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user