Vuetify独立v-navigation-drawer仅点击遮罩关闭的实现优化咨询
导航抽屉点击遮罩关闭的优化方案
现有实现的问题根源
你现在需要手动监听外部点击、靠类名判断触发关闭的核心原因,是给v-navigation-drawer加了stateless属性:
- 这个属性会让组件变成完全剥离内置交互的纯展示组件,直接把原本内置的「点击遮罩层自动关闭」逻辑全部移除了
- 现在靠
e.target.className === "v-overlay__scrim"做相等判断的写法有明显隐患:一旦Vuetify版本迭代修改遮罩层类名、或者遮罩层上绑定了其他附加类名,这个相等判断就会直接失效;如果页面上刚好有其他元素带了同名类,还会出现误触发
推荐的最优实现(完全适配你现有的父子组件状态管控模式)
直接去掉冗余的stateless属性和自定义v-click-outside逻辑,通过计算属性适配单向数据流规则,复用组件内置的遮罩交互能力,不需要自己写任何类名判断:
- 调整模板配置,删掉多余的自定义指令和stateless属性
<v-navigation-drawer v-model="drawerState" temporary fixed :width="width" :height="height" right ></v-navigation-drawer> - 在组件脚本中新增带读写逻辑的计算属性,满足「子组件不直接修改prop、通过emit通知父组件更新状态」的要求
computed: { drawerState: { // 读取父组件传入的抽屉显隐状态 get() { return this.isDrawerShowing }, // 抽屉状态变更时,直接通知父组件更新,不直接操作prop set(newVal) { this.$emit('update:isDrawerShowing', newVal) // 兼容你现有自定义事件的写法,也可以直接触发之前的hide-drawer事件 // this.$emit('hide-drawer', newVal) } } }
这种实现的优势:
- 完全复用Vuetify内置的遮罩点击判断逻辑,不存在类名兼容问题
- 天然规避误触发:temporary模式下的遮罩层会铺满整个视口、叠加在所有页面内容之上,内置逻辑只会响应遮罩层本身的点击,父组件上其他元素的点击根本不会触发关闭
- 严格遵循你现有的状态管控流程,所有状态更新都由父组件统一处理,不会破坏单向数据流规则
如果业务必须保留stateless属性的备选方案
如果你的场景确实需要完全自定义抽屉的交互、必须保留stateless属性,也不需要手写v-click-outside和类名判断,直接用组件内置的@click:scrim事件就行:
<v-navigation-drawer v-model="isDrawerShowing" temporary fixed :width="width" :height="height" right stateless @click:scrim="handleScrimClick" ></v-navigation-drawer>
对应的事件处理逻辑:
handleScrimClick() { this.$emit('hide-drawer', false) }
这个方案比你现在的手写点击监听更可靠:@click:scrim是组件内部直接绑定在遮罩层DOM上的事件,只有真正点击遮罩层时才会触发,既不会受类名变更影响,也不会因为父组件其他元素的点击产生误触发,代码量还比现有实现少一半。
内容的提问来源于stack exchange,提问作者D'Mar
相关产品推荐
相关产品推荐

