AngularJS 1.6/TS项目中MD菜单与Select点击外部无法同时关闭的需求
解决AngularJS Material菜单与内部Select组件的同步关闭问题
这个问题我之前在项目里也碰到过,核心原因确实是你说的——AngularJS Material菜单的md-backdrop元素默认z-index比select组件的更高,导致点击外部区域时,只有菜单的backdrop能捕获到点击事件触发关闭,而select的backdrop被完全遮挡,无法响应点击。下面给你两个实用的解决方案:
方案一:层级调整+双向状态同步
先通过CSS提升select相关元素的层级,确保它们能优先捕获外部点击;再通过组件事件回调实现双向同步关闭。
自定义CSS
/* 让select的下拉面板和backdrop层级高于菜单 */ md-menu-content .md-select-menu-container { z-index: 10000 !important; } md-menu-content .md-select-menu-container + .md-backdrop { z-index: 9999 !important; }
HTML结构
<md-menu md-on-close="ctrl.closeSelect()"> <md-button aria-label="Open interactions menu" class="md-icon-button" ng-click="$mdMenu.open();"> qq </md-button> <md-menu-content width="4"> <md-menu-item> <md-button> yy </md-button> </md-menu-item> <md-menu-item> <md-button> zz </md-button> </md-menu-item> <md-menu-divider></md-menu-divider> <md-menu-item> <md-button> xx </md-button> </md-menu-item> <md-input-container> <label>Status</label> <md-select ng-model="ctrl.userState" md-select-id="status-select" ng-blur="ctrl.closeMenu()"> <md-option><em>None</em></md-option> <md-option> Something </md-option> <md-option> Something </md-option> <md-option> Something </md-option> <md-option> Something </md-option> </md-select> </md-input-container> </md-menu-content> </md-menu>
TypeScript控制器
class MenuSelectController { userState: string; constructor(private $mdMenu: angular.material.IMenuService) {} // 菜单关闭时,同步关闭打开的select closeSelect() { const selectElement = angular.element(document.getElementById('status-select')); const selectCtrl = selectElement.controller('mdSelect'); if (selectCtrl && selectCtrl.isOpen()) { selectCtrl.close(); } } // select失去焦点关闭时,同步关闭菜单 closeMenu() { this.$mdMenu.close(); } } angular.module('myApp', ['ngMaterial']) .controller('MenuSelectController', MenuSelectController);
方案二:全局点击监听(无需修改样式)
如果不想改动组件默认样式,可以通过监听全局点击事件,判断点击区域是否在菜单和select之外,同时关闭两者:
TypeScript控制器
class MenuSelectController { userState: string; private menuOpen = false; private selectOpen = false; constructor( private $mdMenu: angular.material.IMenuService, private $document: angular.IDocumentService, private $scope: angular.IScope ) { // 监听菜单的打开/关闭状态 this.$scope.$on('mdMenuOpen', () => this.menuOpen = true); this.$scope.$on('mdMenuClose', () => this.menuOpen = false); // 监听select的打开/关闭状态 this.$scope.$on('mdSelectOpen', () => this.selectOpen = true); this.$scope.$on('mdSelectClose', () => this.selectOpen = false); // 绑定全局点击监听 this.$document.on('click', (event) => { const target = angular.element(event.target); // 判断点击区域是否不在菜单和select范围内 const isOutsideMenu = !target.closest('md-menu').length; const isOutsideSelect = !target.closest('md-select-menu-container').length; if (this.menuOpen && this.selectOpen && isOutsideMenu && isOutsideSelect) { this.$mdMenu.close(); const selectCtrl = angular.element(document.getElementById('status-select')).controller('mdSelect'); selectCtrl?.close(); // 手动触发digest更新视图 this.$scope.$apply(); } }); // 控制器销毁时移除全局监听,避免内存泄漏 this.$scope.$on('$destroy', () => { this.$document.off('click'); }); } }
两种方案都能实现你想要的效果:点击外部区域时,菜单和select容器同时关闭。你可以根据项目的样式规范和代码习惯选择合适的方案。
内容的提问来源于stack exchange,提问作者Peter Boomsma
相关产品推荐
相关产品推荐

