Angular 彻底解决 Dropdown 在 Safari 上无法自动关闭的问题

之前在 Safari 上用 focus 事件来实现 Dropdown 下拉菜单,结果在 iOS 上不兼容。

尝试了 MDN 和 stack over flow 上各种奇技淫巧,然而在 iOS 上全都败下阵来。

孙子兵法云:上兵伐谋。看来正面不行,就要侧面来。

与其针对 iOS Safari 这个怪物,不如来次釜底抽薪,永绝后患。

我们不用 iOS 上不友好的事件,只用click这种没有问题的事件接口。

监听到全局的click事件触发,就立即关闭下拉菜单。

app.component.html中监听

<div (click)="onTap($event)" class="h-100"></div>

app.component.ts中处理

export class AppComponent {

  constructor(private globalSvc: GlobalStatusService) {
  }

  onTap(event: Event) {
    this.globalSvc.globalClick(event);
  }
}

这里封装了一个全局的状态服务GlobalStatusService.ts

import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class GlobalStatusService {
  private clickRootSource = new Subject<Event>();
  clickRoot$ = this.clickRootSource.asObservable();
  constructor() { }

  globalClick(event: Event) {
    this.clickRootSource.next(event);
  }
}

在全局范围内注入,传播这个点击事件给所有的订户。

Dropdown所在的nav-menu.ts中订阅这个全局点击事件

this.globalSvc.clickRoot$.subscribe(x => {
      this.closeNav();
      this.closeAuthDropdown();
    }

这样当全局点击事件触发时就能自动关闭下拉菜单了,但是呢,我们希望点击菜单中某些区域时不要自动关闭下拉菜单。

这也不难办,我们只要控制这个区域的点击事件不要冒泡即可,例如这个下拉菜单中的一个按钮,

<button class="flex-sm-right" (click)="nobuble($event)">
子菜单
</button>
  nobuble(event: Event) {
    event.stopPropagation();
  }

通过stopPropagation()阻止事件冒泡,这样全局点击事件就不会触发了,完美实现我们的需求。

如此,终于攻破了 iOS Safari 这个阻止提高用户体验的城池。

posted @ 2019-08-26 17:26  蝌蝌  阅读(443)  评论(0编辑  收藏  举报