Browse Source

fix(v-on): add removing all dom event listeners when vnode destroyed (#10085)

dev
zrh122 3 years ago
committed by GitHub
parent
commit
3d29ba863b
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      src/platforms/web/runtime/modules/events.js
  2. 32
      test/unit/features/component/component-keep-alive.spec.js

8
src/platforms/web/runtime/modules/events.js

@ -5,6 +5,7 @@ import { updateListeners } from 'core/vdom/helpers/index'
import { isIE, isFF, supportsPassive, isUsingMicroTask } from 'core/util/index' import { isIE, isFF, supportsPassive, isUsingMicroTask } from 'core/util/index'
import { RANGE_TOKEN, CHECKBOX_RADIO_TOKEN } from 'web/compiler/directives/model' import { RANGE_TOKEN, CHECKBOX_RADIO_TOKEN } from 'web/compiler/directives/model'
import { currentFlushTimestamp } from 'core/observer/scheduler' import { currentFlushTimestamp } from 'core/observer/scheduler'
import { emptyNode } from 'core/vdom/patch'
// normalize v-model event tokens that can only be determined at runtime. // normalize v-model event tokens that can only be determined at runtime.
// it's important to place the event as the first in the array because // it's important to place the event as the first in the array because
@ -108,7 +109,9 @@ function updateDOMListeners (oldVnode: VNodeWithData, vnode: VNodeWithData) {
} }
const on = vnode.data.on || {} const on = vnode.data.on || {}
const oldOn = oldVnode.data.on || {} const oldOn = oldVnode.data.on || {}
target = vnode.elm // vnode is empty when removing all listeners,
// and use old vnode dom element
target = vnode.elm || oldVnode.elm
normalizeEvents(on) normalizeEvents(on)
updateListeners(on, oldOn, add, remove, createOnceHandler, vnode.context) updateListeners(on, oldOn, add, remove, createOnceHandler, vnode.context)
target = undefined target = undefined
@ -116,5 +119,6 @@ function updateDOMListeners (oldVnode: VNodeWithData, vnode: VNodeWithData) {
export default { export default {
create: updateDOMListeners, create: updateDOMListeners,
update: updateDOMListeners update: updateDOMListeners,
destroy: (vnode: VNodeWithData) => updateDOMListeners(vnode, emptyNode)
} }

32
test/unit/features/component/component-keep-alive.spec.js

@ -1249,5 +1249,37 @@ describe('Component keep-alive', () => {
}).then(done) }).then(done)
} }
}) })
// #10083
it('should not attach event handler repeatedly', done => {
const vm = new Vue({
template: `
<keep-alive>
<btn v-if="showBtn" @click.native="add" />
</keep-alive>
`,
data: { showBtn: true, n: 0 },
methods: {
add () {
this.n++
}
},
components: {
btn: { template: '<button>add 1</button>' }
}
}).$mount()
const btn = vm.$el
expect(vm.n).toBe(0)
btn.click()
expect(vm.n).toBe(1)
vm.showBtn = false
waitForUpdate(() => {
vm.showBtn = true
}).then(() => {
btn.click()
expect(vm.n).toBe(2)
}).then(done)
})
} }
}) })

Loading…
Cancel
Save