Angular cdk 學(xué)習(xí)之 Accessibility(ally)

? ? ? ?cdk ally里面提供的功能運(yùn)用場(chǎng)景是 select, menu 這種有 list options 的組件, 負(fù)責(zé)處理鍵盤(pán)上下按鈕時(shí) option active 的邏輯。cdk Accessibility 部分官方文檔連接https://material.angular.io/cdk/a11y/overview稽荧。

? ? ? ?和cdk里面其他功能模塊一樣橘茉,cdk ally使用之前也要provider導(dǎo)入A11yModule模塊。

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

一 ListKeyManager

? ? ? ?ListKeyManager主要做的事情就是去管理一堆的list 里面哪個(gè)item處于active狀態(tài)(active代表一種狀態(tài)姨丈,比如處于活動(dòng)轉(zhuǎn)換畅卓,獲取焦點(diǎn)狀態(tài)等等)。而且ListKeyManager管理的item必須實(shí)現(xiàn)ListKeyManagerOption接口蟋恬。換句話說(shuō)ListKeyManager用于管理一系列l(wèi)ist的item,這些item就是ListKeyManagerOption翁潘。通過(guò)ListKeyManager來(lái)控制那個(gè)ListKeyManagerOption對(duì)應(yīng)的item處于active狀態(tài)。所以咱們先看下ListKeyManagerOption和ListKeyManager里面一些常見(jiàn)的方法歼争,如下:

1.1 ListKeyManager常用方法

? ? ? ?講ListKeyManager方法的時(shí)候咱們順帶講下ListKeyManagerOption里面的方法

1.1.1 ListKeyManagerOption常用方法介紹

export interface ListKeyManagerOption {
    /** 當(dāng)前item是否disabled. */
    disabled?: boolean;
    /** 獲取當(dāng)前item對(duì)應(yīng)的label,配合ListKeyManager里面withTypeAhead函數(shù)的使用
     *  適用于輸入框的情況拜马,比如輸入框下面有一些list item。當(dāng)輸入框輸入字符的時(shí)候list item 里面的active
     *  item 和輸入的文字匹配
     */
    getLabel?(): string;
}

1.1.2 ListKeyManager常用方法介紹

export declare class ListKeyManager<T extends ListKeyManagerOption> {
    /**
     * tab 按鍵的時(shí)候觸發(fā)的
     */
    tabOut: Subject<void>;
    /** 當(dāng)ListKeyManager里面的list item ,active item 改變的時(shí)候觸發(fā)*/
    change: Subject<number>;
    /**
     * 設(shè)置那些ListKeyManager管理的list里在移動(dòng)(比如tab 按鍵切換)過(guò)程中那些item需要跳過(guò)沐绒。
     */
    skipPredicate(predicate: (item: T) => boolean): this;
    /**
     * 設(shè)置是否循環(huán)移動(dòng)(當(dāng)active item是最好一個(gè)的時(shí)候俩莽,繼續(xù)下一個(gè)跳到第一個(gè))
     */
    withWrap(shouldWrap?: boolean): this;
    /**
     * active item 移動(dòng)方向垂直(對(duì)應(yīng)鍵盤(pán)方向鍵的 上下按鍵)
     */
    withVerticalOrientation(enabled?: boolean): this;
    /**
     * active item 移動(dòng)方向水平(對(duì)應(yīng)鍵盤(pán)方向鍵的 左右按鍵)
     */
    withHorizontalOrientation(direction: 'ltr' | 'rtl' | null): this;
    /**
     * 用來(lái)處理組合按鍵的情況,比如 altr + 方向鍵的時(shí)候乔遮。同樣達(dá)到方向按鍵的效果
     */
    withAllowedModifierKeys(keys: ListKeyManagerModifierKey[]): this;
    /**
     * 設(shè)置typeahead 模式 配合ListKeyManagerOption的getLabel()函數(shù)使用扮超,一般用于配合有輸入框的情況下使用,比如輸入框輸入一個(gè)字符蹋肮,active item 會(huì)自動(dòng)設(shè)置到包含這個(gè)字符item
     */
    withTypeAhead(debounceInterval?: number): this;
    /**
     * 設(shè)置 active item 對(duì)應(yīng)的index
     */
    setActiveItem(index: number): void;
    /**
     * 設(shè)置 active item 對(duì)應(yīng)的item
     */
    setActiveItem(item: T): void;
    /**
     * 設(shè)置按鍵
     */
    onKeydown(event: KeyboardEvent): void;
    /** 當(dāng)前active item 對(duì)應(yīng)的事件 */
    readonly activeItemIndex: number | null;
    /** 當(dāng)前active item 對(duì)應(yīng)的item */
    readonly activeItem: T | null;
    /** 設(shè)置第一個(gè)位置的item 為active item(當(dāng)然了如果第一個(gè)item 是disable,則設(shè)置第二個(gè)) */
    setFirstItemActive(): void;
    /** 設(shè)置最后一個(gè)位置的item 為 active item */
    setLastItemActive(): void;
    /** 設(shè)置下一個(gè)item 為active item */
    setNextItemActive(): void;
    /** 設(shè)置上一個(gè)item 為active item */
    setPreviousItemActive(): void;
    /**
     * 設(shè)置active item,但是不產(chǎn)生其他的效果
     */
    updateActiveItem(index: number): void;
    /**
     * 設(shè)置active item,但是不產(chǎn)生其他的效果
     */
    updateActiveItem(item: T): void;
}

1.2 ListKeyManager的使用

? ? ? ?接下來(lái)咱們通過(guò)ListKeyManager的兩個(gè)具體繼承類(lèi)ActiveDescendantKeyManager和FocusKeyManager來(lái)說(shuō)明ListKeyManager的具體使用出刷。其實(shí)ActiveDescendantKeyManager里面管理的item必須實(shí)現(xiàn)Highlightable接口、FocusKeyManager里面管理的item必須實(shí)現(xiàn)FocusableOption坯辩。

1.2.1 ActiveDescendantKeyManager的使用

? ? ? ?ActiveDescendantKeyManager里面管理的list item 必須實(shí)現(xiàn)Highlightable接口馁龟。

ActiveDescendantKeyManager繼承了ListKeyManager類(lèi),Highlightable實(shí)現(xiàn)了ListKeyManagerOption接口

? ? ? ?ActiveDescendantKeyManager使用場(chǎng)景:如果想ListKeyManager管理的list里面active的item標(biāo)記為活動(dòng)狀態(tài)濒翻,其他的標(biāo)記為非活動(dòng)狀態(tài)情況下使用屁柏。而且每個(gè)item都必須實(shí)現(xiàn)Highlightable接口啦膜。接下來(lái)咱們通過(guò)一個(gè)具體的實(shí)例來(lái)簡(jiǎn)單的說(shuō)明下。

咱們自定義一個(gè)item組件ItemActiveOptionComponent淌喻,這個(gè)組件實(shí)現(xiàn)Highlightable接口僧家。組件里面做的事情也很簡(jiǎn)單就是去改變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;
    }

    /**
     * 設(shè)置 active對(duì)應(yīng)的class
     */
    setActiveStyles() {
        this._isActive = true;
    }

    /**
     * 設(shè)置非active對(duì)應(yīng)的class
     */
    setInactiveStyles() {
        this._isActive = false;
    }

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


cdk-active-descendant.component.less文件裸删,組件對(duì)應(yīng)樣式

.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的使用八拱,咱們放在這個(gè)組件里面實(shí)現(xiàn)。ActiveDescendantKeyManager里面管理的item就是咱們上面自定義的ItemActiveOptionComponent涯塔。具體的實(shí)現(xiàn)可以看下代碼肌稻。

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() // 循環(huán)
            .withTypeAhead(); // 支持搜索

    }

    onKeyDown(event) {
        // 傳遞事件進(jìn)去
        this.keyManager.onKeydown(event);
    }
}

ActiveDescendantKeyManager.gif

1.2.2 FocusKeyManager的使用

? ? ? ?FocusKeyManager里面管理的item必須實(shí)現(xiàn)FocusableOption接口。

FocusKeyManager繼承了ListKeyManager類(lèi)匕荸,F(xiàn)ocusableOption實(shí)現(xiàn)了ListKeyManagerOption接口

? ? ? ?FocusKeyManager使用場(chǎng)景:如果想ListKeyManager管理的list里面active item想直接接受到瀏覽器的焦點(diǎn)focus的時(shí)候使用爹谭。每個(gè)item都必須實(shí)現(xiàn)FocusableOption接口。

自定義一個(gè)組件ItemFocusOptionComponent,并且這個(gè)組件實(shí)現(xiàn)了FocusableOption接口榛搔,F(xiàn)ocusableOption接口的focus()方法里面設(shè)置當(dāng)前item獲取焦點(diǎn)诺凡。

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;

    /**
     * 屏蔽掉默認(rèn)的鍵盤(pán)事件,js里面自己控制鍵盤(pán)事件
     */
    @HostBinding('tabindex') tabindex = '-1';

    constructor(private host: ElementRef) {
    }

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

    /**
     * 設(shè)置獲取焦點(diǎn)
     */
    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 {

    // 獲取搜有實(shí)現(xiàn)了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() {
        // 創(chuàng)建FocusKeyManager對(duì)象
        this.keyManager = new FocusKeyManager(this.items)
            .withWrap()
            .withTypeAhead();

    }

    /**
     * 傳遞按鍵事件
     * @param event
     */
    onKeyDown(event) {
        this.keyManager.onKeydown(event);
    }

    /**
     * 點(diǎn)擊選中
     * @param index
     */
    selectItem(index: number) {
        this.keyManager.setActiveItem(index);
    }

}

FocusKeyManager.gif

二 FocusTrap

? ? ? ?FocusTrap是cdk ally模塊里面提供的一個(gè)指令践惑。用于捕獲元素中的Tab鍵焦點(diǎn)腹泌。同時(shí)控制焦點(diǎn)的范圍,Tab切換焦點(diǎn)的時(shí)候不會(huì)跳出這個(gè)區(qū)域。舉個(gè)例子比如有一個(gè)視圖元素添加了FocusTrap指令尔觉,這個(gè)視圖元素里面有三個(gè)input凉袱。這樣Tab鍵切換焦點(diǎn)的時(shí)候焦點(diǎn)會(huì)在這三個(gè)input之間切換。

? ? ? ?Selector: [cdkTrapFocus]

? ? ? ?Exported as: cdkTrapFocus

? ? ? ?還有幾個(gè)其他的指令可以配合FocusTrap指令來(lái)使用:cdkFocusRegionStart侦铜、cdkFocusRegionEnd专甩、cdkFocusInitial。咱們上面不是說(shuō)了FocusTrap指令會(huì)控制焦點(diǎn)的范圍泵额。cdkFocusRegionStart和cdkFocusRegionEnd指令有可以進(jìn)一步的控制焦點(diǎn)的范圍

  • cdkFocusRegionStart:FocusTrap范圍的起點(diǎn)
  • cdkFocusRegionEnd:FocusTrap范圍的終點(diǎn)
  • cdkFocusInitial:區(qū)間出現(xiàn)時(shí)配深,一開(kāi)始獲取focus的item。

2.1 FocusTrap指令屬性介紹

FocusTrap屬性 類(lèi)型 解釋
autoCapture: boolean @Input('cdkTrapFocusAutoCapture') 初始化的時(shí)候元素是否自動(dòng)獲取焦點(diǎn)
enabled: boolean @Input('cdkTrapFocus') false Tab切換焦點(diǎn)的時(shí)候會(huì)跑到外面去嫁盲,true Tab切換焦點(diǎn)的時(shí)候焦點(diǎn)不會(huì)跑到外面去

2.2 FocusTrap指令使用

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

@Component({
    selector: 'app-cdk-accessibility',
    template: `
        <!-- FocusTrap的使用篓叶,- 控制焦點(diǎn)的范圍,tab切換焦點(diǎn)的時(shí)候不會(huì)跳出這個(gè)區(qū)域 -->
        <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的使用應(yīng)該很好理解。就是用來(lái)控制范圍的羞秤。關(guān)鍵是cdkFocusInitial的使用缸托,cdkFocusInitial必須要配合cdkTrapFocus指令的cdkTrapFocusAutoCapture=true使用。而且我試了下cdkFocusInitial一開(kāi)始是沒(méi)有效果瘾蛋,沒(méi)都是隱藏顯示的時(shí)候才有效果俐镐,才獲取到焦點(diǎn)。

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里面提供的一個(gè)Service哺哼。用于監(jiān)控焦點(diǎn)佩抹。FocusMonitor里面常用方法如下

export declare class FocusMonitor implements OnDestroy {

    /**
     * 監(jiān)聽(tīng)元素的焦點(diǎn)獲取
     */
    monitor(element: HTMLElement, checkChildren?: boolean): Observable<FocusOrigin>;
    monitor(element: ElementRef<HTMLElement>, checkChildren?: boolean): Observable<FocusOrigin>;
    /**
     * 停止監(jiān)聽(tīng)元素的焦點(diǎn)獲取
     */
    stopMonitoring(element: HTMLElement): void;
    stopMonitoring(element: ElementRef<HTMLElement>): void;
    /**
     * 設(shè)置元素獲取焦點(diǎn)
     * @param element 元素
     * @param origin 設(shè)置的焦點(diǎn)是通過(guò)哪個(gè)來(lái)的 'touch' | 'mouse' | 'keyboard' | 'program' | null
     * @param options 用于配置focus行為的選項(xiàng).
     */
    focusVia(element: HTMLElement, origin: FocusOrigin, options?: FocusOptions): void;
    focusVia(element: ElementRef<HTMLElement>, origin: FocusOrigin, options?: FocusOptions): void;
}

3.1 FocusMonitor的使用

? ? ? ?一個(gè)簡(jiǎn)單的例子叼风,咱們僅僅是在元素獲取焦點(diǎn)的時(shí)候做一個(gè)簡(jiǎn)單的打印。

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() {
        /**
         * 這里我們只是做了一個(gè)簡(jiǎn)單的打印
         */
        this._focusMonitor.monitor(this._elementRef.nativeElement, true).subscribe(mode => {
            console.log('元素獲取到焦點(diǎn) focused 來(lái)源 ' + mode);
        });
    }

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

}

四 FocusTrapFactory

? ? ? ?FocusTrapFactory也是cdk ally里面提供的一個(gè)Service棍苹。他的功能就是用來(lái)給元素添加cdkFocusTrap指令无宿。FocusTrapFactory常用函數(shù)就一個(gè),如下

export declare class FocusTrapFactory {
    /**
     * 給指定的元素添加cdkFocusTrap指令枢里,deferCaptureElements參數(shù)正好對(duì)應(yīng)cdkFocusTrap指令
     * @Input('cdkTrapFocusAutoCapture')功能
     */
    create(element: HTMLElement, deferCaptureElements?: boolean): FocusTrap;
}

4.1 FocusTrapFactory使用

? ? ? ?通過(guò)FocusTrapFactory的crete函數(shù)達(dá)到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是一個(gè)Service,用于檢查元素的一些狀態(tài)栏豺。常見(jiàn)方法如下彬碱。

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按鍵切換焦點(diǎn)
     */
    isTabbable(element: HTMLElement): boolean;
    /**
     * 元素是否可以獲取焦點(diǎn)
     */
    isFocusable(element: HTMLElement): boolean;
}

5.1 InteractivityChecker使用

? ? ? ?舉一個(gè)非常簡(jiǎn)單的例子奥洼,打印出button的各種狀態(tài)巷疼。

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

@Component({
    selector: 'app-cdk-interactivity-checker',
    template: `
        <button #interactivityCheckerButton>InteractivityChecker測(cè)試</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也是一個(gè)Service。用于在屏幕上發(fā)布一個(gè)消息灵奖。把消息顯示在屏幕上皮迟。關(guān)于這一部分的內(nèi)容估計(jì)的去看下W3C關(guān)于WAI-ARIA的使用。我們就舉一個(gè)簡(jiǎn)單的例子桑寨。

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

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

    index = 1;

    /**
     * 會(huì)在屏幕上輸出Hey Google,三秒之后又會(huì)換成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");
    }

}


? ? ? ?關(guān)于cdk ally咱們就扯這么多忿檩,希望能對(duì)大家有點(diǎn)幫助尉尾。當(dāng)然了里面很有很多其他的類(lèi)咱們沒(méi)有介紹到。大家在時(shí)機(jī)使用的時(shí)候可以對(duì)照官方文檔看下 https://material.angular.io/cdk/a11y/overview燥透。 文章中涉及到的例子連接地址 https://github.com/tuacy/angular-cdk-study

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末沙咏,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子班套,更是在濱河造成了極大的恐慌肢藐,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,039評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件吱韭,死亡現(xiàn)場(chǎng)離奇詭異吆豹,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)理盆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)痘煤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人猿规,你說(shuō)我怎么就攤上這事衷快。” “怎么了姨俩?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,417評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵蘸拔,是天一觀的道長(zhǎng)师郑。 經(jīng)常有香客問(wèn)我,道長(zhǎng)调窍,這世上最難降的妖魔是什么宝冕? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,868評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮陨晶,結(jié)果婚禮上猬仁,老公的妹妹穿的比我還像新娘。我一直安慰自己先誉,他們只是感情好湿刽,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著褐耳,像睡著了一般诈闺。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上铃芦,一...
    開(kāi)封第一講書(shū)人閱讀 51,692評(píng)論 1 305
  • 那天雅镊,我揣著相機(jī)與錄音,去河邊找鬼刃滓。 笑死仁烹,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的咧虎。 我是一名探鬼主播卓缰,決...
    沈念sama閱讀 40,416評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼砰诵!你這毒婦竟也來(lái)了征唬?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,326評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤茁彭,失蹤者是張志新(化名)和其女友劉穎总寒,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體理肺,經(jīng)...
    沈念sama閱讀 45,782評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡摄闸,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了哲嘲。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片贪薪。...
    茶點(diǎn)故事閱讀 40,102評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖眠副,靈堂內(nèi)的尸體忽然破棺而出画切,到底是詐尸還是另有隱情,我是刑警寧澤囱怕,帶...
    沈念sama閱讀 35,790評(píng)論 5 346
  • 正文 年R本政府宣布霍弹,位于F島的核電站毫别,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏典格。R本人自食惡果不足惜岛宦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望耍缴。 院中可真熱鬧砾肺,春花似錦、人聲如沸防嗡。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,996評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)蚁趁。三九已至裙盾,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間他嫡,已是汗流浹背番官。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,113評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留钢属,地道東北人徘熔。 一個(gè)月前我還...
    沈念sama閱讀 48,332評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像淆党,于是被迫代替她去往敵國(guó)和親近顷。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • # 傳智播客vue 學(xué)習(xí)## 1. 什么是 Vue.js* Vue 開(kāi)發(fā)手機(jī) APP 需要借助于 Weex* Vu...
    再見(jiàn)天才閱讀 3,549評(píng)論 0 6
  • 第一節(jié):初識(shí)Angular-CLI第二節(jié):登錄組件的構(gòu)建第三節(jié):建立一個(gè)待辦事項(xiàng)應(yīng)用第四節(jié):進(jìn)化宁否!模塊化你的應(yīng)用第...
    接灰的電子產(chǎn)品閱讀 13,701評(píng)論 64 25
  • Angualr drag-drop里面的功能能讓我們非常方便的處理頁(yè)面上視圖的拖拽(自由拖拽、列表排序拖拽缀遍、...
    tuacy閱讀 8,120評(píng)論 0 2
  • 前段時(shí)間慕匠,看了一段西瓜視頻。講述了一個(gè)農(nóng)村家庭域醇,參加台谊,變形記的小女孩兒。名字叫什么我就不發(fā)了譬挚,我們就把她叫小花吧锅铅。...
    鐘容閱讀 297評(píng)論 0 0
  • 文/荷曦 居民樓內(nèi)星星點(diǎn)點(diǎn)的燈光讓人感覺(jué)溫馨,可能减宣,有些人還在計(jì)劃這個(gè)長(zhǎng)假去哪玩盐须,也有人在抓緊完成欠下的稿子撤蟆。不管...
    荷曦閱讀 464評(píng)論 4 3