AngularJS中Daterangepicker点击无法正常弹出问题求解
问题背景
开发栈为AngularJS、jQuery、Bootstrap,接入daterangepicker日期范围选择组件时出现异常:
- 点击组件绑定的输入框时,选择面板无法正常打开
- 只有切换页面后返回当前页、或代码中插入
alert阻塞执行、保持输入框焦点时,面板才能正常弹出
相关业务代码如下:
test.html
<div class="date-range-support-div"> <input type="text" name="daterange" value="" ng-click="glElmDb.openRangePicker()" id="daterange"/> </div>
test.js
// writing custom code for date range picker glElmDb.openRangePicker = function () { alert(''); $('input[name="daterange"]').daterangepicker({ opens: 'left' }, function (start, end, label) { console.log("A new date selection was made: " + start.format('YYYY-MM-DD') + ' to ' + end.format('YYYY-MM-DD')); }); }
异常表现参考:
- 无
alert时面板无法打开:
- 插入
alert后面板正常弹出:
、
问题根因
核心问题是组件初始化时机完全错误:
- daterangepicker本身的设计是:完成初始化后才会给目标输入框绑定点击、聚焦触发面板弹出的事件监听
- 现有代码把初始化逻辑写在了输入框的
ng-click回调里,第一次点击输入框时才会跑初始化代码,等初始化完成,这次点击的事件传播流程早就结束了,组件根本捕获不到这次点击,面板自然弹不出来 - 加
alert会阻塞JS主线程,关掉alert弹窗的时候输入框还持有焦点,相当于又触发了一次焦点/点击事件,这时候组件已经初始化完绑定好监听了,所以能弹出面板;切页面再返回的逻辑也一样,返回时输入框触发聚焦,组件如果已经初始化过,就会正常弹出。
可行解决方案
方案1:提前初始化组件(最推荐,符合组件设计逻辑)
不要把初始化放在点击事件里,等页面DOM渲染完直接初始化就行,组件自己会处理点击弹出的逻辑,不需要手动绑定点击事件。
AngularJS场景下别直接在控制器顶层拿DOM初始化,要等视图渲染完再操作,避免找不到元素:
- 先把输入框上多余的
ng-click删掉:
<div class="date-range-support-div"> <input type="text" name="daterange" value="" id="daterange"/> </div>
- 把初始化逻辑挪到视图渲染完成的钩子里:
// 监听AngularJS视图渲染完成事件,确保输入框DOM已经存在 $scope.$on('$viewContentLoaded', function() { $('input[name="daterange"]').daterangepicker({ opens: 'left' }, function (start, end, label) { console.log("A new date selection was made: " + start.format('YYYY-MM-DD') + ' to ' + end.format('YYYY-MM-DD')); }); });
方案2:必须点击时初始化的场景,手动调起面板
如果业务有特殊要求,非得点击时才初始化组件,那就在初始化跑完之后手动调用组件的show方法把面板拉起来,记得加判断避免每次点击都重复初始化:
glElmDb.openRangePicker = function () { const $targetInput = $('input[name="daterange"]'); // 已经初始化过就别重复绑定事件 if (!$targetInput.data('daterangepicker')) { $targetInput.daterangepicker({ opens: 'left' }, function (start, end, label) { console.log("A new date selection was made: " + start.format('YYYY-MM-DD') + ' to ' + end.format('YYYY-MM-DD')); }); } // 初始化完成后主动弹出面板 $targetInput.data('daterangepicker').show(); }
方案3:使用适配AngularJS的封装版本
如果项目里大部分逻辑都是AngularJS编写,不要直接硬套原生jQuery版的daterangepicker,可以使用适配了AngularJS生命周期的封装实现,不用自己手动操作DOM绑定事件,能避开很多生命周期冲突的坑。
内容的提问来源于stack exchange,提问作者Mohit Kumar Sharma
相关产品推荐
相关产品推荐

