Vue2点击显示/失焦隐藏包裹组件:Close事件拦截问题求助
你的问题核心在于ToggleWrapper里给slot绑定@close是无效的——因为slot的内容是在父组件作用域渲染的,Input触发的close事件会冒泡到使用ToggleWrapper的那个父组件,根本传不到ToggleWrapper本身。另外Input里还有个小bug:$refs.text应该改成$refs.input,不然拿不到输入框的值。
下面给你两种解决方案,优先第一种,因为额外标记最少,还能保持组件解耦:
方案一:用作用域插槽传递关闭方法
这是Vue2里处理这类父子组件插槽事件的标准做法,只需要在使用时加少量标记。
1. 修改ToggleWrapper.vue
把关闭逻辑包装成方法,通过作用域插槽传给插槽里的组件:
<template> <div @click="open = true"> <div v-if="open"> <!-- 把关闭方法通过作用域插槽传出去 --> <slot :close="handleClose"></slot> </div> </div> </template> <script> export default { data() { return { open: false } }, methods: { handleClose() { this.open = false } } } </script>
2. 修正Input.vue的ref错误
把$refs.text改成$refs.input,确保能正确获取输入框值:
<template> <input ref="input" :value="value" @input="input" @blur="input" @keyup.escape="close" @keyup.enter="input" /> </template> <script> export default { props: ['value'], methods: { input() { this.$emit("input", this.$refs.input.value) this.close() }, close() { this.$emit("close") }, } } </script>
3. 最终使用方式
用v-slot接收ToggleWrapper传过来的close方法,绑定到Input的close事件上:
<ToggleWrapper> <template v-slot="{ close }"> <Input v-model="myText" @close="close" /> </template> </ToggleWrapper>
方案二:事件总线(不推荐)
如果不想修改使用方式,可以用事件总线,但会让组件耦合度变高,只适合小型项目:
- 先创建一个事件总线文件:
// bus.js import Vue from 'vue' export default new Vue()
- 修改Input.vue,触发总线事件:
<script> import bus from './bus.js' export default { // ...其他代码 methods: { close() { bus.$emit('toggle-close') } } } </script>
- 修改ToggleWrapper.vue,监听总线事件:
<script> import bus from './bus.js' export default { data() { return { open: false } }, mounted() { bus.$on('toggle-close', () => { this.open = false }) }, beforeDestroy() { bus.$off('toggle-close') } } </script>
另外你提到的"scoped events"不是Vue2的官方概念,应该是混淆了作用域插槽(scoped slots)——作用域插槽才是解决这类问题的正确思路,它能明确传递逻辑,组件之间解耦性更好。
内容的提问来源于stack exchange,提问作者Pierre de LESPINAY
相关产品推荐
相关产品推荐

