2
0
mirror of https://github.com/tenrok/vue-meta.git synced 2026-05-17 20:39:37 +03:00

feat: merge mixins options

Closes #261
This commit is contained in:
adrienbaron
2018-09-06 11:47:07 +02:00
parent 33a7aa46d5
commit ad4d61c38f
5 changed files with 187 additions and 20 deletions
+18 -9
View File
@@ -1,4 +1,5 @@
import deepmerge from 'deepmerge'
import isArray from './isArray'
/**
* Returns the `opts.option` $option value of the given `opts.component`.
@@ -24,16 +25,10 @@ export default function getComponentOption (opts, result = {}) {
if (typeof $options[option] !== 'undefined' && $options[option] !== null) {
let data = $options[option]
// if option is a function, replace it with it's result
if (typeof data === 'function') {
data = data.call(component)
}
if (typeof data === 'object') {
// merge with existing options
result = deepmerge(result, data, { arrayMerge })
if (isArray(data)) {
result = data.reduce((result, dataItem) => mergeDataInResult(dataItem, result, component, arrayMerge), result)
} else {
result = data
result = mergeDataInResult(data, result, component, arrayMerge)
}
}
@@ -67,3 +62,17 @@ export default function getComponentOption (opts, result = {}) {
}
return result
}
function mergeDataInResult (data, result, component, arrayMerge) {
// if option is a function, replace it with it's result
if (typeof data === 'function') {
data = data.call(component)
}
if (typeof data === 'object') {
// merge with existing options
return deepmerge(result, data, { arrayMerge })
} else {
return data
}
}
+3
View File
@@ -35,6 +35,9 @@ export default function VueMeta (Vue, options = {}) {
// bind the $meta method to this component instance
Vue.prototype.$meta = $meta(options)
// define optionMergeStrategies for the keyName
Vue.config.optionMergeStrategies[options.keyName] = Vue.config.optionMergeStrategies.created
// store an id to keep track of DOM updates
let batchID = null
+70 -11
View File
@@ -43,19 +43,23 @@ describe('getComponentOption', () => {
expect(mergedOption).to.eql({ bar: 'baz', fizz: 'buzz' })
})
it('allows for a custom array merge strategy', () => {
it('allows for a custom array merge strategy in object literal', () => {
Vue.component('array-child', {
template: '<div></div>',
foo: [
{ name: 'flower', content: 'rose' }
]
foo: {
flowers: [
{ name: 'flower', content: 'rose' }
]
}
})
component = new Vue({
render: (h) => h('div', null, [h('array-child')]),
foo: [
{ name: 'flower', content: 'tulip' }
],
foo: {
flowers: [
{ name: 'flower', content: 'tulip' }
]
},
el: container
})
@@ -68,9 +72,64 @@ describe('getComponentOption', () => {
}
})
expect(mergedOption).to.eql([
{ name: 'flower', content: 'tulip' },
{ name: 'flower', content: 'rose' }
])
expect(mergedOption).to.eql({
flowers: [
{ name: 'flower', content: 'tulip' },
{ name: 'flower', content: 'rose' }
]
})
})
it('merges arrays of objects literal options', () => {
component = new Vue({ someOption: [{ foo: 'hello' }, { bar: 'there' }] })
const mergedOption = getComponentOption({ component, option: 'someOption' })
expect(mergedOption).to.eql({ foo: 'hello', bar: 'there' })
})
it('merges arrays of mixed object literals and functions', () => {
component = new Vue({
cake: 'good',
desserts: [
{ yogurt: 'meh' },
function someFunction () {
return { cake: this.$options.cake }
},
function someOtherFunction () {
return { pineapple: 'not bad' }
}
]
})
const mergedOption = getComponentOption({ component, option: 'desserts' })
expect(mergedOption).to.eql({ yogurt: 'meh', cake: 'good', pineapple: 'not bad' })
})
it('uses custom array merge strategy when merging arrays in arrays of options', () => {
component = new Vue({
template: '<div></div>',
foo: [
{ cars: [{ brand: 'renault', color: 'red' }] },
function someFunction () {
return { cars: [{ brand: 'peugeot', color: 'blue' }] }
}
]
})
const mergedOption = getComponentOption({
component,
option: 'foo',
deep: true,
arrayMerge (target, source) {
return target.concat(source)
}
})
expect(mergedOption).to.eql({
cars: [
{ brand: 'renault', color: 'red' },
{ brand: 'peugeot', color: 'blue' }
]
})
})
})
+91
View File
@@ -21,6 +21,9 @@ const defaultOptions = {
const getMetaInfo = _getMetaInfo(defaultOptions)
// define optionMergeStrategies for the keyName
Vue.config.optionMergeStrategies[VUE_META_KEY_NAME] = Vue.config.optionMergeStrategies.created
describe('getMetaInfo', () => {
// const container = document.createElement('div')
let component
@@ -530,4 +533,92 @@ describe('getMetaInfo', () => {
__dangerouslyDisableSanitizersByTagID: {}
})
})
it('properly merges mixins options', () => {
const mixin1 = {
metaInfo: function () {
return {
title: 'This title will be overridden',
meta: [
{
vmid: 'og:title',
property: 'og:title',
content: 'This title will be overridden'
},
{
vmid: 'og:fromMixin1',
property: 'og:fromMixin1',
content: 'This is from mixin1'
}
]
}
}
}
const mixin2 = {
metaInfo: {
meta: [
{
vmid: 'og:fromMixin2',
property: 'og:fromMixin2',
content: 'This is from mixin2'
}
]
}
}
const component = new Vue({
mixins: [mixin1, mixin2],
metaInfo: {
title: 'New Title',
meta: [
{
vmid: 'og:title',
property: 'og:title',
content: 'New Title! - My page'
},
{
vmid: 'og:description',
property: 'og:description',
content: 'Some Description'
}
]
}
})
expect(getMetaInfo(component)).to.eql({
title: 'New Title',
titleChunk: 'New Title',
titleTemplate: '%s',
htmlAttrs: {},
headAttrs: {},
bodyAttrs: {},
meta: [
{
vmid: 'og:fromMixin1',
property: 'og:fromMixin1',
content: 'This is from mixin1'
},
{
vmid: 'og:fromMixin2',
property: 'og:fromMixin2',
content: 'This is from mixin2'
},
{
vmid: 'og:title',
property: 'og:title',
content: 'New Title! - My page'
},
{
vmid: 'og:description',
property: 'og:description',
content: 'Some Description'
}
],
base: [],
link: [],
style: [],
script: [],
noscript: [],
__dangerouslyDisableSanitizers: [],
__dangerouslyDisableSanitizersByTagID: {}
})
})
})
+5
View File
@@ -30,4 +30,9 @@ describe('plugin', () => {
const vm = new Vue(Component).$mount()
expect(vm._hasMetaInfo).to.equal(true)
})
it('setup optionMergeStrategies for the keyName', () => {
const strats = Vue.config.optionMergeStrategies
expect(strats[VUE_META_KEY_NAME]).to.equal(strats.created)
})
})