如何实现uib-datepicker仅在点击组件外部区域时关闭
AngularJS uib-datepicker多日期选择器点击外部关闭实现
问题现状
使用uib-datepicker实现多日期选择功能,期望组件仅在点击外部区域时关闭,初始实现代码如下:
<div class="date-multi-select" uib-dropdown is-open="$ctrl.isOpen"> <div class="input-group"> <input type="text" class="form-control" placeholder="{{ $ctrl.placeholder }}" ng-model="$ctrl.value" ng-required="$ctrl.required" ng-disabled="$ctrl.disabled" ng-click="$ctrl.isOpen = true" ng-blur="$ctrl.toggleOpen($event)" ng-readonly="true"> <div class="input-group-btn addon-button"> <button type="button" class="btn btn-default" ng-click="$ctrl.toggleOpen($event)"> <i class="far fa-calendar-alt"></i> </button> </div> </div> <div class="dropdown-menu" uib-dropdown-menu> <div uib-datepicker ng-model="$ctrl.dt" datepicker-options="$ctrl.dateOptions" multi-select="$ctrl.dates" template-url="datepicker-multi-select.html" ng-change="$ctrl.onDateChange()"> </div> </div> </div>
初始控制器逻辑:
self.toggleOpen = function (event) { if (event.relatedTarget.classList[0] === "btn") { self.isOpen = true; } else { self.isOpen = !self.isOpen; } };
存在两个异常:
- 点击日期选择器内部区域时组件直接关闭,无法完成多日期选择操作
- 尝试在父级div标签添加
auto-close="disabled"或auto-close="outsideClick"属性配置时,会出现日期选择器完全无法关闭的问题
解决方案
1. 调整HTML配置
核心改动是启用官方外部点击关闭规则,移除冲突的失焦事件绑定,修改后代码如下:
<div class="date-multi-select" uib-dropdown is-open="$ctrl.isOpen" auto-close="outsideClick"> <div class="input-group"> <input type="text" class="form-control" placeholder="{{ $ctrl.placeholder }}" ng-model="$ctrl.value" ng-required="$ctrl.required" ng-disabled="$ctrl.disabled" ng-click="$ctrl.isOpen = true" ng-readonly="true"> <div class="input-group-btn addon-button"> <button type="button" class="btn btn-default" ng-click="$ctrl.toggleOpen()"> <i class="far fa-calendar-alt"></i> </button> </div> </div> <div class="dropdown-menu" uib-dropdown-menu> <div uib-datepicker ng-model="$ctrl.dt" datepicker-options="$ctrl.dateOptions" multi-select="$ctrl.dates" template-url="datepicker-multi-select.html" ng-change="$ctrl.onDateChange()"> </div> </div> </div>
改动点说明:
- 给uib-dropdown根节点添加
auto-close="outsideClick"属性,启用组件原生的外部点击关闭逻辑,组件会自动判定点击源是否属于下拉框内部,决定是否关闭 - 移除input元素上的
ng-blur="$ctrl.toggleOpen($event)"绑定:该事件会在点击日期面板、焦点从输入框转移到面板元素时错误触发,是导致内部点击关闭的核心原因 - 移除按钮点击事件传递的$event参数,不需要依赖事件对象做兼容性差的类名判断
2. 简化控制器开关逻辑
替换原有依赖事件对象的判断逻辑,简化为纯状态切换:
self.toggleOpen = function () { self.isOpen = !self.isOpen; };
3. 特殊兼容处理(若上述配置后仍有内部点击关闭问题)
如果自定义的日期选择器模板存在事件冒泡拦截,给下拉菜单容器添加mousedown事件阻止冒泡即可,确保组件能正确识别面板为内部元素:
<div class="dropdown-menu" uib-dropdown-menu ng-mousedown="$event.stopPropagation()"> <!-- 原有日期选择器代码 --> </div>
实现效果
- 点击输入框、日历图标按钮:正常唤起日期选择器
- 点击日期面板内部区域(选择多日期、切换年月等操作):选择器保持打开,不会意外关闭
- 点击选择器、输入框、图标按钮之外的页面任意区域:选择器自动关闭
内容的提问来源于stack exchange,提问作者Mattias Inokuchi
相关产品推荐
相关产品推荐

