实现效果:
1.点击按钮展开下拉列表
2.点击下拉列表中的选项进行选择,随后收起下拉列表
3.点击除下拉列表外的位置(包括按钮),收起下拉列表
效果图如下所示:
完整代码请查看:
https://github.com/wolf-wolf/pullDownList.git
实现环境
1.angular
2.sublime
#基本结构:
组件的基本HTML结构如下所示:
实现
方法一:
基本思路
在document上监听click事件,进而关闭打开的下拉列表
主要代码
Javascript代码
$scope.flag = {showList: false
};
$document.bind('click', function(event) {_closeList();$scope.$apply();
});
function _closeList() {$scope.flag.showList = false;
}
总结
上述方法实现简单,理解容易,但存在问题,如果在同一页面中存在多个组件可供点击,并且存在部分组件针对click事件使用event.stopPropagation()
或event.stopImmediatePropagation()
方法阻止事件冒泡,则点击事件无法到达document,进而无法达到自动关闭下拉列表的效果。
方法二
###基本思路
在列表打开时,在body
上添加遮罩层,并将其z-index
属性设置为最高,进而遮挡所有该页面的其他组件,同时监听发生在遮罩层上的点击事件,来达到自动关闭下拉列表的效果。
主要代码
####Javascript
$scope.toggleList = function(event) {if ($scope.flag.showList) { _closeList();} else { var _mask = document.createElement('div');_mask.className = 'drop-down-mask-' + _uniquePrefix;_mask.style.position = 'absolute';_mask.style.top = '0';_mask.style.left = '0';_mask.style.width = '100%';_mask.style.height = '100%';_mask.style.zIndex = '99998';_mask.style.background = 'rgba(255, 255, 255, 0)';_mask.addEventListener('click', function(event) {_closeList();$scope.$apply();});$document[0].body.append(_mask);$scope.flag.showList = true;}};
function _closeList() {$scope.flag.showList = false;var _mask = angular.element(document.getElementsByClassName('drop-down-mask-' + _uniquePrefix));if (_mask) {_mask.remove();}
}
HTML
<div class&#61;"main"><button class&#61;"open-btn" ng-click&#61;"toggleList($event)">选择列表1button><div class&#61;"list-wrapper" ng-show&#61;"flag.showList"><ul class&#61;"list"><li class&#61;"item" ng-repeat&#61;"item in list" ng-click&#61;"selectItem($event,item)"><span class&#61;"item-name" ng-bind&#61;"item.name">span>li>ul>div>
div>
总结
- 下拉列表打开后添加遮罩层
- 遮罩层插入到
body
下&#xff0c;body
的position
属性为relative
&#xff0c;遮罩层的position
属性为absolute
&#xff0c;以确保遮盖整个页面 - 在创建遮罩层时&#xff0c;需要判断是否已经存在遮罩&#xff0c;在这里&#xff0c;因为打开下拉列表表示遮罩层已经创建&#xff0c;所以判断下拉列表是否打开和判断遮罩层是否已经存在具有等同效果。如果未做判断&#xff0c;则会出现多次点击生成多个遮罩层的效果&#xff0c;从而在点击遮罩层时&#xff0c;需要多次点击才能保证其他组件的可用性
- 在关闭下拉列表的同时&#xff0c;一定要移除遮罩层的存在
缺陷&#xff1a;因为有遮罩层的存在所以在点击非下拉列表的位置时&#xff0c;点击事件发生在遮罩层上&#xff0c;如果想要在下拉列表打开的情况下&#xff0c;将焦点定位到其他组件&#xff0c;则需要二次点击。
TIP&#xff1a;
此方法是select2组件所采用的方式&#xff0c;可通过链接查看官网。
方法三
基本思路
为div
添加tabindex
属性&#xff0c;使其可以获得和失去焦点。监听blur
事件做到自动关闭下拉列表的效果
主要代码
Javascript
$scope.closeList &#61; function(event) {event.stopPropagation();_closeList();
}
$scope.toggleList &#61; function(event) {event.stopImmediatePropagation();if ($scope.flag.showList) {_closeList();} else {$scope.flag.showList &#61; true;}
};
function _closeList() {$scope.flag.showList &#61; false;
}
HTML
<div class&#61;"main" tabindex&#61;"-1" ng-blur&#61;"closeList($event)" ng-click&#61;"toggleList($event)"><h4 class&#61;"open-btn">选择列表2h4><div class&#61;"list-wrapper" ng-show&#61;"flag.showList"><ul class&#61;"list"><li class&#61;"item" ng-repeat&#61;"item in list" ng-click&#61;"selectItem($event,item)"><span class&#61;"item-name" ng-bind&#61;"item.name">span>li>ul>div>
div>
总结
- 在最外层包裹层&#xff0c;添加
tabindex
属性&#xff0c;这里将其值置为-1
&#xff0c;目的是保证在使用tab
键进行组件焦点切换时不会切换到本组件 - 监听
blur
事件而非click
事件 - 对按钮部分监听
click
事件&#xff0c;以实现点击按钮切换下拉列表打开状态的效果
TIP&#xff1a;
为什么不监听focus
事件&#xff1a;因为在获取焦点后&#xff0c;focus
事件步不再会被触发&#xff0c;则无法通过点击按钮来关闭下拉列表。同时focus
事件发生在click
事件之前&#xff0c;如果两个事件同时绑定打开下拉列表的处理函数&#xff0c;则会产生闪烁效果&#xff0c;具体情况&#xff0c;看官可自行尝试~~
tabindex
属性&#xff1a;请查看W3CSchool
如有错误请多多包涵&#xff0c;敬请反馈&#xff0c;期待一起进步~~~
再见&#xff0c;祝好~~&#xff01;