NG-ZORRO / ng-zorro-antd

Angular UI Component Library based on Ant Design
https://ng.ant.design
MIT License
8.87k stars 3.94k forks source link

下拉菜单不能连续触发 #2018

Closed qdwxlong closed 5 years ago

qdwxlong commented 6 years ago

Version

1.4.0

Environment

Reproduction link

https://stackblitz.com/edit/ng-zorro-antd-start-c87p83

Steps to reproduce

在区域内任意位置右击触发下拉菜单,在不关闭下拉菜单时,再次在此区域内的其他位置右击

What is expected?

关闭上一个下拉菜单,打开新的下拉菜单

What is actually happening?

无反应,必须关闭上一个下拉菜单,才可以触发下次事件

Other?

触发下拉菜单会生成一个全页面的遮蔽层,导致无法点击右键区域,用户体验不好,在tree控件右击菜单尤其不好,此情况也存在于click和hover触发行为,同时验证了一下React版本无此问题,希望可以修改,谢谢

vthinkxie commented 6 years ago

ref https://github.com/angular/material2/issues/5007

qdwxlong commented 6 years ago

我的临时解决方案(参考Ng Alain tab页右键菜单)

private dropdown: NzDropdownContextComponent;
nzVisible: boolean = false;

constructor(private nzDropdownService: NzDropdownService) { }
ngOnInit(): void { }

contextMenu($event: MouseEvent, template: TemplateRef<void>): void {
    $event.preventDefault();
    $event.stopPropagation();
    if (this.dropdown) {
        this.nzDropdownService.close();
    }
    this.dropdown = this.nzDropdownService.create($event, template);
}

close(e: NzMenuItemDirective): void {
    this.dropdown.close();
}

@HostListener('document:click', ['$event'])
@HostListener('document:contextmenu', ['$event'])
closeMenu(event: MouseEvent): void {
    if (event.type === 'click' && event.button === 2) return;
    if (this.nzVisible)
        this.nzVisible = false;
    if (this.dropdown) {
        this.nzDropdownService.close();
    }
}

同时修改样式(Ng Alain右键菜单会删除这个class对应的div): .cdk-overlay-backdrop { position: static !important; } 连接:https://stackblitz.com/edit/ng-zorro-antd-start-5c7jpr 问题:样式的修改会影响其他的组件,如时间组件点击空白处无法关闭,是否可以通过修改各个弹出框的关闭方式解决此问题,当然这可能是个比较大的工作量 @vthinkxie 或者参考Ng Alain删除对应的div才实现 @cipchk

qdwxlong commented 6 years ago

在上面的基础上又做了一下修改: nz-dropdown.service.ts(做了部分修改)

private createOverlay($event: MouseEvent): OverlayRef {
    this.createPoint($event);
    const fakeElementRef = new ElementRef(this.locatePoint);
    this.positionStrategy = this.overlay.position().flexibleConnectedTo(fakeElementRef);
    this.handlePositionChanges(this.positionStrategy);
    const overlayConfig = new OverlayConfig({
        hasBackdrop: false,//原为true
        scrollStrategy: this.overlay.scrollStrategies.close(),
        positionStrategy: this.positionStrategy
    });
    return this.overlay.create(overlayConfig);
}

create($event: MouseEvent, template: TemplateRef<void>): NzDropdownContextComponent {
    $event.preventDefault();
    $event.stopPropagation();
    this.close();//关闭已经打开的
    if (this.overlayRef && this.overlayRef.hasAttached()) {
        this.overlayRef.dispose();
    } else {
        this.overlayRef = this.createOverlay($event);
        setTimeout(() => {
            if (this.overlayRef.backdropElement) {
                this.zone.runOutsideAngular(() => { 
                    this.overlayRef.backdropElement.addEventListener('contextmenu', (e: MouseEvent) => e.preventDefault());
                });
            }
        });
        this.instance = this.overlayRef.attach(new ComponentPortal(NzDropdownContextComponent)).instance;
        this.setInstanceValue(this.instance, template);
        this.handleCloseEvent(this.overlayRef);
        return this.instance;
    }
}

close(): void {
    if (this.instance) {//关闭时做了验证
        this.removePoint();
        this.overlayRef.dispose();
        if (this.backdropClickSubscription) {
            this.backdropClickSubscription.unsubscribe();
            this.backdropClickSubscription = null;
        }
        if (this.detachmentsSubscription) {
            this.detachmentsSubscription.unsubscribe();
            this.detachmentsSubscription = null;
        }
        if (this.onPositionChangeSubscription) {
            this.onPositionChangeSubscription.unsubscribe();
            this.onPositionChangeSubscription = null;
        }
    }
}

创建一个Directive:

import { Directive, ElementRef, HostListener, Input, OnInit, TemplateRef } from '@angular/core';
import { DropdownDemoService } from './dropdown-demo.service';

@Directive({
    selector: '[dropdown-demo]',
    host: {
        '[class.ant-dropdown-trigger]': 'true'
    }
})
export class DropDownDemoDirective implements OnInit {

    @Input() dropdownDemo: TemplateRef<void>;
    ngOnInit(): void { }

    constructor(private dropdownDemoService: DropdownDemoService, public elementRef: ElementRef) { }

    @HostListener('contextmenu', ['$event'])
        contextmenu(event: MouseEvent): void {
        this.dropdownDemoService.create(event, this.dropdownDemo);
    }

    @HostListener('document:click', ['$event'])
    @HostListener('document:contextmenu', ['$event'])
    closeMenu(event: MouseEvent): void {
        if (event.type === 'click' && event.button === 2) return;
        this.dropdownDemoService.close();
    }
}

见连接:https://stackblitz.com/edit/ng-zorro-antd-start-qwkrrk 不在对样式进行修改 暂时自己这样用

vthinkxie commented 5 years ago

fixed in https://github.com/NG-ZORRO/ng-zorro-antd/commit/09f21d0860e7934da696f201c86b3e07afec052a