Cle*_*ent 129 javascript rxjs drop-down-menu angular
当用户点击该下拉菜单之外的任何地方时,我想关闭我的登录菜单下拉菜单,我想用Angular2和Angular2"方法"来做...
我已经实施了一个解决方案,但我真的对它没有信心.我认为必须有一种最简单的方法来实现相同的结果,所以如果你有任何想法......让我们讨论:)!
这是我的实现:
这是我的下拉列表的组件:
这是代码
export class UserMenuComponent {
_isVisible: boolean = false;
_subscriptions: Subscription<any> = null;
constructor(public subjects: SubjectsService) {
}
onClick(event) {
event.stopPropagation();
}
set isVisible(v) {
if( v ){
setTimeout( () => {
this._subscriptions = this.subjects.userMenu.subscribe((e) => {
this.isVisible = false;
})
}, 0);
} else {
this._subscriptions.unsubscribe();
}
this._isVisible = v;
}
get isVisible() {
return this._isVisible;
}
}
Run Code Online (Sandbox Code Playgroud)
另一方面,有应用程序组件(它是下拉组件的父级):
这是代码:
export class AppComponent {
constructor( public subjects: SubjectsService) {
document.addEventListener('click', () => this.onClick());
}
onClick( ) {
this.subjects.userMenu.next({});
}
}
Run Code Online (Sandbox Code Playgroud)
这设置超时延迟订阅到当前JavaScript代码的结束转而解决问题,但在我看来以非常优雅的方式.
如果您了解更清洁,更好,更智能,更快速或更强大的解决方案,请告诉我:)!
Sas*_*sxa 225
你可以使用(document:click)事件:
@Component({
host: {
'(document:click)': 'onClick($event)',
},
})
class SomeComponent() {
constructor(private _eref: ElementRef) { }
onClick(event) {
if (!this._eref.nativeElement.contains(event.target)) // or some similar check
doSomething();
}
}
Run Code Online (Sandbox Code Playgroud)
另一种方法是将自定义事件创建为指令.看看Ben Nadel的这些帖子:
Kam*_*ski 34
我找到了这个clickOut指令:https:
//github.com/chliebel/angular2-click-outside.我检查它,它运作良好(我只复制clickOutside.directive.ts到我的项目).你可以这样使用它:
<div (clickOutside)="close($event)"></div>
Run Code Online (Sandbox Code Playgroud)
close当用户在div外部单击时,您的函数将在何处调用.处理问题所描述的问题是非常优雅的方式.
如果你使用above指令关闭popUp窗口,请记住首先添加event.stopPropagation()到打开popUp的按钮单击事件处理程序.
下面我从文件中复制oryginal指令代码clickOutside.directive.ts(如果链接将来会停止工作) - 作者是Christian Liebel:
import {Directive, ElementRef, Output, EventEmitter, HostListener} from '@angular/core';
@Directive({
selector: '[clickOutside]'
})
export class ClickOutsideDirective {
constructor(private _elementRef: ElementRef) {
}
@Output()
public clickOutside = new EventEmitter<MouseEvent>();
@HostListener('document:click', ['$event', '$event.target'])
public onClick(event: MouseEvent, targetElement: HTMLElement): void {
if (!targetElement) {
return;
}
const clickedInside = this._elementRef.nativeElement.contains(targetElement);
if (!clickedInside) {
this.clickOutside.emit(event);
}
}
}Run Code Online (Sandbox Code Playgroud)
Ton*_*ony 18
我这样做了.
在文档中添加了一个事件监听器,click并在该处理程序中检查了我是否container包含event.target,如果不包含- 隐藏下拉列表.
它看起来像这样.
@Component({})
class SomeComponent {
@ViewChild('container') container;
@ViewChild('dropdown') dropdown;
constructor() {
document.addEventListener('click', this.offClickHandler.bind(this)); // bind on doc
}
offClickHandler(event:any) {
if (!this.container.nativeElement.contains(event.target)) { // check click origin
this.dropdown.nativeElement.style.display = "none";
}
}
}
Run Code Online (Sandbox Code Playgroud)
JuH*_*m89 16
我认为Sasxa接受了大多数人的回答.但是,我遇到了一种情况,即应该监听off-click事件的Element内容会动态更改.所以Elements nativeElement在动态创建时不包含event.target.我可以用以下指令解决这个问题
@Directive({
selector: '[myOffClick]'
})
export class MyOffClickDirective {
@Output() offClick = new EventEmitter();
constructor(private _elementRef: ElementRef) {
}
@HostListener('document:click', ['$event.path'])
public onGlobalClick(targetElementPath: Array<any>) {
let elementRefInPath = targetElementPath.find(e => e === this._elementRef.nativeElement);
if (!elementRefInPath) {
this.offClick.emit(null);
}
}
}
Run Code Online (Sandbox Code Playgroud)
我检查elementRef是否在事件的路径(DOM目标路径)中,而不是检查elementRef是否包含event.target.这样就可以处理动态创建的元素.
Xav*_*ier 11
touchstart事件:从Angular 4开始,HostListener装饰是执行此操作的首选方式
import { Component, OnInit, HostListener, ElementRef } from '@angular/core';
...
@Component({...})
export class MyComponent implement OnInit {
constructor(private eRef: ElementRef){}
@HostListener('document:click', ['$event'])
@HostListener('document:touchstart', ['$event'])
handleOutsideClick(event) {
// Some kind of logic to exclude clicks in Component.
// This example is borrowed Kamil's answer
if (!this.eRef.nativeElement.contains(event.target) {
doSomethingCool();
}
}
}
Run Code Online (Sandbox Code Playgroud)
小智 10
我们今天一直在研究一个类似的问题,试图找出如何让dropdown div在被点击时消失.我们与初始海报的问题略有不同,因为我们不想点击其他组件或指令,而只是在特定div之外.
我们最终通过使用(window:mouseup)事件处理程序来解决它.
步骤:
1.)我们给整个下拉菜单div一个唯一的类名.
2.)在内部下拉菜单本身(我们想要点击不关闭菜单的唯一部分),我们添加了一个(window:mouseup)事件处理程序并传入$ event.
注意:使用典型的"单击"处理程序无法完成,因为这与父单击处理程序冲突.
3.)在我们的控制器中,我们创建了我们想要在click out事件中调用的方法,并且我们使用event.closest(这里是docs)来查明点击的点是否在我们的目标类div中.
autoCloseForDropdownCars(event) {
var target = event.target;
if (!target.closest(".DropdownCars")) {
// do whatever you want here
}
}Run Code Online (Sandbox Code Playgroud)
<div class="DropdownCars">
<span (click)="toggleDropdown(dropdownTypes.Cars)" class="searchBarPlaceholder">Cars</span>
<div class="criteriaDropdown" (window:mouseup)="autoCloseForDropdownCars($event)" *ngIf="isDropdownShown(dropdownTypes.Cars)">
</div>
</div>Run Code Online (Sandbox Code Playgroud)
mouseleave您可以像这样在您的视图中使用
用 Angular 8 测试并完美工作
<ul (mouseleave)="closeDropdown()"> </ul>
Run Code Online (Sandbox Code Playgroud)
您可以为覆盖整个屏幕的下拉列表创建一个兄弟元素,该元素将不可见并且仅用于捕获点击事件。然后您可以检测对该元素的点击并在点击时关闭下拉列表。让我们说元素是丝印类,这是它的一些样式:
.silkscreen {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index: 1;
}
Run Code Online (Sandbox Code Playgroud)
z-index 需要足够高以将其定位在除下拉列表之外的所有内容之上。在这种情况下,我的下拉列表将 b z-index 2。
其他答案在某些情况下对我有用,除了有时当我与其中的元素交互时我的下拉菜单关闭,我不想要那样。我根据事件目标动态添加了未包含在我的组件中的元素,就像我预期的那样。我想我不会用丝网印刷的方式来解决这个问题。
小智 5
我没有任何解决方法。我刚刚附加了文档:单击切换功能,如下所示:
@指示({
选择器:“ [appDropDown]”
})
导出类DropdownDirective实现OnInit {
@HostBinding('class.open')isOpen:布尔值;
构造函数(私有elemRef:ElementRef){}
ngOnInit():void {
this.isOpen = false;
}
@HostListener('document:click',['$ event'])
@HostListener('document:touchstart',['$ event'])
切换(事件){
如果(this.elemRef.nativeElement.contains(event.target)){
this.isOpen =!this.isOpen;
}其他{
this.isOpen = false;
}
}
因此,当我超出指令范围时,我将关闭下拉列表。
| 归档时间: |
|
| 查看次数: |
121963 次 |
| 最近记录: |