mirror of
https://github.com/tenrok/vue-meta.git
synced 2026-06-24 01:30:33 +03:00
Add meta templates
This commit is contained in:
@@ -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">
|
<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])
|
#### `link` ([Object])
|
||||||
|
|
||||||
Each item in the array maps to a newly-created `<link>` element, where object properties map to attributes.
|
Each item in the array maps to a newly-created `<link>` element, where object properties map to attributes.
|
||||||
|
|||||||
@@ -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
|
// that both have `vmid` of "description", then vue-meta will overwrite the
|
||||||
// shallowest one with the deepest one.
|
// shallowest one with the deepest one.
|
||||||
export const VUE_META_TAG_LIST_ID_KEY_NAME = 'vmid'
|
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'
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import deepmerge from 'deepmerge'
|
|||||||
* @return {Object} result - final aggregated result
|
* @return {Object} result - final aggregated result
|
||||||
*/
|
*/
|
||||||
export default function getComponentOption (opts, result = {}) {
|
export default function getComponentOption (opts, result = {}) {
|
||||||
const { component, option, deep, arrayMerge } = opts
|
const { component, option, deep, arrayMerge, metaTemplateKeyName } = opts
|
||||||
const { $options } = component
|
const { $options } = component
|
||||||
|
|
||||||
if (component._inactive) return result
|
if (component._inactive) return result
|
||||||
@@ -48,6 +48,22 @@ export default function getComponentOption (opts, result = {}) {
|
|||||||
}, 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
|
return result
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ const escapeHTML = (str) => typeof window === 'undefined'
|
|||||||
.replace(/'/g, '\u0027')
|
.replace(/'/g, '\u0027')
|
||||||
|
|
||||||
export default function _getMetaInfo (options = {}) {
|
export default function _getMetaInfo (options = {}) {
|
||||||
const { keyName, tagIDKeyName } = options
|
const { keyName, tagIDKeyName, metaTemplateKeyName } = options
|
||||||
/**
|
/**
|
||||||
* Returns the correct meta info for the given component
|
* Returns the correct meta info for the given component
|
||||||
* (child components will overwrite parent meta info)
|
* (child components will overwrite parent meta info)
|
||||||
@@ -52,6 +52,7 @@ export default function _getMetaInfo (options = {}) {
|
|||||||
component,
|
component,
|
||||||
option: keyName,
|
option: keyName,
|
||||||
deep: true,
|
deep: true,
|
||||||
|
metaTemplateKeyName,
|
||||||
arrayMerge (target, source) {
|
arrayMerge (target, source) {
|
||||||
// we concat the arrays without merging objects contained in,
|
// we concat the arrays without merging objects contained in,
|
||||||
// but we check for a `vmid` property on each object in the array
|
// but we check for a `vmid` property on each object in the array
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ import {
|
|||||||
VUE_META_KEY_NAME,
|
VUE_META_KEY_NAME,
|
||||||
VUE_META_ATTRIBUTE,
|
VUE_META_ATTRIBUTE,
|
||||||
VUE_META_SERVER_RENDERED_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'
|
} from './constants'
|
||||||
|
|
||||||
// automatic install
|
// automatic install
|
||||||
@@ -22,6 +23,7 @@ export default function VueMeta (Vue, options = {}) {
|
|||||||
// set some default options
|
// set some default options
|
||||||
const defaultOptions = {
|
const defaultOptions = {
|
||||||
keyName: VUE_META_KEY_NAME,
|
keyName: VUE_META_KEY_NAME,
|
||||||
|
metaTemplateKeyName: VUE_META_TEMPLATE_KEY_NAME,
|
||||||
attribute: VUE_META_ATTRIBUTE,
|
attribute: VUE_META_ATTRIBUTE,
|
||||||
ssrAttribute: VUE_META_SERVER_RENDERED_ATTRIBUTE,
|
ssrAttribute: VUE_META_SERVER_RENDERED_ATTRIBUTE,
|
||||||
tagIDKeyName: VUE_META_TAG_LIST_ID_KEY_NAME
|
tagIDKeyName: VUE_META_TAG_LIST_ID_KEY_NAME
|
||||||
|
|||||||
+197
-6
@@ -1,10 +1,11 @@
|
|||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import _getMetaInfo from '../src/shared/getMetaInfo'
|
import _getMetaInfo from '../src/shared/getMetaInfo'
|
||||||
import {
|
import {
|
||||||
VUE_META_KEY_NAME,
|
|
||||||
VUE_META_ATTRIBUTE,
|
VUE_META_ATTRIBUTE,
|
||||||
|
VUE_META_KEY_NAME,
|
||||||
VUE_META_SERVER_RENDERED_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 '../src/shared/constants'
|
} from '../src/shared/constants'
|
||||||
|
|
||||||
// set some default options
|
// set some default options
|
||||||
@@ -12,6 +13,7 @@ const defaultOptions = {
|
|||||||
keyName: VUE_META_KEY_NAME,
|
keyName: VUE_META_KEY_NAME,
|
||||||
attribute: VUE_META_ATTRIBUTE,
|
attribute: VUE_META_ATTRIBUTE,
|
||||||
ssrAttribute: VUE_META_SERVER_RENDERED_ATTRIBUTE,
|
ssrAttribute: VUE_META_SERVER_RENDERED_ATTRIBUTE,
|
||||||
|
metaTemplateKeyName: VUE_META_TEMPLATE_KEY_NAME,
|
||||||
tagIDKeyName: VUE_META_TAG_LIST_ID_KEY_NAME
|
tagIDKeyName: VUE_META_TAG_LIST_ID_KEY_NAME
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,7 +110,7 @@ describe('getMetaInfo', () => {
|
|||||||
component = new Vue({
|
component = new Vue({
|
||||||
metaInfo: {
|
metaInfo: {
|
||||||
title: 'Hello',
|
title: 'Hello',
|
||||||
titleTemplate: titleTemplate,
|
titleTemplate,
|
||||||
meta: [
|
meta: [
|
||||||
{ charset: 'utf-8' }
|
{ charset: 'utf-8' }
|
||||||
]
|
]
|
||||||
@@ -117,7 +119,7 @@ describe('getMetaInfo', () => {
|
|||||||
expect(getMetaInfo(component)).to.eql({
|
expect(getMetaInfo(component)).to.eql({
|
||||||
title: 'Hello Function World',
|
title: 'Hello Function World',
|
||||||
titleChunk: 'Hello',
|
titleChunk: 'Hello',
|
||||||
titleTemplate: titleTemplate,
|
titleTemplate,
|
||||||
htmlAttrs: {},
|
htmlAttrs: {},
|
||||||
headAttrs: {},
|
headAttrs: {},
|
||||||
bodyAttrs: {},
|
bodyAttrs: {},
|
||||||
@@ -142,7 +144,7 @@ describe('getMetaInfo', () => {
|
|||||||
component = new Vue({
|
component = new Vue({
|
||||||
metaInfo: {
|
metaInfo: {
|
||||||
title: 'Hello',
|
title: 'Hello',
|
||||||
titleTemplate: titleTemplate,
|
titleTemplate,
|
||||||
meta: [
|
meta: [
|
||||||
{ charset: 'utf-8' }
|
{ charset: 'utf-8' }
|
||||||
]
|
]
|
||||||
@@ -156,7 +158,7 @@ describe('getMetaInfo', () => {
|
|||||||
expect(getMetaInfo(component)).to.eql({
|
expect(getMetaInfo(component)).to.eql({
|
||||||
title: 'Hello Function World',
|
title: 'Hello Function World',
|
||||||
titleChunk: 'Hello',
|
titleChunk: 'Hello',
|
||||||
titleTemplate: titleTemplate,
|
titleTemplate,
|
||||||
htmlAttrs: {},
|
htmlAttrs: {},
|
||||||
headAttrs: {},
|
headAttrs: {},
|
||||||
bodyAttrs: {},
|
bodyAttrs: {},
|
||||||
@@ -172,4 +174,193 @@ describe('getMetaInfo', () => {
|
|||||||
__dangerouslyDisableSanitizersByTagID: {}
|
__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: {}
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user