mirror of
https://gitee.com/vuejs/vue.git
synced 2024-12-05 05:27:59 +08:00
avoid duplicate lifecycle hooks during constructor resolution
This commit is contained in:
parent
673acecc34
commit
7fa8fa76fe
@ -86,7 +86,7 @@ function initInternalComponent (vm: Component, options: InternalComponentOptions
|
||||
export function resolveConstructorOptions (Ctor: Class<Component>) {
|
||||
let options = Ctor.options
|
||||
if (Ctor.super) {
|
||||
const superOptions = Ctor.super.options
|
||||
const superOptions = resolveConstructorOptions(Ctor.super)
|
||||
const cachedSuperOptions = Ctor.superOptions
|
||||
if (superOptions !== cachedSuperOptions) {
|
||||
// super option changed,
|
||||
@ -108,14 +108,31 @@ export function resolveConstructorOptions (Ctor: Class<Component>) {
|
||||
}
|
||||
|
||||
function resolveModifiedOptions (Ctor: Class<Component>): ?Object {
|
||||
let res
|
||||
const options = Ctor.options
|
||||
let modified
|
||||
const latest = Ctor.options
|
||||
const sealed = Ctor.sealedOptions
|
||||
for (const key in options) {
|
||||
if (sealed[key] !== options[key]) {
|
||||
if (!res) res = {}
|
||||
res[key] = options[key]
|
||||
for (const key in latest) {
|
||||
if (latest[key] !== sealed[key]) {
|
||||
if (!modified) modified = {}
|
||||
modified[key] = dedupe(latest[key], sealed[key])
|
||||
}
|
||||
}
|
||||
return res
|
||||
return modified
|
||||
}
|
||||
|
||||
function dedupe (latest, sealed) {
|
||||
// compare latest and sealed to ensure lifecycle hooks won't be duplicated
|
||||
// between merges
|
||||
if (Array.isArray(latest)) {
|
||||
const res = []
|
||||
sealed = Array.isArray(sealed) ? sealed : [sealed]
|
||||
for (let i = 0; i < latest.length; i++) {
|
||||
if (sealed.indexOf(latest[i]) < 0) {
|
||||
res.push(latest[i])
|
||||
}
|
||||
}
|
||||
return res
|
||||
} else {
|
||||
return latest
|
||||
}
|
||||
}
|
||||
|
@ -87,7 +87,12 @@ describe('Global API: mixin', () => {
|
||||
|
||||
// #4976
|
||||
it('should not drop late-attached custom options on existing constructors', () => {
|
||||
const Test = Vue.extend({})
|
||||
const baseSpy = jasmine.createSpy('base')
|
||||
const Base = Vue.extend({
|
||||
beforeCreate: baseSpy
|
||||
})
|
||||
|
||||
const Test = Base.extend({})
|
||||
|
||||
// Inject options later
|
||||
// vue-loader and vue-hot-reload-api are doing like this
|
||||
@ -95,23 +100,28 @@ describe('Global API: mixin', () => {
|
||||
$style: () => 123
|
||||
}
|
||||
|
||||
const spy = jasmine.createSpy('mixin')
|
||||
Test.options.beforeCreate = [spy]
|
||||
const spy = jasmine.createSpy('late attached')
|
||||
Test.options.beforeCreate = Test.options.beforeCreate.concat(spy)
|
||||
|
||||
// Update super constructor's options
|
||||
Vue.mixin({})
|
||||
const mixinSpy = jasmine.createSpy('mixin')
|
||||
Vue.mixin({
|
||||
beforeCreate: mixinSpy
|
||||
})
|
||||
|
||||
// mount the component
|
||||
const vm = new Test({
|
||||
template: '<div>{{ $style }}</div>'
|
||||
}).$mount()
|
||||
|
||||
expect(spy).toHaveBeenCalled()
|
||||
expect(spy.calls.count()).toBe(1)
|
||||
expect(baseSpy.calls.count()).toBe(1)
|
||||
expect(mixinSpy.calls.count()).toBe(1)
|
||||
expect(vm.$el.textContent).toBe('123')
|
||||
expect(vm.$style).toBe(123)
|
||||
|
||||
// Should not be dropped
|
||||
expect(Test.options.computed.$style()).toBe(123)
|
||||
expect(Test.options.beforeCreate).toEqual([spy])
|
||||
expect(Test.options.beforeCreate).toEqual([mixinSpy, baseSpy, spy])
|
||||
})
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user