Skip to content

Commit 3d29ba8

Browse files
authored
fix(v-on): add removing all dom event listeners when vnode destroyed (#10085)
1 parent 509de2a commit 3d29ba8

File tree

2 files changed

+38
-2
lines changed

2 files changed

+38
-2
lines changed

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

+6-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { updateListeners } from 'core/vdom/helpers/index'
55
import { isIE, isFF, supportsPassive, isUsingMicroTask } from 'core/util/index'
66
import { RANGE_TOKEN, CHECKBOX_RADIO_TOKEN } from 'web/compiler/directives/model'
77
import { currentFlushTimestamp } from 'core/observer/scheduler'
8+
import { emptyNode } from 'core/vdom/patch'
89

910
// normalize v-model event tokens that can only be determined at runtime.
1011
// it's important to place the event as the first in the array because
@@ -108,13 +109,16 @@ function updateDOMListeners (oldVnode: VNodeWithData, vnode: VNodeWithData) {
108109
}
109110
const on = vnode.data.on || {}
110111
const oldOn = oldVnode.data.on || {}
111-
target = vnode.elm
112+
// vnode is empty when removing all listeners,
113+
// and use old vnode dom element
114+
target = vnode.elm || oldVnode.elm
112115
normalizeEvents(on)
113116
updateListeners(on, oldOn, add, remove, createOnceHandler, vnode.context)
114117
target = undefined
115118
}
116119

117120
export default {
118121
create: updateDOMListeners,
119-
update: updateDOMListeners
122+
update: updateDOMListeners,
123+
destroy: (vnode: VNodeWithData) => updateDOMListeners(vnode, emptyNode)
120124
}

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

+32
Original file line numberDiff line numberDiff line change
@@ -1249,5 +1249,37 @@ describe('Component keep-alive', () => {
12491249
}).then(done)
12501250
}
12511251
})
1252+
1253+
// #10083
1254+
it('should not attach event handler repeatedly', done => {
1255+
const vm = new Vue({
1256+
template: `
1257+
<keep-alive>
1258+
<btn v-if="showBtn" @click.native="add" />
1259+
</keep-alive>
1260+
`,
1261+
data: { showBtn: true, n: 0 },
1262+
methods: {
1263+
add () {
1264+
this.n++
1265+
}
1266+
},
1267+
components: {
1268+
btn: { template: '<button>add 1</button>' }
1269+
}
1270+
}).$mount()
1271+
1272+
const btn = vm.$el
1273+
expect(vm.n).toBe(0)
1274+
btn.click()
1275+
expect(vm.n).toBe(1)
1276+
vm.showBtn = false
1277+
waitForUpdate(() => {
1278+
vm.showBtn = true
1279+
}).then(() => {
1280+
btn.click()
1281+
expect(vm.n).toBe(2)
1282+
}).then(done)
1283+
})
12521284
}
12531285
})

0 commit comments

Comments
 (0)