1. ホーム
  2. javascript

[解決済み] ドロップダウンを外部クリックで閉じるには?

2022-04-24 19:07:37

質問内容

ログインメニューのドロップダウンを、ユーザーがそのドロップダウンの外をクリックしたときに閉じたいのですが、Angular2とAngular2の"aproach"でそれをしたいのですが・・・。

解決策を実装したのですが、本当に自信がありません。同じ結果を得るための最も簡単な方法があるはずなので、もし何かアイデアがあれば...話し合いましょう :) !

以下は私の実装です。

ドロップダウンのコンポーネントです。

これは、私のドロップダウンのコンポーネントです。

  • このコンポーネントがvisibleに設定されるたびに(たとえば、ユーザーがボタンをクリックして表示するとき)、quot;global" rxjsのサブジェクトにサブスクライブされます。 ユーザーメニュー の中に格納されています。 サブジェクトサービス .
  • そして、非表示になるたびに、この件名の配信を停止する。
  • どこをクリックしても このコンポーネントのテンプレートは onClick() メソッドで、トップ(およびアプリケーションコンポーネント)へのイベントのバブリングを停止します。

以下はそのコードです。

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;
    }
}

アプリケーションの構成要素です。

一方、アプリケーション・コンポーネント(ドロップダウン・コンポーネントの親)があります。

  • このコンポーネントは、すべてのクリックイベントをキャッチし、同じrxjsのSubject( ユーザーメニュー )

以下はそのコードです。

export class AppComponent {

    constructor( public subjects: SubjectsService) {
        document.addEventListener('click', () => this.onClick());
    }
    onClick( ) {
        this.subjects.userMenu.next({});
    }
}

気になること

  1. これらのコンポーネント間のコネクターとして機能するグローバルなSubjectを持つという考えには、本当に納得がいきません。
  2. その セットタイムアウト : これは、ユーザーがドロップダウンを表示するボタンをクリックした場合に、そうでなければ何が起こるかを示すために必要です。
    • ユーザはドロップダウンを表示するためにボタン(ドロップダウン・コンポーネントの一部ではない)をクリックします。
    • ドロップダウンが表示され は、すぐにuserMenuのサブジェクトに登録されます。 .
    • クリックイベントはアプリコンポーネントにバブルアップされ、キャッチされます。
    • アプリケーションコンポーネントは ユーザーメニュー 件名
    • ドロップダウン・コンポーネントは、このアクションを ユーザーメニュー で、ドロップダウンを非表示にします。
    • 最後にはドロップダウンは表示されません。

このセットのタイムアウトは、問題を解決する現在のJavaScriptコードのターンの終わりにサブスクリプションを遅らせますが、私の意見では非常にエレガントな方法で。

もし、もっと簡単な、もっと良い、もっと賢い、もっと速い、もっと強力な解決策をご存知でしたら、ぜひ教えてください :) !

解決方法は?

を使用することができます。 (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();
  }
}

もう一つの方法は、カスタムイベントをディレクティブとして作成することです。Ben Nadelによるこれらの投稿をチェックしてみてください。