2
0
mirror of https://github.com/tenrok/vue-meta.git synced 2026-06-12 15:12:26 +03:00

Add meta templates

This commit is contained in:
Alexander Lichter
2018-03-19 12:07:07 +01:00
parent 617500fe98
commit 0457b585e5
6 changed files with 246 additions and 9 deletions
+24
View File
@@ -458,6 +458,30 @@ Each item in the array maps to a newly-created `<meta>` element, where object pr
<meta name="viewport" content="width=device-width, initial-scale=1">
```
Since v1.5.0, you can now set up meta templates that work similar to the titleTemplate:
```js
{
metaInfo: {
meta: [
{ charset: 'utf-8' },
{
'vmid': 'og:title',
'property': 'og:title',
'content': 'Test title',
'template': chunk => `${chunk} - My page` //or as string template: '%s - My page'
}
]
}
}
```
```html
<meta charset="utf-8">
<meta name="og:title" property="og:title" content="Test title - My page">
```
#### `link` ([Object])
Each item in the array maps to a newly-created `<link>` element, where object properties map to attributes.
+3
View File
@@ -19,3 +19,6 @@ export const VUE_META_SERVER_RENDERED_ATTRIBUTE = 'data-vue-meta-server-rendered
// that both have `vmid` of "description", then vue-meta will overwrite the
// shallowest one with the deepest one.
export const VUE_META_TAG_LIST_ID_KEY_NAME = 'vmid'
// This is the key name for possible meta templates
export const VUE_META_TEMPLATE_KEY_NAME = 'template'
+17 -1
View File
@@ -15,7 +15,7 @@ import deepmerge from 'deepmerge'
* @return {Object} result - final aggregated result
*/
export default function getComponentOption (opts, result = {}) {
const { component, option, deep, arrayMerge } = opts
const { component, option, deep, arrayMerge, metaTemplateKeyName } = opts
const { $options } = component
if (component._inactive) return result
@@ -48,6 +48,22 @@ export default function getComponentOption (opts, result = {}) {
}, result)
})
}
if (metaTemplateKeyName && result.hasOwnProperty('meta')) {
result.meta = Object.keys(result.meta).map(metaKey => {
const metaObject = result.meta[metaKey]
if (!metaObject.hasOwnProperty(metaTemplateKeyName) || !metaObject.hasOwnProperty('content') || typeof metaObject[metaTemplateKeyName] === 'undefined') {
return result.meta[metaKey]
}
const template = metaObject[metaTemplateKeyName]
delete metaObject[metaTemplateKeyName]
if (template) {
metaObject.content = typeof template === 'function' ? template(metaObject.content) : template.replace(/%s/g, metaObject.content)
}
return metaObject
})
}
return result
}
+2 -1
View File
@@ -20,7 +20,7 @@ const escapeHTML = (str) => typeof window === 'undefined'
.replace(/'/g, '\u0027')
export default function _getMetaInfo (options = {}) {
const { keyName, tagIDKeyName } = options
const { keyName, tagIDKeyName, metaTemplateKeyName } = options
/**
* Returns the correct meta info for the given component
* (child components will overwrite parent meta info)
@@ -52,6 +52,7 @@ export default function _getMetaInfo (options = {}) {
component,
option: keyName,
deep: true,
metaTemplateKeyName,
arrayMerge (target, source) {
// we concat the arrays without merging objects contained in,
// but we check for a `vmid` property on each object in the array
+3 -1
View File
@@ -6,7 +6,8 @@ import {
VUE_META_KEY_NAME,
VUE_META_ATTRIBUTE,
VUE_META_SERVER_RENDERED_ATTRIBUTE,
VUE_META_TAG_LIST_ID_KEY_NAME
VUE_META_TAG_LIST_ID_KEY_NAME,
VUE_META_TEMPLATE_KEY_NAME
} from './constants'
// automatic install
@@ -22,6 +23,7 @@ export default function VueMeta (Vue, options = {}) {
// set some default options
const defaultOptions = {
keyName: VUE_META_KEY_NAME,
metaTemplateKeyName: VUE_META_TEMPLATE_KEY_NAME,
attribute: VUE_META_ATTRIBUTE,
ssrAttribute: VUE_META_SERVER_RENDERED_ATTRIBUTE,
tagIDKeyName: VUE_META_TAG_LIST_ID_KEY_NAME
+197 -6
View File
@@ -1,10 +1,11 @@
import Vue from 'vue'
import _getMetaInfo from '../src/shared/getMetaInfo'
import {
VUE_META_KEY_NAME,
VUE_META_ATTRIBUTE,
VUE_META_KEY_NAME,
VUE_META_SERVER_RENDERED_ATTRIBUTE,
VUE_META_TAG_LIST_ID_KEY_NAME
VUE_META_TAG_LIST_ID_KEY_NAME,
VUE_META_TEMPLATE_KEY_NAME
} from '../src/shared/constants'
// set some default options
@@ -12,6 +13,7 @@ const defaultOptions = {
keyName: VUE_META_KEY_NAME,
attribute: VUE_META_ATTRIBUTE,
ssrAttribute: VUE_META_SERVER_RENDERED_ATTRIBUTE,
metaTemplateKeyName: VUE_META_TEMPLATE_KEY_NAME,
tagIDKeyName: VUE_META_TAG_LIST_ID_KEY_NAME
}
@@ -108,7 +110,7 @@ describe('getMetaInfo', () => {
component = new Vue({
metaInfo: {
title: 'Hello',
titleTemplate: titleTemplate,
titleTemplate,
meta: [
{ charset: 'utf-8' }
]
@@ -117,7 +119,7 @@ describe('getMetaInfo', () => {
expect(getMetaInfo(component)).to.eql({
title: 'Hello Function World',
titleChunk: 'Hello',
titleTemplate: titleTemplate,
titleTemplate,
htmlAttrs: {},
headAttrs: {},
bodyAttrs: {},
@@ -142,7 +144,7 @@ describe('getMetaInfo', () => {
component = new Vue({
metaInfo: {
title: 'Hello',
titleTemplate: titleTemplate,
titleTemplate,
meta: [
{ charset: 'utf-8' }
]
@@ -156,7 +158,7 @@ describe('getMetaInfo', () => {
expect(getMetaInfo(component)).to.eql({
title: 'Hello Function World',
titleChunk: 'Hello',
titleTemplate: titleTemplate,
titleTemplate,
htmlAttrs: {},
headAttrs: {},
bodyAttrs: {},
@@ -172,4 +174,193 @@ describe('getMetaInfo', () => {
__dangerouslyDisableSanitizersByTagID: {}
})
})
it('properly uses string meta templates', () => {
component = new Vue({
metaInfo: {
title: 'Hello',
meta: [
{
vmid: 'og:title',
property: 'og:title',
content: 'Test title',
template: '%s - My page'
}
]
}
})
expect(getMetaInfo(component)).to.eql({
title: 'Hello',
titleChunk: 'Hello',
titleTemplate: '%s',
htmlAttrs: {},
headAttrs: {},
bodyAttrs: {},
meta: [
{
vmid: 'og:title',
property: 'og:title',
content: 'Test title - My page'
}
],
base: [],
link: [],
style: [],
script: [],
noscript: [],
__dangerouslyDisableSanitizers: [],
__dangerouslyDisableSanitizersByTagID: {}
})
})
it('properly uses function meta templates', () => {
component = new Vue({
metaInfo: {
title: 'Hello',
meta: [
{
vmid: 'og:title',
property: 'og:title',
content: 'Test title',
template: chunk => `${chunk} - My page`
}
]
}
})
expect(getMetaInfo(component)).to.eql({
title: 'Hello',
titleChunk: 'Hello',
titleTemplate: '%s',
htmlAttrs: {},
headAttrs: {},
bodyAttrs: {},
meta: [
{
vmid: 'og:title',
property: 'og:title',
content: 'Test title - My page'
}
],
base: [],
link: [],
style: [],
script: [],
noscript: [],
__dangerouslyDisableSanitizers: [],
__dangerouslyDisableSanitizersByTagID: {}
})
})
it('properly uses content only if template is not defined', () => {
component = new Vue({
metaInfo: {
title: 'Hello',
meta: [
{
vmid: 'og:title',
property: 'og:title',
content: 'Test title'
}
]
}
})
expect(getMetaInfo(component)).to.eql({
title: 'Hello',
titleChunk: 'Hello',
titleTemplate: '%s',
htmlAttrs: {},
headAttrs: {},
bodyAttrs: {},
meta: [
{
vmid: 'og:title',
property: 'og:title',
content: 'Test title'
}
],
base: [],
link: [],
style: [],
script: [],
noscript: [],
__dangerouslyDisableSanitizers: [],
__dangerouslyDisableSanitizersByTagID: {}
})
})
it('properly uses content only if template is null', () => {
component = new Vue({
metaInfo: {
title: 'Hello',
meta: [
{
vmid: 'og:title',
property: 'og:title',
content: 'Test title',
template: null
}
]
}
})
expect(getMetaInfo(component)).to.eql({
title: 'Hello',
titleChunk: 'Hello',
titleTemplate: '%s',
htmlAttrs: {},
headAttrs: {},
bodyAttrs: {},
meta: [
{
vmid: 'og:title',
property: 'og:title',
content: 'Test title'
}
],
base: [],
link: [],
style: [],
script: [],
noscript: [],
__dangerouslyDisableSanitizers: [],
__dangerouslyDisableSanitizersByTagID: {}
})
})
it('properly uses content only if template is false', () => {
component = new Vue({
metaInfo: {
title: 'Hello',
meta: [
{
vmid: 'og:title',
property: 'og:title',
content: 'Test title',
template: false
}
]
}
})
expect(getMetaInfo(component)).to.eql({
title: 'Hello',
titleChunk: 'Hello',
titleTemplate: '%s',
htmlAttrs: {},
headAttrs: {},
bodyAttrs: {},
meta: [
{
vmid: 'og:title',
property: 'og:title',
content: 'Test title'
}
],
base: [],
link: [],
style: [],
script: [],
noscript: [],
__dangerouslyDisableSanitizers: [],
__dangerouslyDisableSanitizersByTagID: {}
})
})
})