2
0
mirror of https://github.com/tenrok/vue-meta.git synced 2026-06-11 21:22:24 +03:00

Merge pull request #15 from declandewet/fix/taglist-duplicate-overrides

Favor function syntax over per-attribute function syntax
This commit is contained in:
Declan de Wet
2016-11-10 15:58:02 +02:00
committed by GitHub
13 changed files with 102 additions and 83 deletions
+28 -44
View File
@@ -75,8 +75,7 @@
- [Performance](#performance)
- [How to prevent the update on the initial page render](#how-to-prevent-the-update-on-the-initial-page-render)
- [FAQ](#faq)
- [How do I use component data in `metaInfo`?](#how-do-i-use-component-data-in-metainfo)
- [How do I use component props in `metaInfo`?](#how-do-i-use-component-props-in-metainfo)
- [How do I use component props and/or component data in `metaInfo`?](#how-do-i-use-component-props-andor-component-data-in-metainfo)
- [How do I populate `metaInfo` from the result of an asynchronous action?](#how-do-i-populate-metainfo-from-the-result-of-an-asynchronous-action)
- [Examples](#examples)
@@ -610,71 +609,56 @@ Add the `data-vue-meta-server-rendered` attribute to the `<html>` tag on the ser
Here are some answers to some frequently asked questions.
## How do I use component data in `metaInfo`?
Specify a function instead of an object. It will need to return the same type as its definition.
## How do I use component props and/or component data in `metaInfo`?
**BlogPost.vue:**
Easy. Instead of defining `metaInfo` as an object, define it as a function and access `this` as usual:
**Post.vue:**
```html
<template>
<div id="page">
<div>
<h1>{{ title }}</h1>
</div>
</template>
<script>
export default {
name: 'BlogPost',
data: () => ({
title: 'Sample blog post'
}),
metaInfo: {
title () {
return this.title
name: 'post',
props: ['title'],
data () {
return {
description: 'A blog post about some stuff'
}
},
metaInfo ()
return {
title: this.title,
meta: [
{ vmid: 'description', name: 'description', content: this.description }
]
}
}
}
</script>
```
## How do I use component props in `metaInfo`?
The same way you use data - specify a function instead of an object. It will need to return the same type as its definition.
**BlogPostWrapper.vue**
**PostContainer.vue:**
```html
<template>
<div id="page">
<blog-post :title="title"></blog-post>
<div>
<post :title="title"></post>
</div>
</template>
<script>
import BlogPost from './BlogPost.vue'
import Post from './Post.vue'
export default {
name: 'BlogPostWrapper',
components: { BlogPost },
data: () => ({
title: 'Example blog post'
})
}
</script>
```
**BlogPost.vue**
```html
<template>
<div id="page">
<h1>{{ title }}</h1>
</div>
</template>
<script>
export default {
name: 'BlogPost',
props: ['title'],
metaInfo: {
title () {
return this.title
name: 'post-container',
components: { Post },
data () {
return {
title: 'Example blog post'
}
}
}
+3 -3
View File
@@ -9,9 +9,9 @@ Vue.component('child', {
render (h) {
return h('h3', null, this.page)
},
metaInfo: {
title () {
return this.page
metaInfo () {
return {
title: this.page
}
}
})
+2 -2
View File
@@ -10,12 +10,12 @@ new Vue({
<p>Inspect Element to see the meta info</p>
</div>
`,
metaInfo: {
metaInfo: () => ({
title: 'Basic',
titleTemplate: '%s | Vue Meta Examples',
htmlAttrs: {
lang: 'en',
amp: undefined
}
}
})
}).$mount('#app')
+3 -3
View File
@@ -10,9 +10,9 @@ const ChildComponent = {
name: `child-component`,
props: ['page'],
template: `<h3>You're looking at the <strong>{{ page }}</strong> page</h3>`,
metaInfo: {
title () {
return this.page
metaInfo () {
return {
title: this.page
}
}
}
+10
View File
@@ -5,3 +5,13 @@
<p>Inspect Element to see the meta info</p>
</div>
</template>
<script>
export default {
metaInfo: {
meta: [
{ vmid: 'charset', charset: 'utf-8' }
]
}
}
</script>
+4 -1
View File
@@ -20,7 +20,10 @@
postsCount: 'publishedPostsCount'
}),
metaInfo: {
title: 'Home'
title: 'Home',
meta: [
{ vmid: 'description', name: 'description', content: 'The home page' }
]
}
}
</script>
+6 -3
View File
@@ -28,9 +28,12 @@
'isLoading',
'post'
]),
metaInfo: {
title () {
return this.isLoading ? 'Loading...' : this.post.title
metaInfo () {
return {
title: this.isLoading ? 'Loading...' : this.post.title,
meta: [
{ vmid: 'description', name: 'description', content: this.post.title }
]
}
}
}
+10
View File
@@ -5,3 +5,13 @@
<p>Inspect Element to see the meta info</p>
</div>
</template>
<script>
export default {
metaInfo: {
meta: [
{ vmid: 'charset', charset: 'utf-8' }
]
}
}
</script>
+4 -1
View File
@@ -20,7 +20,10 @@
postsCount: 'publishedPostsCount'
}),
metaInfo: {
title: 'Home'
title: 'Home',
meta: [
{ vmid: 'description', name: 'description', content: 'The home page' }
]
}
}
</script>
+6 -3
View File
@@ -18,9 +18,12 @@
computed: mapGetters([
'post'
]),
metaInfo: {
title () {
return this.post.title
metaInfo () {
return {
title: this.post.title,
meta: [
{ vmid: 'description', name: 'description', content: this.post.title }
]
}
}
}
+9 -7
View File
@@ -13,26 +13,28 @@ import deepmerge from 'deepmerge'
* @param {Function} opts.arrayMerge - how should arrays be merged?
* @param {Object} [result={}] - result so far
* @return {Object} result - final aggregated result
* @return {Object} result.mergedOption - the actual merged options
* @return {Object} result.deepestComponentWithMetaInfo - the deepest component in the heirarchy that has a `metaInfo` instance property
*/
export default function getComponentOption (opts, result = { mergedOption: {} }) {
export default function getComponentOption (opts, result = {}) {
const { component, option, deep, arrayMerge } = opts
const { $options } = component
// only collect option data if it exists
if (typeof $options[option] !== 'undefined' && $options[option] !== null) {
const data = $options[option]
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.mergedOption = deepmerge(result.mergedOption, data, {
result = deepmerge(result, data, {
clone: true,
arrayMerge
})
result.deepestComponentWithMetaInfo = component
} else {
result.mergedOption = data
result = data
}
}
+2 -12
View File
@@ -25,7 +25,7 @@ export default function getMetaInfo (component) {
}
// collect & aggregate all metaInfo $options
const { mergedOption: info, deepestComponentWithMetaInfo } = getComponentOption({
const info = getComponentOption({
component,
option: 'metaInfo',
deep: true,
@@ -71,15 +71,5 @@ export default function getMetaInfo (component) {
info.base = Object.keys(info.base).length ? [info.base] : []
}
const metaInfo = deepmerge(defaultInfo, info)
// 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(deepestComponentWithMetaInfo)
}
})
return metaInfo
return deepmerge(defaultInfo, info)
}
+15 -4
View File
@@ -9,16 +9,27 @@ describe('getComponentOption', () => {
it('returns an empty object when no matching options are found', () => {
component = new Vue()
const { mergedOption } = getComponentOption({ component, option: 'noop' })
const mergedOption = getComponentOption({ component, option: 'noop' })
expect(mergedOption).to.eql({})
})
it('fetches the given option from the given component', () => {
component = new Vue({ someOption: 'foo' })
const { mergedOption } = getComponentOption({ component, option: 'someOption' })
const mergedOption = getComponentOption({ component, option: 'someOption' })
expect(mergedOption).to.eql('foo')
})
it('calls a function option, injecting the component as context', () => {
component = new Vue({
name: 'foobar',
someFunc () {
return this.$options.name
}
})
const mergedOption = getComponentOption({ component, option: 'someFunc' })
expect(mergedOption).to.eql('foobar')
})
it('fetches deeply nested component options and merges them', () => {
Vue.component('merge-child', { template: '<div></div>', foo: { bar: 'baz' } })
@@ -28,7 +39,7 @@ describe('getComponentOption', () => {
el: container
})
const { mergedOption } = getComponentOption({ component, option: 'foo', deep: true })
const mergedOption = getComponentOption({ component, option: 'foo', deep: true })
expect(mergedOption).to.eql({ bar: 'baz', fizz: 'buzz' })
})
@@ -48,7 +59,7 @@ describe('getComponentOption', () => {
el: container
})
const { mergedOption } = getComponentOption({
const mergedOption = getComponentOption({
component,
option: 'foo',
deep: true,