Angular cdk 学习之 Accessibility(al

2018-12-20  本文已影响84人  tuacy

       cdk ally里面提供的功能运用场景是 select, menu 这种有 list options 的组件, 负责处理键盘上下按钮时 option active 的逻辑。cdk Accessibility 部分官方文档连接https://material.angular.io/cdk/a11y/overview

       和cdk里面其他功能模块一样,cdk ally使用之前也要provider导入A11yModule模块。

import {A11yModule} from '@angular/cdk/a11y';

一 ListKeyManager

       ListKeyManager主要做的事情就是去管理一堆的list 里面哪个item处于active状态(active代表一种状态,比如处于活动转换,获取焦点状态等等)。而且ListKeyManager管理的item必须实现ListKeyManagerOption接口。换句话说ListKeyManager用于管理一系列list的item,这些item就是ListKeyManagerOption。通过ListKeyManager来控制那个ListKeyManagerOption对应的item处于active状态。所以咱们先看下ListKeyManagerOption和ListKeyManager里面一些常见的方法,如下:

1.1 ListKeyManager常用方法

       讲ListKeyManager方法的时候咱们顺带讲下ListKeyManagerOption里面的方法

1.1.1 ListKeyManagerOption常用方法介绍

export interface ListKeyManagerOption {
    /** 当前item是否disabled. */
    disabled?: boolean;
    /** 获取当前item对应的label,配合ListKeyManager里面withTypeAhead函数的使用
     *  适用于输入框的情况,比如输入框下面有一些list item。当输入框输入字符的时候list item 里面的active
     *  item 和输入的文字匹配
     */
    getLabel?(): string;
}

1.1.2 ListKeyManager常用方法介绍

export declare class ListKeyManager<T extends ListKeyManagerOption> {
    /**
     * tab 按键的时候触发的
     */
    tabOut: Subject<void>;
    /** 当ListKeyManager里面的list item ,active item 改变的时候触发*/
    change: Subject<number>;
    /**
     * 设置那些ListKeyManager管理的list里在移动(比如tab 按键切换)过程中那些item需要跳过。
     */
    skipPredicate(predicate: (item: T) => boolean): this;
    /**
     * 设置是否循环移动(当active item是最好一个的时候,继续下一个跳到第一个)
     */
    withWrap(shouldWrap?: boolean): this;
    /**
     * active item 移动方向垂直(对应键盘方向键的 上下按键)
     */
    withVerticalOrientation(enabled?: boolean): this;
    /**
     * active item 移动方向水平(对应键盘方向键的 左右按键)
     */
    withHorizontalOrientation(direction: 'ltr' | 'rtl' | null): this;
    /**
     * 用来处理组合按键的情况,比如 altr + 方向键的时候。同样达到方向按键的效果
     */
    withAllowedModifierKeys(keys: ListKeyManagerModifierKey[]): this;
    /**
     * 设置typeahead 模式 配合ListKeyManagerOption的getLabel()函数使用,一般用于配合有输入框的情况下使用,比如输入框输入一个字符,active item 会自动设置到包含这个字符item
     */
    withTypeAhead(debounceInterval?: number): this;
    /**
     * 设置 active item 对应的index
     */
    setActiveItem(index: number): void;
    /**
     * 设置 active item 对应的item
     */
    setActiveItem(item: T): void;
    /**
     * 设置按键
     */
    onKeydown(event: KeyboardEvent): void;
    /** 当前active item 对应的事件 */
    readonly activeItemIndex: number | null;
    /** 当前active item 对应的item */
    readonly activeItem: T | null;
    /** 设置第一个位置的item 为active item(当然了如果第一个item 是disable,则设置第二个) */
    setFirstItemActive(): void;
    /** 设置最后一个位置的item 为 active item */
    setLastItemActive(): void;
    /** 设置下一个item 为active item */
    setNextItemActive(): void;
    /** 设置上一个item 为active item */
    setPreviousItemActive(): void;
    /**
     * 设置active item,但是不产生其他的效果
     */
    updateActiveItem(index: number): void;
    /**
     * 设置active item,但是不产生其他的效果
     */
    updateActiveItem(item: T): void;
}

1.2 ListKeyManager的使用

       接下来咱们通过ListKeyManager的两个具体继承类ActiveDescendantKeyManager和FocusKeyManager来说明ListKeyManager的具体使用。其实ActiveDescendantKeyManager里面管理的item必须实现Highlightable接口、FocusKeyManager里面管理的item必须实现FocusableOption。

1.2.1 ActiveDescendantKeyManager的使用

       ActiveDescendantKeyManager里面管理的list item 必须实现Highlightable接口。

ActiveDescendantKeyManager继承了ListKeyManager类,Highlightable实现了ListKeyManagerOption接口

       ActiveDescendantKeyManager使用场景:如果想ListKeyManager管理的list里面active的item标记为活动状态,其他的标记为非活动状态情况下使用。而且每个item都必须实现Highlightable接口。接下来咱们通过一个具体的实例来简单的说明下。

咱们自定义一个item组件ItemActiveOptionComponent,这个组件实现Highlightable接口。组件里面做的事情也很简单就是去改变active item的class样式。

import {Component, HostBinding, Input} from '@angular/core';
import {Highlightable} from "@angular/cdk/a11y";

@Component({
    selector: 'app-item-active-option',
    template: `
        <div [class.disabled]="disabled">
            <ng-content></ng-content>
        </div>
    `,
    styles: [`
        .active {
            background-color: lightblue;
            color: #fff;
        }

        .disabled {
            opacity: 0.3;
        }
    `]
})
export class ItemActiveOptionComponent implements Highlightable {
    @Input() item;
    @Input() disabled = false;
    private _isActive = false;

    @HostBinding('class.active') get isActive() {
        return this._isActive;
    }

    /**
     * 设置 active对应的class
     */
    setActiveStyles() {
        this._isActive = true;
    }

    /**
     * 设置非active对应的class
     */
    setInactiveStyles() {
        this._isActive = false;
    }

    getLabel() {
        return this.item.name;
    }
}


cdk-active-descendant.component.less文件,组件对应样式

.form-control {
  display: block;
  width: 100%;
  height: calc(2.25rem + 2px);
  padding: .375rem .75rem;
  font-size: 1rem;
  line-height: 1.5;
  color: #495057;
  background-color: #fff;
  background-clip: padding-box;
  border: 1px solid #ced4da;
  border-radius: .25rem;
  transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out;
}

.form-control:focus {
  color: #495057;
  background-color: #fff;
  border-color: #80bdff;
  outline: 0;
  box-shadow: 0 0 0 0.2rem rgba(0,123,255,.25);
}


.list-group-item:first-child {
  margin-top: 1rem;
  border-top-left-radius: .25rem;
  border-top-right-radius: .25rem;
}

.list-group-item  {
  position: relative;
  display: block;
  padding: .75rem 1.25rem;
  margin-bottom: -1px;
  background-color: #fff;
  border: 1px solid rgba(0, 0, 0, .125);
}

.list-group-item:last-child {
  margin-bottom: 0;
  border-bottom-right-radius: .25rem;
  border-bottom-left-radius: .25rem;
}

.list-group-item.active  {
  z-index: 2;
  color: #fff;
  background-color: #007bff;
  border-color: #007bff;
}

ActiveDescendantKeyManager的使用,咱们放在这个组件里面实现。ActiveDescendantKeyManager里面管理的item就是咱们上面自定义的ItemActiveOptionComponent。具体的实现可以看下代码。

import {AfterViewInit, Component, QueryList, ViewChildren} from '@angular/core';
import {ItemActiveOptionComponent} from "./active-item-option/item-active-option.component";
import {ActiveDescendantKeyManager} from "@angular/cdk/a11y";

@Component({
    selector: 'app-cdk-active-descendant',
    template: `
        <!-- 输入框 -->
        <div class="form-group">
            <input class="form-control" placeholder="Search..." (keyup)="onKeyDown($event)" #input>
        </div>

        <section class="list-group">
            <!-- ActiveDescendantKeyManager要管理的item -->
            <app-item-active-option *ngFor="let user of users | filter: 'name' : input.value; index as index"
                                    [item]="user" class="list-group-item">
                {{user.name}}
            </app-item-active-option>
        </section>
    `,
    styleUrls: ['cdk-active-descendant.component.less']
})
export class CdkActiveDescendantComponent implements AfterViewInit {

    /**
     * 找到所有的item(ListKeyManagerOption - Highlightable)
     */
    @ViewChildren(ItemActiveOptionComponent) items: QueryList<ItemActiveOptionComponent>;
    // list item source list
    users = [
        {
            "id": "5b902934d965e7501f4e1c6f",
            "name": "Caroline Hodges"
        },
        {
            "id": "5b9029348f7eed8b6f5f02db",
            "name": "Delores Rivas"
        },
        {
            "id": "5b9029346f48c8407c64d0d5",
            "name": "Darlene Franklin"
        },
        {
            "id": "5b9029341eff315fa87f9e21",
            "name": "Alfreda Love"
        },
        {
            "id": "5b9029342e8917c6ccdb9865",
            "name": "Marcy Ratliff"
        },
        {
            "id": "5b9029349dbb48013460e01f",
            "name": "Beulah Nielsen"
        },
        {
            "id": "5b902934f4f1586e5e72d74a",
            "name": "Morton Kerr"
        },
        {
            "id": "5b9029347918bb204bf7014e",
            "name": "Autumn Tillman"
        },
        {
            "id": "5b902934b86f80e1fc60c626",
            "name": "Diane Bennett"
        },
        {
            "id": "5b9029348999f59215020349",
            "name": "June Eaton"
        }
    ];

    private keyManager: ActiveDescendantKeyManager<ItemActiveOptionComponent>;

    ngAfterViewInit() {
        // new ActiveDescendantKeyManager
        this.keyManager = new ActiveDescendantKeyManager(this.items)
            .withWrap() // 循环
            .withTypeAhead(); // 支持搜索

    }

    onKeyDown(event) {
        // 传递事件进去
        this.keyManager.onKeydown(event);
    }
}

ActiveDescendantKeyManager.gif

1.2.2 FocusKeyManager的使用

       FocusKeyManager里面管理的item必须实现FocusableOption接口。

FocusKeyManager继承了ListKeyManager类,FocusableOption实现了ListKeyManagerOption接口

       FocusKeyManager使用场景:如果想ListKeyManager管理的list里面active item想直接接受到浏览器的焦点focus的时候使用。每个item都必须实现FocusableOption接口。

自定义一个组件ItemFocusOptionComponent,并且这个组件实现了FocusableOption接口,FocusableOption接口的focus()方法里面设置当前item获取焦点。

import {Component, ElementRef, HostBinding, Input} from '@angular/core';
import {FocusableOption, FocusOrigin} from "@angular/cdk/a11y";

@Component({
    selector: 'app-item-focus-option',
    template: `
        <ng-content></ng-content>
    `,
    styles: [
            `:host:focus {
            background: lightblue;
            color: #fff;
        }`
    ]
})

export class ItemFocusOptionComponent implements FocusableOption {
    @Input() item;

    /**
     * 屏蔽掉默认的键盘事件,js里面自己控制键盘事件
     */
    @HostBinding('tabindex') tabindex = '-1';

    constructor(private host: ElementRef) {
    }

    getLabel() {
        return this.item.name;
    }

    /**
     * 设置获取焦点
     */
    focus(origin?: FocusOrigin): void {
        this.host.nativeElement.focus();
    }
}

cdk-focus.component.less 样式文件

.form-control {
  display: block;
  width: 100%;
  height: calc(2.25rem + 2px);
  padding: .375rem .75rem;
  font-size: 1rem;
  line-height: 1.5;
  color: #495057;
  background-color: #fff;
  background-clip: padding-box;
  border: 1px solid #ced4da;
  border-radius: .25rem;
  transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out;
}

.form-control:focus {
  color: #495057;
  background-color: #fff;
  border-color: #80bdff;
  outline: 0;
  box-shadow: 0 0 0 0.2rem rgba(0,123,255,.25);
}


.list-group-item:first-child {
  margin-top: 1rem;
  border-top-left-radius: .25rem;
  border-top-right-radius: .25rem;
}

.list-group-item  {
  position: relative;
  display: block;
  padding: .75rem 1.25rem;
  margin-bottom: -1px;
  background-color: #fff;
  border: 1px solid rgba(0, 0, 0, .125);
}

.list-group-item:last-child {
  margin-bottom: 0;
  border-bottom-right-radius: .25rem;
  border-bottom-left-radius: .25rem;
}

.list-group-item.focus {
  z-index: 2;
  color: #fff;
  background-color: #007bff;
  border-color: #007bff;
}

FocusKeyManager的具体使用

import {AfterViewInit, Component, QueryList, ViewChildren} from '@angular/core';
import {FocusableOption, FocusKeyManager} from "@angular/cdk/a11y";
import {ItemFocusOptionComponent} from "./focus-item-option/item-focus-option.component";

@Component({
    selector: 'app-cdk-focus',
    template: `
        <section class="list-group" (keyup)="onKeyDown($event)">
            <app-item-focus-option *ngFor="let user of users; index as index"
                                   [item]="user" class="list-group-item"
                                   (click)="selectItem(index)">
                {{user.name}}
            </app-item-focus-option>
        </section>
    `,
    styleUrls: ['./cdk-focus.component.less']
})
export class CdkFocusComponent implements AfterViewInit {

    // 获取搜有实现了FocusableOption接口的item
    @ViewChildren(ItemFocusOptionComponent) items: QueryList<ItemFocusOptionComponent>;
    // list source
    users = [
        {
            "id": "5b902934d965e7501f4e1c6f",
            "name": "Caroline Hodges"
        },
        {
            "id": "5b9029348f7eed8b6f5f02db",
            "name": "Delores Rivas"
        },
        {
            "id": "5b9029346f48c8407c64d0d5",
            "name": "Darlene Franklin"
        },
        {
            "id": "5b9029341eff315fa87f9e21",
            "name": "Alfreda Love"
        },
        {
            "id": "5b9029342e8917c6ccdb9865",
            "name": "Marcy Ratliff"
        },
        {
            "id": "5b9029349dbb48013460e01f",
            "name": "Beulah Nielsen"
        },
        {
            "id": "5b902934f4f1586e5e72d74a",
            "name": "Morton Kerr"
        },
        {
            "id": "5b9029347918bb204bf7014e",
            "name": "Autumn Tillman"
        },
        {
            "id": "5b902934b86f80e1fc60c626",
            "name": "Diane Bennett"
        },
        {
            "id": "5b9029348999f59215020349",
            "name": "June Eaton"
        }
    ];

    private keyManager: FocusKeyManager<ItemFocusOptionComponent>;

    ngAfterViewInit() {
        // 创建FocusKeyManager对象
        this.keyManager = new FocusKeyManager(this.items)
            .withWrap()
            .withTypeAhead();

    }

    /**
     * 传递按键事件
     * @param event
     */
    onKeyDown(event) {
        this.keyManager.onKeydown(event);
    }

    /**
     * 点击选中
     * @param index
     */
    selectItem(index: number) {
        this.keyManager.setActiveItem(index);
    }

}

FocusKeyManager.gif

二 FocusTrap

       FocusTrap是cdk ally模块里面提供的一个指令。用于捕获元素中的Tab键焦点。同时控制焦点的范围,Tab切换焦点的时候不会跳出这个区域。举个例子比如有一个视图元素添加了FocusTrap指令,这个视图元素里面有三个input。这样Tab键切换焦点的时候焦点会在这三个input之间切换。

       Selector: [cdkTrapFocus]

       Exported as: cdkTrapFocus

       还有几个其他的指令可以配合FocusTrap指令来使用:cdkFocusRegionStart、cdkFocusRegionEnd、cdkFocusInitial。咱们上面不是说了FocusTrap指令会控制焦点的范围。cdkFocusRegionStart和cdkFocusRegionEnd指令有可以进一步的控制焦点的范围

2.1 FocusTrap指令属性介绍

FocusTrap属性 类型 解释
autoCapture: boolean @Input('cdkTrapFocusAutoCapture') 初始化的时候元素是否自动获取焦点
enabled: boolean @Input('cdkTrapFocus') false Tab切换焦点的时候会跑到外面去,true Tab切换焦点的时候焦点不会跑到外面去

2.2 FocusTrap指令使用

import {Component} from '@angular/core';

@Component({
    selector: 'app-cdk-accessibility',
    template: `
        <!-- FocusTrap的使用,- 控制焦点的范围,tab切换焦点的时候不会跳出这个区域 -->
        <div cdkTrapFocus style="border: solid 1px #ccc; padding: 10px">
            <!-- Tab and Shift + Tab will not leave this element. -->
            <input placeholder="Email">
            <input type="password" placeholder="Password" style="margin-left: 10px">
            <button type="submit" style="margin-left: 10px">Submit</button>
        </div>
    `
})
export class CdkAccessibilityComponent {
}

2.3 cdkFocusRegionStart cdkFocusRegionEnd cdkFocusInitial的使用

       cdkFocusRegionStart和cdkFocusRegionEnd的使用应该很好理解。就是用来控制范围的。关键是cdkFocusInitial的使用,cdkFocusInitial必须要配合cdkTrapFocus指令的cdkTrapFocusAutoCapture=true使用。而且我试了下cdkFocusInitial一开始是没有效果,没都是隐藏显示的时候才有效果,才获取到焦点。

import {Component} from '@angular/core';

@Component({
    selector: 'app-cdk-accessibility',
    template: `
        <div *ngIf="displayFocusTrap" cdkTrapFocus cdkTrapFocusAutoCapture="true"
             style="border: solid 1px #ccc; padding: 10px; margin-top: 10px">
            <input value="1">
            <input style="margin-left: 10px" value="2" cdkFocusRegionStart>
            <input style="margin-left: 10px" value="3" cdkFocusInitial>
            <input style="margin-left: 10px" value="4" cdkFocusRegionEnd>
        </div>
        <button (click)="displayFocusTrap=!displayFocusTrap">显示</button>
    `
})
export class CdkAccessibilityComponent {

    displayFocusTrap = false;

}



三 FocusMonitor

       FocusMonitor是cdk ally里面提供的一个Service。用于监控焦点。FocusMonitor里面常用方法如下

export declare class FocusMonitor implements OnDestroy {

    /**
     * 监听元素的焦点获取
     */
    monitor(element: HTMLElement, checkChildren?: boolean): Observable<FocusOrigin>;
    monitor(element: ElementRef<HTMLElement>, checkChildren?: boolean): Observable<FocusOrigin>;
    /**
     * 停止监听元素的焦点获取
     */
    stopMonitoring(element: HTMLElement): void;
    stopMonitoring(element: ElementRef<HTMLElement>): void;
    /**
     * 设置元素获取焦点
     * @param element 元素
     * @param origin 设置的焦点是通过哪个来的 'touch' | 'mouse' | 'keyboard' | 'program' | null
     * @param options 用于配置focus行为的选项.
     */
    focusVia(element: HTMLElement, origin: FocusOrigin, options?: FocusOptions): void;
    focusVia(element: ElementRef<HTMLElement>, origin: FocusOrigin, options?: FocusOptions): void;
}

3.1 FocusMonitor的使用

       一个简单的例子,咱们仅仅是在元素获取焦点的时候做一个简单的打印。

import {AfterViewInit, Component, ElementRef, OnDestroy} from '@angular/core';
import {FocusMonitor} from "@angular/cdk/a11y";

@Component({
    selector: 'app-cdk-focus-monitor',
    template: `
        <div cdkTrapFocus style="border: solid 1px #ccc; padding: 10px; margin-top: 10px">
            <input value="FocusMonitor item 1">
            <input style="margin-left: 10px" value="FocusMonitor item 2">
            <input style="margin-left: 10px" value="FocusMonitor item 3">
            <input style="margin-left: 10px" value="FocusMonitor item 4">
        </div>
    `
})
export class CdkFocusMonitorComponent implements AfterViewInit, OnDestroy {

    constructor(private _elementRef: ElementRef,
                private _focusMonitor: FocusMonitor) {
    }

    ngAfterViewInit() {
        /**
         * 这里我们只是做了一个简单的打印
         */
        this._focusMonitor.monitor(this._elementRef.nativeElement, true).subscribe(mode => {
            console.log('元素获取到焦点 focused 来源 ' + mode);
        });
    }

    ngOnDestroy() {
        this._focusMonitor.stopMonitoring(this._elementRef.nativeElement);
    }

}

四 FocusTrapFactory

       FocusTrapFactory也是cdk ally里面提供的一个Service。他的功能就是用来给元素添加cdkFocusTrap指令。FocusTrapFactory常用函数就一个,如下

export declare class FocusTrapFactory {
    /**
     * 给指定的元素添加cdkFocusTrap指令,deferCaptureElements参数正好对应cdkFocusTrap指令
     * @Input('cdkTrapFocusAutoCapture')功能
     */
    create(element: HTMLElement, deferCaptureElements?: boolean): FocusTrap;
}

4.1 FocusTrapFactory使用

       通过FocusTrapFactory的crete函数达到cdkFocusTrap指令的效果。

import {AfterViewInit, Component, ElementRef} from '@angular/core';
import {FocusTrap, FocusTrapFactory} from "@angular/cdk/a11y";

@Component({
    selector: 'app-cdk-focus-trap-factory',
    template: `
        <div style="border: solid 1px #ccc; padding: 10px; margin-top: 10px">
            <input value="FocusTrapFactory item 1">
            <input style="margin-left: 10px" value="FocusTrapFactory item 2">
            <input style="margin-left: 10px" value="FocusTrapFactory item 3">
            <input style="margin-left: 10px" value="FocusTrapFactory item 4">
        </div>
    `
})
export class CdkFocusTrapFactoryComponent implements AfterViewInit {

    private _focusTrap: FocusTrap;

    constructor(private _elementRef: ElementRef,
                private _focusTrapFactory: FocusTrapFactory) {
    }

    ngAfterViewInit() {
        this._focusTrap = this._focusTrapFactory.create(this._elementRef.nativeElement);
    }

}

五 InteractivityChecker

       InteractivityChecker是一个Service,用于检查元素的一些状态。常见方法如下。

export declare class InteractivityChecker {
    /**
     * 元素是否 disabled.
     */
    isDisabled(element: HTMLElement): boolean;
    /**
     * 元素是否visible
     *
     * This will capture states like `display: none` and `visibility: hidden`, but not things like
     * being clipped by an `overflow: hidden` parent or being outside the viewport.
     *
     * @returns Whether the element is visible.
     */
    isVisible(element: HTMLElement): boolean;
    /**
     * 元素是否接受Tab按键,不如Tab按键切换焦点
     */
    isTabbable(element: HTMLElement): boolean;
    /**
     * 元素是否可以获取焦点
     */
    isFocusable(element: HTMLElement): boolean;
}

5.1 InteractivityChecker使用

       举一个非常简单的例子,打印出button的各种状态。

import {Component, ElementRef, OnInit, ViewChild} from '@angular/core';
import {InteractivityChecker} from "@angular/cdk/a11y";

@Component({
    selector: 'app-cdk-interactivity-checker',
    template: `
        <button #interactivityCheckerButton>InteractivityChecker测试</button>
        <p>上面button是否disable: {{disable}}</p>
        <p>上面button是否visible: {{visible}}</p>
        <p>上面button是否可以tabable: {{tabable}}</p>
        <p>上面button是否可以focusable: {{focusable}}</p>
    `
})
export class CdkInteractivityCheckerComponent implements OnInit {

    @ViewChild('interactivityCheckerButton') button: ElementRef;
    disable: boolean;
    visible: boolean;
    tabable: boolean;
    focusable: boolean;

    constructor(private _interactivityChecker: InteractivityChecker) {
    }

    ngOnInit() {
        this.disable = this._interactivityChecker.isDisabled(this.button.nativeElement);
        this.visible = this._interactivityChecker.isVisible(this.button.nativeElement);
        this.tabable = this._interactivityChecker.isTabbable(this.button.nativeElement);
        this.focusable = this._interactivityChecker.isFocusable(this.button.nativeElement);
    }

}

六 LiveAnnouncer

       LiveAnnouncer也是一个Service。用于在屏幕上发布一个消息。把消息显示在屏幕上。关于这一部分的内容估计的去看下W3C关于WAI-ARIA的使用。我们就举一个简单的例子。

import {Component} from '@angular/core';
import {LiveAnnouncer} from "@angular/cdk/a11y";

@Component({
    selector: 'app-cdk-live-announcer',
    template: `
    `
})
export class CdkLiveAnnouncerComponent {

    index = 1;

    /**
     * 会在屏幕上输出Hey Google,三秒之后又会换成Hey Google 2
     */
    constructor(private liveAnnouncer: LiveAnnouncer) {
        liveAnnouncer.announce("Hey Google");
        setTimeout(() => {
            this.timerTask();
        }, 3000);
    }

    timerTask() {
        this.index = this.index + 1;
        this.liveAnnouncer.announce("Hey Google " + this.index.toString(), "off");
    }

}


       关于cdk ally咱们就扯这么多,希望能对大家有点帮助。当然了里面很有很多其他的类咱们没有介绍到。大家在时机使用的时候可以对照官方文档看下 https://material.angular.io/cdk/a11y/overview。 文章中涉及到的例子连接地址 https://github.com/tuacy/angular-cdk-study

上一篇下一篇

猜你喜欢

热点阅读