mirror of
https://github.com/tenrok/vue-meta.git
synced 2026-06-25 10:40:33 +03:00
feat: add option waitOnDestroyed
This commit is contained in:
+7
-2
@@ -20,17 +20,22 @@ export default function $meta (options) {
|
|||||||
'setOptions': (newOptions) => {
|
'setOptions': (newOptions) => {
|
||||||
const refreshNavKey = 'refreshOnceOnNavigation'
|
const refreshNavKey = 'refreshOnceOnNavigation'
|
||||||
if (newOptions && newOptions[refreshNavKey]) {
|
if (newOptions && newOptions[refreshNavKey]) {
|
||||||
options.refreshOnceOnNavigation = newOptions[refreshNavKey]
|
options.refreshOnceOnNavigation = !!newOptions[refreshNavKey]
|
||||||
addNavGuards($root)
|
addNavGuards($root)
|
||||||
}
|
}
|
||||||
|
|
||||||
const debounceWaitKey = 'debounceWait'
|
const debounceWaitKey = 'debounceWait'
|
||||||
if (newOptions && newOptions[debounceWaitKey]) {
|
if (newOptions && debounceWaitKey in newOptions) {
|
||||||
const debounceWait = parseInt(newOptions[debounceWaitKey])
|
const debounceWait = parseInt(newOptions[debounceWaitKey])
|
||||||
if (!isNaN(debounceWait)) {
|
if (!isNaN(debounceWait)) {
|
||||||
options.debounceWait = debounceWait
|
options.debounceWait = debounceWait
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const waitOnDestroyedKey = 'waitOnDestroyed'
|
||||||
|
if (newOptions && waitOnDestroyedKey in newOptions) {
|
||||||
|
options.waitOnDestroyed = !!newOptions[waitOnDestroyedKey]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
'refresh': () => refresh($root, options),
|
'refresh': () => refresh($root, options),
|
||||||
'inject': () => process.server ? inject($root, options) : showWarningNotSupportedInBrowserBundle('inject'),
|
'inject': () => process.server ? inject($root, options) : showWarningNotSupportedInBrowserBundle('inject'),
|
||||||
|
|||||||
@@ -52,6 +52,9 @@ export const ssrAppId = 'ssr'
|
|||||||
// How long meta update
|
// How long meta update
|
||||||
export const debounceWait = 10
|
export const debounceWait = 10
|
||||||
|
|
||||||
|
// How long meta update
|
||||||
|
export const waitOnDestroyed = true
|
||||||
|
|
||||||
export const defaultOptions = {
|
export const defaultOptions = {
|
||||||
keyName,
|
keyName,
|
||||||
attribute,
|
attribute,
|
||||||
@@ -59,6 +62,7 @@ export const defaultOptions = {
|
|||||||
tagIDKeyName,
|
tagIDKeyName,
|
||||||
contentKeyName,
|
contentKeyName,
|
||||||
metaTemplateKeyName,
|
metaTemplateKeyName,
|
||||||
|
waitOnDestroyed,
|
||||||
debounceWait,
|
debounceWait,
|
||||||
ssrAppId
|
ssrAppId
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-4
@@ -147,25 +147,32 @@ export default function createMixin (Vue, options) {
|
|||||||
},
|
},
|
||||||
// TODO: move back into beforeCreate when Vue issue is resolved
|
// TODO: move back into beforeCreate when Vue issue is resolved
|
||||||
destroyed () {
|
destroyed () {
|
||||||
const $this = this
|
|
||||||
// do not trigger refresh:
|
// do not trigger refresh:
|
||||||
|
// - when user configured to not wait for transitions on destroyed
|
||||||
// - when the component doesnt have a parent
|
// - when the component doesnt have a parent
|
||||||
// - doesnt have metaInfo defined
|
// - doesnt have metaInfo defined
|
||||||
if (!$this.$parent || !hasMetaInfo($this)) {
|
if (!this.$parent || !hasMetaInfo(this)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (!options.waitOnDestroyed || !this.$el || !this.$el.offsetParent) {
|
||||||
|
triggerUpdate(options, this.$root, 'destroyed')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait that element is hidden before refreshing meta tags (to support animations)
|
// Wait that element is hidden before refreshing meta tags (to support animations)
|
||||||
const interval = setInterval(() => {
|
const interval = setInterval(() => {
|
||||||
if ($this.$el && $this.$el.offsetParent !== null) {
|
if (this.$el && this.$el.offsetParent !== null) {
|
||||||
/* istanbul ignore next line */
|
/* istanbul ignore next line */
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
clearInterval(interval)
|
clearInterval(interval)
|
||||||
|
|
||||||
triggerUpdate(options, $this.$root, 'destroyed')
|
triggerUpdate(options, this.$root, 'destroyed')
|
||||||
}, 50)
|
}, 50)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { isObject } from '../utils/is-type'
|
import { isObject, isUndefined } from '../utils/is-type'
|
||||||
import { defaultOptions } from './constants'
|
import { defaultOptions } from './constants'
|
||||||
|
|
||||||
export function setOptions (options) {
|
export function setOptions (options) {
|
||||||
@@ -17,7 +17,8 @@ export function setOptions (options) {
|
|||||||
tagIDKeyName: options['tagIDKeyName'] || defaultOptions.tagIDKeyName,
|
tagIDKeyName: options['tagIDKeyName'] || defaultOptions.tagIDKeyName,
|
||||||
contentKeyName: options['contentKeyName'] || defaultOptions.contentKeyName,
|
contentKeyName: options['contentKeyName'] || defaultOptions.contentKeyName,
|
||||||
metaTemplateKeyName: options['metaTemplateKeyName'] || defaultOptions.metaTemplateKeyName,
|
metaTemplateKeyName: options['metaTemplateKeyName'] || defaultOptions.metaTemplateKeyName,
|
||||||
debounceWait: options['debounceWait'] || defaultOptions.debounceWait,
|
debounceWait: isUndefined(options['debounceWait']) ? defaultOptions.debounceWait : options['debounceWait'],
|
||||||
|
waitOnDestroyed: isUndefined(options['waitOnDestroyed']) ? defaultOptions.waitOnDestroyed : options['waitOnDestroyed'],
|
||||||
ssrAppId: options['ssrAppId'] || defaultOptions.ssrAppId,
|
ssrAppId: options['ssrAppId'] || defaultOptions.ssrAppId,
|
||||||
refreshOnceOnNavigation: !!options['refreshOnceOnNavigation']
|
refreshOnceOnNavigation: !!options['refreshOnceOnNavigation']
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { getComponentMetaInfo } from '../../src/shared/getComponentOption'
|
import { getComponentMetaInfo } from '../../src/shared/getComponentOption'
|
||||||
import _getMetaInfo from '../../src/shared/getMetaInfo'
|
import _getMetaInfo from '../../src/shared/getMetaInfo'
|
||||||
|
import { triggerUpdate, batchUpdate } from '../../src/client/update'
|
||||||
import { mount, createWrapper, loadVueMetaPlugin, vmTick, clearClientAttributeMap } from '../utils'
|
import { mount, createWrapper, loadVueMetaPlugin, vmTick, clearClientAttributeMap } from '../utils'
|
||||||
import { defaultOptions } from '../../src/shared/constants'
|
import { defaultOptions } from '../../src/shared/constants'
|
||||||
|
|
||||||
@@ -10,6 +11,7 @@ import Changed from '../components/changed.vue'
|
|||||||
|
|
||||||
const getMetaInfo = component => _getMetaInfo(defaultOptions, getComponentMetaInfo(defaultOptions, component))
|
const getMetaInfo = component => _getMetaInfo(defaultOptions, getComponentMetaInfo(defaultOptions, component))
|
||||||
|
|
||||||
|
jest.mock('../../src/client/update')
|
||||||
jest.mock('../../src/utils/window', () => ({
|
jest.mock('../../src/utils/window', () => ({
|
||||||
hasGlobalWindow: false
|
hasGlobalWindow: false
|
||||||
}))
|
}))
|
||||||
@@ -48,6 +50,8 @@ describe('components', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
|
jest.clearAllMocks()
|
||||||
|
|
||||||
elements.html.getAttributeNames().forEach(name => elements.html.removeAttribute(name))
|
elements.html.getAttributeNames().forEach(name => elements.html.removeAttribute(name))
|
||||||
elements.head.childNodes.forEach(child => child.remove())
|
elements.head.childNodes.forEach(child => child.remove())
|
||||||
elements.head.getAttributeNames().forEach(name => elements.head.removeAttribute(name))
|
elements.head.getAttributeNames().forEach(name => elements.head.removeAttribute(name))
|
||||||
@@ -209,6 +213,10 @@ describe('components', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
test('changed function is called', async () => {
|
test('changed function is called', async () => {
|
||||||
|
const update = jest.requireActual('../../src/client/update')
|
||||||
|
triggerUpdate.mockImplementation(update.triggerUpdate)
|
||||||
|
batchUpdate.mockImplementation(update.batchUpdate)
|
||||||
|
|
||||||
let context
|
let context
|
||||||
const changed = jest.fn(function () {
|
const changed = jest.fn(function () {
|
||||||
context = this
|
context = this
|
||||||
@@ -226,6 +234,9 @@ describe('components', () => {
|
|||||||
|
|
||||||
expect(changed).toHaveBeenCalledTimes(2)
|
expect(changed).toHaveBeenCalledTimes(2)
|
||||||
expect(context._uid).toBe(wrapper.vm._uid)
|
expect(context._uid).toBe(wrapper.vm._uid)
|
||||||
|
|
||||||
|
triggerUpdate.mockRestore()
|
||||||
|
batchUpdate.mockRestore()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('afterNavigation function is called with refreshOnce: true', async () => {
|
test('afterNavigation function is called with refreshOnce: true', async () => {
|
||||||
@@ -299,6 +310,10 @@ describe('components', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
test('changes before hydration initialization trigger an update', async () => {
|
test('changes before hydration initialization trigger an update', async () => {
|
||||||
|
const update = jest.requireActual('../../src/client/update')
|
||||||
|
triggerUpdate.mockImplementation(update.triggerUpdate)
|
||||||
|
batchUpdate.mockImplementation(update.batchUpdate)
|
||||||
|
|
||||||
const { html } = elements
|
const { html } = elements
|
||||||
html.setAttribute(defaultOptions.ssrAttribute, 'true')
|
html.setAttribute(defaultOptions.ssrAttribute, 'true')
|
||||||
|
|
||||||
@@ -342,9 +357,16 @@ describe('components', () => {
|
|||||||
|
|
||||||
expect(html.getAttribute('theme')).toBe('dark')
|
expect(html.getAttribute('theme')).toBe('dark')
|
||||||
wrapper.destroy()
|
wrapper.destroy()
|
||||||
|
|
||||||
|
triggerUpdate.mockRestore()
|
||||||
|
batchUpdate.mockRestore()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('changes during hydration initialization trigger an update', async () => {
|
test('changes during hydration initialization trigger an update', async () => {
|
||||||
|
const update = jest.requireActual('../../src/client/update')
|
||||||
|
triggerUpdate.mockImplementation(update.triggerUpdate)
|
||||||
|
batchUpdate.mockImplementation(update.batchUpdate)
|
||||||
|
|
||||||
const { html } = elements
|
const { html } = elements
|
||||||
html.setAttribute(defaultOptions.ssrAttribute, 'true')
|
html.setAttribute(defaultOptions.ssrAttribute, 'true')
|
||||||
|
|
||||||
@@ -386,6 +408,9 @@ describe('components', () => {
|
|||||||
|
|
||||||
expect(html.getAttribute('theme')).toBe('dark')
|
expect(html.getAttribute('theme')).toBe('dark')
|
||||||
wrapper.destroy()
|
wrapper.destroy()
|
||||||
|
|
||||||
|
triggerUpdate.mockRestore()
|
||||||
|
batchUpdate.mockRestore()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('can add/remove meta info from additional app ', () => {
|
test('can add/remove meta info from additional app ', () => {
|
||||||
@@ -504,13 +529,34 @@ describe('components', () => {
|
|||||||
expect(guards.after).not.toBeUndefined()
|
expect(guards.after).not.toBeUndefined()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('can set option debounceWait runtime', () => {
|
test('destroyed hook calls triggerUpdate delayed', async () => {
|
||||||
const wrapper = mount(HelloWorld, { localVue: Vue })
|
jest.useFakeTimers()
|
||||||
|
const wrapper = mount(HelloWorld, { localVue: Vue, parentComponent: { render: h => h('div') } })
|
||||||
|
const spy = jest.spyOn(wrapper.vm.$el, 'offsetParent', 'get').mockReturnValue(true)
|
||||||
|
|
||||||
expect(wrapper.vm.$meta().getOptions().debounceWait).toBe(10)
|
wrapper.destroy()
|
||||||
|
|
||||||
wrapper.vm.$meta().setOptions({ debounceWait: 69420 })
|
await vmTick(wrapper.vm)
|
||||||
|
|
||||||
expect(wrapper.vm.$meta().getOptions().debounceWait).toBe(69420)
|
expect(triggerUpdate).toHaveBeenCalledTimes(1)
|
||||||
|
spy.mockRestore()
|
||||||
|
|
||||||
|
jest.advanceTimersByTime(51)
|
||||||
|
|
||||||
|
expect(triggerUpdate).toHaveBeenCalledTimes(2)
|
||||||
|
expect(triggerUpdate).toHaveBeenCalledWith(expect.any(Object), expect.any(Object), 'destroyed')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('destroyed hook calls triggerUpdate immediately when waitOnDestroyed: false', async () => {
|
||||||
|
jest.useFakeTimers()
|
||||||
|
|
||||||
|
const wrapper = mount(HelloWorld, { localVue: Vue, parentComponent: { render: h => h('div') } })
|
||||||
|
wrapper.vm.$meta().setOptions({ waitOnDestroyed: false })
|
||||||
|
wrapper.destroy()
|
||||||
|
|
||||||
|
await vmTick(wrapper.vm)
|
||||||
|
|
||||||
|
expect(triggerUpdate).toHaveBeenCalledTimes(2)
|
||||||
|
expect(triggerUpdate).toHaveBeenCalledWith(expect.any(Object), expect.any(Object), 'destroyed')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ describe('generators', () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
describe.only('extra tests', () => {
|
describe('extra tests', () => {
|
||||||
test('empty config doesnt generate a tag', () => {
|
test('empty config doesnt generate a tag', () => {
|
||||||
const { meta } = generateServerInjector({ meta: [] })
|
const { meta } = generateServerInjector({ meta: [] })
|
||||||
|
|
||||||
|
|||||||
@@ -263,4 +263,24 @@ describe('plugin', () => {
|
|||||||
jest.advanceTimersByTime(10)
|
jest.advanceTimersByTime(10)
|
||||||
expect(refreshSpy).toHaveBeenCalled()
|
expect(refreshSpy).toHaveBeenCalled()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('can set option waitOnDestroyed runtime', () => {
|
||||||
|
const wrapper = mount({ render: h => h('div') }, { localVue: Vue })
|
||||||
|
|
||||||
|
expect(wrapper.vm.$meta().getOptions().waitOnDestroyed).toBe(true)
|
||||||
|
|
||||||
|
wrapper.vm.$meta().setOptions({ waitOnDestroyed: false })
|
||||||
|
|
||||||
|
expect(wrapper.vm.$meta().getOptions().waitOnDestroyed).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('can set option debounceWait runtime', () => {
|
||||||
|
const wrapper = mount({ render: h => h('div') }, { localVue: Vue })
|
||||||
|
|
||||||
|
expect(wrapper.vm.$meta().getOptions().debounceWait).toBe(10)
|
||||||
|
|
||||||
|
wrapper.vm.$meta().setOptions({ debounceWait: 69420 })
|
||||||
|
|
||||||
|
expect(wrapper.vm.$meta().getOptions().debounceWait).toBe(69420)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user