场景:在实际开发中,遇到了这样一种场景,vue3页面,两个相同组件,在满足某条件下 v-if 展示第一个组件,满足另一个条件下, v-if 隐藏第一个组件,同时展示第二个组件,比如反馈组件,会通过 window.addEventListener 来监听自定义的反馈弹窗展示和隐藏事件。
结果:两个相同组件一个卸载,一个挂载,第一个组监听的反馈弹窗展示和隐藏事件都可以生效,后展示的组件事件监听都不生效.....
示例如下:
代码语言:javascript复制<script lang="ts" setup>
import { onBeforeUnmount } from 'vue'
window.addEventListener('feedbackShow', () => {
console.log('反馈弹窗出现')
})
window.addEventListener('feedbackHide', () => {
console.log('反馈弹窗消失')
})
onBeforeUnmount(() => {
window.removeEventListener('feedbackShow')
window.removeEventListener('feedbackHide')
})
</script>
分析:
通过打印日志,跟踪组件的挂载、卸载时机,发现 同时卸载的组件,onBeforeUnmount 的执行时机会晚于 同时挂载组件 的 setup 时机,从而导致第二次挂载的组件的新监听的事件被第一次组件的事件卸载一次性remove 了,所以导致后一个组件的事件监听不生效。
解决:
同时卸载和挂载两个相同的组件,关于执行时机,遇到了两种场景:
代码语言:javascript复制<script lang="ts" setup>
import { onBeforeMount, onMounted, onBeforeUnmount,onUnmounted } from 'vue'
console.log('反馈setup', props.name)
onBeforeMount(() => {
console.log('反馈onBeforeMount', props.name)
})
onMounted(() => {
console.log('反馈onBeforeMount', props.name)
})
onBeforeUnmount(() => {
console.log('反馈onBeforeUnmount', props.name)
})
onUnmounted(() => {
console.log('反馈onUnmounted', props.name)
})
</script>
卸载的挂件,onBeforeMount 既有在挂载组件的 setup 之前的情况,也有之后的情况,卸载组件的 onUnmounted 既有在挂载组件的 onMounted 之前,也有可能在挂载组件的 onMounted 之后,总而言之,onBeforeMount 和 onUnmounted 都一定在新挂载组件 setup 之后,所以当遇到挂件监听和卸载事件的情况时,事件监听一定要写在 onMounted 钩子里即可保证不被 remove。
最终:
代码语言:javascript复制<script lang="ts" setup>
import { onMounted, onBeforeUnmount } from 'vue'
onMounted(()) => {
window.addEventListener('feedbackShow', () => {
console.log('反馈弹窗出现')
})
window.addEventListener('feedbackHide', () => {
console.log('反馈弹窗消失')
})
})
onBeforeUnmount(() => {
window.removeEventListener('feedbackShow')
window.removeEventListener('feedbackHide')
})
</script>