mirror of
https://github.com/tenrok/vue-meta.git
synced 2026-06-23 23:10:34 +03:00
feat: add options debounceWait
This commit is contained in:
@@ -3,7 +3,7 @@ import { rootConfigKey } from '../shared/constants'
|
|||||||
// store an id to keep track of DOM updates
|
// store an id to keep track of DOM updates
|
||||||
let batchId = null
|
let batchId = null
|
||||||
|
|
||||||
export function triggerUpdate (rootVm, hookName) {
|
export function triggerUpdate ({ debounceWait }, rootVm, hookName) {
|
||||||
// if an update was triggered during initialization or when an update was triggered by the
|
// if an update was triggered during initialization or when an update was triggered by the
|
||||||
// metaInfo watcher, set initialized to null
|
// metaInfo watcher, set initialized to null
|
||||||
// then we keep falsy value but know we need to run a triggerUpdate after initialization
|
// then we keep falsy value but know we need to run a triggerUpdate after initialization
|
||||||
@@ -13,7 +13,7 @@ export function triggerUpdate (rootVm, hookName) {
|
|||||||
|
|
||||||
if (rootVm[rootConfigKey].initialized && !rootVm[rootConfigKey].pausing) {
|
if (rootVm[rootConfigKey].initialized && !rootVm[rootConfigKey].pausing) {
|
||||||
// batch potential DOM updates to prevent extraneous re-rendering
|
// batch potential DOM updates to prevent extraneous re-rendering
|
||||||
batchUpdate(() => rootVm.$meta().refresh())
|
batchUpdate(() => void rootVm.$meta().refresh(), debounceWait)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,10 +25,14 @@ export function triggerUpdate (rootVm, hookName) {
|
|||||||
* @return {Number} id - a new ID
|
* @return {Number} id - a new ID
|
||||||
*/
|
*/
|
||||||
export function batchUpdate (callback, timeout) {
|
export function batchUpdate (callback, timeout) {
|
||||||
timeout = timeout || 10
|
timeout = timeout === undefined ? 10 : timeout
|
||||||
|
|
||||||
|
if (!timeout) {
|
||||||
|
callback()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
clearTimeout(batchId)
|
clearTimeout(batchId)
|
||||||
|
|
||||||
batchId = setTimeout(() => {
|
batchId = setTimeout(() => {
|
||||||
callback()
|
callback()
|
||||||
}, timeout)
|
}, timeout)
|
||||||
|
|||||||
@@ -23,6 +23,14 @@ export default function $meta (options) {
|
|||||||
options.refreshOnceOnNavigation = newOptions[refreshNavKey]
|
options.refreshOnceOnNavigation = newOptions[refreshNavKey]
|
||||||
addNavGuards($root)
|
addNavGuards($root)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const debounceWaitKey = 'debounceWait'
|
||||||
|
if (newOptions && newOptions[debounceWaitKey]) {
|
||||||
|
const debounceWait = parseInt(newOptions[debounceWaitKey])
|
||||||
|
if (!isNaN(debounceWait)) {
|
||||||
|
options.debounceWait = debounceWait
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
'refresh': () => refresh($root, options),
|
'refresh': () => refresh($root, options),
|
||||||
'inject': () => process.server ? inject($root, options) : showWarningNotSupportedInBrowserBundle('inject'),
|
'inject': () => process.server ? inject($root, options) : showWarningNotSupportedInBrowserBundle('inject'),
|
||||||
|
|||||||
@@ -49,6 +49,9 @@ export const contentKeyName = 'content'
|
|||||||
// The id used for the ssr app
|
// The id used for the ssr app
|
||||||
export const ssrAppId = 'ssr'
|
export const ssrAppId = 'ssr'
|
||||||
|
|
||||||
|
// How long meta update
|
||||||
|
export const debounceWait = 10
|
||||||
|
|
||||||
export const defaultOptions = {
|
export const defaultOptions = {
|
||||||
keyName,
|
keyName,
|
||||||
attribute,
|
attribute,
|
||||||
@@ -56,6 +59,7 @@ export const defaultOptions = {
|
|||||||
tagIDKeyName,
|
tagIDKeyName,
|
||||||
contentKeyName,
|
contentKeyName,
|
||||||
metaTemplateKeyName,
|
metaTemplateKeyName,
|
||||||
|
debounceWait,
|
||||||
ssrAppId
|
ssrAppId
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-5
@@ -69,7 +69,7 @@ export default function createMixin (Vue, options) {
|
|||||||
// credit for this suggestion goes to [Sébastien Chopin](https://github.com/Atinux)
|
// credit for this suggestion goes to [Sébastien Chopin](https://github.com/Atinux)
|
||||||
ensuredPush($options, 'created', function () {
|
ensuredPush($options, 'created', function () {
|
||||||
this.$watch('$metaInfo', function () {
|
this.$watch('$metaInfo', function () {
|
||||||
triggerUpdate(this[rootKey], 'watcher')
|
triggerUpdate(options, this[rootKey], 'watcher')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -112,7 +112,7 @@ export default function createMixin (Vue, options) {
|
|||||||
// current hook was called
|
// current hook was called
|
||||||
// (during initialization all changes are blocked)
|
// (during initialization all changes are blocked)
|
||||||
if (tags === false && $root[rootConfigKey].initialized === null) {
|
if (tags === false && $root[rootConfigKey].initialized === null) {
|
||||||
this.$nextTick(() => triggerUpdate($root, 'init'))
|
this.$nextTick(() => triggerUpdate(options, $root, 'init'))
|
||||||
}
|
}
|
||||||
|
|
||||||
$root[rootConfigKey].initialized = true
|
$root[rootConfigKey].initialized = true
|
||||||
@@ -126,7 +126,6 @@ export default function createMixin (Vue, options) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// add the navigation guards if requested
|
// add the navigation guards if requested
|
||||||
if (options.refreshOnceOnNavigation) {
|
if (options.refreshOnceOnNavigation) {
|
||||||
addNavGuards($root)
|
addNavGuards($root)
|
||||||
@@ -142,7 +141,7 @@ export default function createMixin (Vue, options) {
|
|||||||
// no need to add this hooks on server side
|
// no need to add this hooks on server side
|
||||||
updateOnLifecycleHook.forEach((lifecycleHook) => {
|
updateOnLifecycleHook.forEach((lifecycleHook) => {
|
||||||
ensuredPush($options, lifecycleHook, function () {
|
ensuredPush($options, lifecycleHook, function () {
|
||||||
triggerUpdate(this[rootKey], lifecycleHook)
|
triggerUpdate(options, this[rootKey], lifecycleHook)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@@ -165,7 +164,7 @@ export default function createMixin (Vue, options) {
|
|||||||
|
|
||||||
clearInterval(interval)
|
clearInterval(interval)
|
||||||
|
|
||||||
triggerUpdate($this.$root, 'destroyed')
|
triggerUpdate(options, $this.$root, 'destroyed')
|
||||||
}, 50)
|
}, 50)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ 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,
|
||||||
ssrAppId: options['ssrAppId'] || defaultOptions.ssrAppId,
|
ssrAppId: options['ssrAppId'] || defaultOptions.ssrAppId,
|
||||||
refreshOnceOnNavigation: !!options['refreshOnceOnNavigation']
|
refreshOnceOnNavigation: !!options['refreshOnceOnNavigation']
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -479,7 +479,7 @@ describe('components', () => {
|
|||||||
wrapper.destroy()
|
wrapper.destroy()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('can toggle refreshOnceOnNavigation runtime', () => {
|
test('can enable option refreshOnceOnNavigation runtime', () => {
|
||||||
const guards = {}
|
const guards = {}
|
||||||
const wrapper = mount(HelloWorld, {
|
const wrapper = mount(HelloWorld, {
|
||||||
localVue: Vue,
|
localVue: Vue,
|
||||||
@@ -503,4 +503,14 @@ describe('components', () => {
|
|||||||
expect(guards.before).not.toBeUndefined()
|
expect(guards.before).not.toBeUndefined()
|
||||||
expect(guards.after).not.toBeUndefined()
|
expect(guards.after).not.toBeUndefined()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('can set option debounceWait runtime', () => {
|
||||||
|
const wrapper = mount(HelloWorld, { localVue: Vue })
|
||||||
|
|
||||||
|
expect(wrapper.vm.$meta().getOptions().debounceWait).toBe(10)
|
||||||
|
|
||||||
|
wrapper.vm.$meta().setOptions({ debounceWait: 69420 })
|
||||||
|
|
||||||
|
expect(wrapper.vm.$meta().getOptions().debounceWait).toBe(69420)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ describe('plugin', () => {
|
|||||||
const batchUpdateSpy = batchUpdate.mockImplementation(_batchUpdate)
|
const batchUpdateSpy = batchUpdate.mockImplementation(_batchUpdate)
|
||||||
// because triggerUpdate & batchUpdate reside in the same file we cant mock them both,
|
// because triggerUpdate & batchUpdate reside in the same file we cant mock them both,
|
||||||
// so just recreate the triggerUpdate fn by copying its implementation
|
// so just recreate the triggerUpdate fn by copying its implementation
|
||||||
const triggerUpdateSpy = triggerUpdate.mockImplementation((vm, hookName) => {
|
const triggerUpdateSpy = triggerUpdate.mockImplementation((options, vm, hookName) => {
|
||||||
if (vm.$root._vueMeta.initialized && !vm.$root._vueMeta.pausing) {
|
if (vm.$root._vueMeta.initialized && !vm.$root._vueMeta.pausing) {
|
||||||
// batch potential DOM updates to prevent extraneous re-rendering
|
// batch potential DOM updates to prevent extraneous re-rendering
|
||||||
batchUpdateSpy(() => vm.$meta().refresh())
|
batchUpdateSpy(() => vm.$meta().refresh())
|
||||||
@@ -216,7 +216,7 @@ describe('plugin', () => {
|
|||||||
expect(metaInfo.title).toBe(title)
|
expect(metaInfo.title).toBe(title)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('updates are batched', async () => {
|
test('updates are batched by default', async () => {
|
||||||
jest.useFakeTimers()
|
jest.useFakeTimers()
|
||||||
|
|
||||||
const { batchUpdate: _batchUpdate } = jest.requireActual('../../src/client/update')
|
const { batchUpdate: _batchUpdate } = jest.requireActual('../../src/client/update')
|
||||||
@@ -224,7 +224,7 @@ describe('plugin', () => {
|
|||||||
const refreshSpy = jest.fn()
|
const refreshSpy = jest.fn()
|
||||||
// because triggerUpdate & batchUpdate reside in the same file we cant mock them both,
|
// because triggerUpdate & batchUpdate reside in the same file we cant mock them both,
|
||||||
// so just recreate the triggerUpdate fn by copying its implementation
|
// so just recreate the triggerUpdate fn by copying its implementation
|
||||||
triggerUpdate.mockImplementation((vm, hookName) => {
|
triggerUpdate.mockImplementation((options, vm, hookName) => {
|
||||||
if (vm.$root._vueMeta.initialized && !vm.$root._vueMeta.pausing) {
|
if (vm.$root._vueMeta.initialized && !vm.$root._vueMeta.pausing) {
|
||||||
// batch potential DOM updates to prevent extraneous re-rendering
|
// batch potential DOM updates to prevent extraneous re-rendering
|
||||||
batchUpdateSpy(refreshSpy)
|
batchUpdateSpy(refreshSpy)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { setOptions } from '../../src/shared/options'
|
import { setOptions } from '../../src/shared/options'
|
||||||
import { defaultOptions } from '../../src/shared/constants'
|
import { defaultOptions } from '../../src/shared/constants'
|
||||||
|
import { triggerUpdate } from '../../src/client/update'
|
||||||
|
|
||||||
describe('shared', () => {
|
describe('shared', () => {
|
||||||
test('can use setOptions', () => {
|
test('can use setOptions', () => {
|
||||||
@@ -11,4 +12,33 @@ describe('shared', () => {
|
|||||||
expect(options.contentKeyName).toBeDefined()
|
expect(options.contentKeyName).toBeDefined()
|
||||||
expect(options.contentKeyName).toBe(defaultOptions.contentKeyName)
|
expect(options.contentKeyName).toBe(defaultOptions.contentKeyName)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('options.debounceWait is used', () => {
|
||||||
|
jest.useFakeTimers()
|
||||||
|
|
||||||
|
const refresh = jest.fn()
|
||||||
|
const componentMock = {
|
||||||
|
_vueMeta: {
|
||||||
|
initialized: true,
|
||||||
|
pausing: false
|
||||||
|
},
|
||||||
|
$meta: () => ({ refresh })
|
||||||
|
}
|
||||||
|
|
||||||
|
triggerUpdate({ debounceWait: 0 }, componentMock, 'test')
|
||||||
|
|
||||||
|
expect(refresh).toHaveBeenCalledTimes(1)
|
||||||
|
|
||||||
|
triggerUpdate({}, componentMock, 'test')
|
||||||
|
expect(refresh).toHaveBeenCalledTimes(1)
|
||||||
|
jest.advanceTimersByTime(11)
|
||||||
|
expect(refresh).toHaveBeenCalledTimes(2)
|
||||||
|
|
||||||
|
triggerUpdate({ debounceWait: 69420 }, componentMock, 'test')
|
||||||
|
expect(refresh).toHaveBeenCalledTimes(2)
|
||||||
|
jest.advanceTimersByTime(11)
|
||||||
|
expect(refresh).toHaveBeenCalledTimes(2)
|
||||||
|
jest.advanceTimersByTime(69500)
|
||||||
|
expect(refresh).toHaveBeenCalledTimes(3)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user