MDC菜单-当焦点在输入上时保持菜单打开

时间:2020-05-20 19:03:05

标签: javascript html mdc-components

我正在使用MDC Web组件构建自动完成输入。我有一个输入文本字段和一个菜单。您可以看到codeandox here。 我正在显示有关focusin事件的菜单,但是如果我开始在输入字段中写入内容,则菜单将立即关闭。

@Injectable({ providedIn: 'root' })
export class AuthGuard implements CanActivate {
  constructor(private authService: AuthService, private router: Router) {}
  canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ):
    | boolean
    | UrlTree
    | Promise<boolean | UrlTree>
    | Observable<boolean | UrlTree> {
    return this.authService.user.pipe(
      map((user) => {
        const isAuth = !!user;

        if (isAuth) {
          return true;
        }

        return this.router.createUrlTree(['/auth']);
      })
    );
  }
}

我认为这是由于菜单默认行为在触发菜单外单击时关闭。这里的问题还在于焦点是来自文本字段的第一个菜单项。防止这种情况的方法是什么,并打开菜单直到焦点消失在输入字段上?

1 个答案:

答案 0 :(得分:2)

这里的问题与可访问性有关,这是按顺序发生的事情:

  1. 当您单击输入时,输入将获得客户端“焦点”。

  2. 这将触发打开菜单的“ focusin”事件。

  3. 然后,根据accessibility documentation defined here,MDCMenu将自动聚焦第一个菜单项。

要阻止此焦点自动发生,我们可以设置

menu.setDefaultFocusState(DefaultFocusState.NONE);

DefaultFocusState.NONE

不改变焦点。如果您不希望菜单将焦点集中在打开上,请进行设置。 (例如,“自动完成”下拉菜单。)

如果这么简单,那就太好了,但是现在的问题是,如果MDCMenu在没有焦点时自动关闭。

[edit]:这下一节是不正确的,锚点并没有打开,只是将其锚定在元素周围

要解决下一个问题,我们将MDCMenu锚定到输入元素(必须是本机元素):

menu.setAnchorElement(document.querySelector(".mdc-text-field"));

最后,我们需要告诉MDCMenu在从输入中移出焦点后关闭:

input.listen("focusout", () => {
  menu.open = false;
});

您可能还需要调整其他一些问题,但我认为应该可以解决。有一个共享的代码示例,该示例也使用MDCMenu制作“自动填充下拉菜单”,您可以在此处参考:https://gist.dreamtobe.cn/gpulido/4bae80a5be4fd5c7ed61f1f1667da039

以下是我的更改的代码,您可以在代码和框中使用:

import { MDCTextField } from "@material/textfield";
import { MDCMenu, DefaultFocusState, Corner } from "@material/menu";
import "./styles.scss";

const input = new MDCTextField(document.querySelector(".mdc-text-field"));
const menu = new MDCMenu(document.querySelector(".mdc-menu"));
menu.setDefaultFocusState(DefaultFocusState.NONE);
menu.setAnchorCorner(Corner.BOTTOM_START);
menu.setAnchorElement(input.component);

input.listen("focusin", () => {
  menu.open = true;
});
input.listen("click", () => {
  menu.open = true;
});
input.listen("focusout", () => {
  menu.open = false;
});