1. 程式人生 > 其它 >angular-cdk 探索

angular-cdk 探索

安裝(文件參考版本12.1.1)

ng add @angular/cdk
新增css
@import '~@angular/cdk/overlay-prebuilt.css';

執行兩個方法

<button (click)="add();add1()">Click</button>

獲取焦點失去焦點

css

.box .cdk-focused{
  background-color: red;
}

html

<div class="box">
  <button  cdkMonitorSubtreeFocus (cdkFocusChange)="add($event)">Click</button>
</div>

ts

 add(e: any) { // 點選的  mouse|touch
    console.log(e);
  }

點選的時候焦點

新增的時候class不一樣

html點選的時候新增的引數不一樣, 或者class不一樣

'touch' | 'mouse' | 'keyboard' | 'program' | null;

<button (click)="focusMonitor.focusVia(aaa,'mouse')">click1</button>
<div class="box">
  <button #aaa>我是box</button>
</div>

ts

export class ThreeComponent implements OnInit, AfterViewInit, OnDestroy {
  @ViewChild('aaa') aaa!: ElementRef<HTMLElement>;

  constructor(
    public focusMonitor: FocusMonitor,
  ) {
  }
  ngAfterViewInit() {
    this.focusMonitor.monitor(this.aaa).subscribe(origin => {
      console.log(origin);
    })
  }
  ngOnDestroy() {
    this.focusMonitor.stopMonitoring(this.aaa)
  }
}

複製剪貼簿

1

<button [cdkCopyToClipboard]="text1">複製到剪貼簿</button>

  text1='我是複製的內容'

2

<button (click)="copyHome()">複製到剪貼簿</button>

  constructor(
    private clip: Clipboard
  ) {}

  copyHome() {
    this.clip.copy('我是複製的文字')
  }

輸入框的實用api

coerceBooleanProperty

輸入的值undefined/null/'false'/false 都為 false

export function coerceBooleanProperty(value: any): boolean {
  return value != null && `${value}` !== 'false';
}

undefined/null/'false'/false 都為 false

官網的案例
[disabled]=""  會傳遞的值就行分析
  @Input()
  get disabled() { return this._disabled; }
  set disabled(value: any) {
    this._disabled = coerceBooleanProperty(value);
  }
  private _disabled = false;

CoerceNumberProperty

輸入數字的限制

原始碼
export function coerceNumberProperty(value: any): number;
export function coerceNumberProperty<D>(value: any, fallback: D): number | D;
export function coerceNumberProperty(value: any, fallbackValue = 0) {
  return _isNumberValue(value) ? Number(value) : fallbackValue;
}
export function _isNumberValue(value: any): boolean {
  return !isNaN(parseFloat(value as any)) && !isNaN(Number(value));
}
// 當輸入不是數字,嘗試parseFloat轉換,然後判斷isNaN檢驗, 
// 如果不是使用預設值
CoerceNumberProperty('1.s',2)

NumberInput

export type BooleanInput = string | boolean | null | undefined;

BooleanInput

export type BooleanInput = string | boolean | null | undefined;

coerceElement

將ElementRef或Element強制轉換為element。

export function coerceElement<T>(elementOrRef: ElementRef<T> | T): T {
  return elementOrRef instanceof ElementRef ? elementOrRef.nativeElement : elementOrRef;
}

使用

  @ViewChild('aaa') aaa!: ElementRef<HTMLElement>;
// 結果一樣
    ngAfterViewInit() {
    console.log(this.aaa.nativeElement);
    console.log(coerceElement(this.aaa));
  }

SelectionModel

多選或者取消

<!--  hasValue 是否有值-->
<label nz-checkbox [nzChecked]="selection.hasValue() &&isAll()"
       [nzIndeterminate]="selection.hasValue()&&!isAll()" (nzCheckedChange)="allToggle()">全選</label>
<div *ngFor="let item of dataArr">
  <label nz-checkbox [(ngModel)]="item.checked" (ngModelChange)="selection.toggle(item.id)">{{item.id}}</label>
</div>
<button (click)="getArr()">查詢狀態</button>
export class ThreeComponent implements OnInit, OnDestroy {
// 多選框
  selection = new SelectionModel<Element>(true, [])
  // 資料
  // 全選或者不全選
  numBool = false;
  indeterminate = false;
  dataArr: Array<any> = [
    {id: 1, checked: false},
    {id: 2, checked: false},
    {id: 3, checked: false},
    {id: 4, checked: false},
  ]

  // 全選
  isAll() {
    const numSelected = this.selection.selected.length;
    const DateNum = this.dataArr.length;
    return numSelected === DateNum;
  }

  // 切換點選全選的
  allToggle(): void {
    if (this.isAll()) {
      this.selection.clear()
      this.dataArr.forEach(row => {
        row.checked = false;
      })
    } else {
      this.dataArr.forEach(row => {
        row.checked = true;
        this.selection.select(row.id)
      })
    }
  }
  getArr() {
    // 拿到查詢陣列
    console.log(this.selection.selected);
  }
}

cdkDrag 拖拽

demo1, 單個數組拖拽

<ul cdkDropList (cdkDropListDropped)="dropClick($event)">
  <li *ngFor="let item of textArr" cdkDrag>{{item.text}}</li>
</ul>

========================
textArr = [
    {text: '11111111111111'},
    {text: '22222222222222'},
    {text: '33333333333333'},
    {text: '44444444444444'},
    {text: '55555555555555'},
  ]

  dropClick($event: any) {
    moveItemInArray(this.textArr, $event.previousIndex, 		                           $event.currentIndex)
  }

自定義拖動預覽(cdkDragPreview)

<div cdkDropList  (cdkDropListDropped)="drop($event)">
  <div  *ngFor="let movie of movies" cdkDrag>
    {{movie.title}}
    <img *cdkDragPreview [src]="movie.poster" [alt]="movie.title">
  </div>
</div>
movies = [
    {
      title: 'Episode V - The Empire Strikes Back',
      poster: 'https://upload.wikimedia.org/wikipedia/en/3/3c/SW_-_Empire_Strikes_Back.jpg'
    },
    {
      title: 'Episode VI - Return of the Jedi',
      poster: 'https://upload.wikimedia.org/wikipedia/en/b/b2/ReturnOfTheJediPoster1983.jpg'
    },
    {
      title: 'Episode VII - The Force Awakens',
      poster: 'https://upload.wikimedia.org/wikipedia/en/a/a2/Star_Wars_The_Force_Awakens_Theatrical_Poster.jpg'
    },
    {
      title: 'Episode VIII - The Last Jedi',
      poster: 'https://upload.wikimedia.org/wikipedia/en/7/7f/Star_Wars_The_Last_Jedi.jpg'
    },
    {
      title: 'Episode IX – The Rise of Skywalker',
      poster: 'https://upload.wikimedia.org/wikipedia/en/a/af/Star_Wars_The_Rise_of_Skywalker_poster.jpg'
    }
  ];
  drop(event: CdkDragDrop<{title: string, poster: string}[]>) {
    moveItemInArray(this.movies, event.previousIndex, event.currentIndex);
  }

自定義拖動佔位符(*cdkDragPlaceholder)

<div cdkDropList (cdkDropListDropped)="drop($event)">
  <div *ngFor="let movie of movies" cdkDrag>
    <div *cdkDragPlaceholder style="width:20px;height: 20px;"></div>
    {{movie.title}}
    <!--    <img *cdkDragPreview [src]="movie.poster" [alt]="movie.title">-->
  </div>
</div>

設定方向

						水平				垂直
type DropListOrientation = 'horizontal' | 'vertical';
<div cdkDropList (cdkDropListDropped)="drop($event)" cdkDropListOrientation="horizontal" style="display: flex">
  <div *ngFor="let movie of movies" cdkDrag  style="width: 200px;">
    <div *cdkDragPlaceholder style="width:200px;"></div>
    {{movie.title}}
 </div>
</div>

限制範圍(cdkDragBoundary)

限制反向(cdkDragLockAxis)

<div class="aaa">
  <div class="bbb" cdkDrag cdkDragBoundary=".aaa"  cdkDragLockAxis = "x"></div>
</div>

demo2, 兩個陣列拖拽

<ul cdkDropList
    #aa="cdkDropList"
    [cdkDropListData]="textArr"
    [cdkDropListConnectedTo]="[bb]"
    (cdkDropListDropped)="dropClick($event)">
  <li *ngFor="let item of textArr" cdkDrag>{{item.text}}</li>
</ul>
<hr>
<ul cdkDropList
    #bb="cdkDropList"
    [cdkDropListData]="textArrTwo"
    [cdkDropListConnectedTo]="[aa]"
    (cdkDropListDropped)="dropClick($event)">
  <li *ngFor="let item of textArrTwo" cdkDrag>{{item.text}}</li>
</ul>
  textArr = [
    {text: '11111111111111'},
    {text: '22222222222222'},
    {text: '33333333333333'},
    {text: '44444444444444'},
    {text: '55555555555555'},
  ]
  textArrTwo = [
    {text: 'aaaaaaaaaaaaaa'},
    {text: 'bbbbbbbbbbbbbb'},
    {text: 'cccccccccccccc'},
    {text: 'eeeeeeeeeeeeee'},
    {text: 'ffffffffffffff'},
  ]
  dropClick(event: CdkDragDrop<any[]>) {
    if (event.previousContainer === event.container) {
      moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
    } else {
      transferArrayItem(event.previousContainer.data,
        event.container.data,
        event.previousIndex,
        event.currentIndex);
    }
  }

上面那種形式, 可以進行簡化

<div cdkDropListGroup>
  <ul cdkDropList
      [cdkDropListData]="textArr"
      (cdkDropListDropped)="dropClick($event)">
    <li *ngFor="let item of textArr" cdkDrag>{{item.text}}</li>
  </ul>
  <hr>
  <ul cdkDropList
      [cdkDropListData]="textArrTwo"
      (cdkDropListDropped)="dropClick($event)">
    <li *ngFor="let item of textArrTwo" cdkDrag>{{item.text}}</li>
  </ul>
</div>

手柄自定義拖動區域

<div class="aaa" cdkDrag>
  <div class="bbb" cdkDragHandle>點我</div>
</div>
.aaa{
  width: 200px;
  height: 200px;
  background-color: #783ce8;
  .bbb{
    width: 40px;
    height: 40px;
    background-color: #af0b0b;
  }
}

檢測螢幕的變化

export class ThreeComponent implements OnInit, OnDestroy {
  destroyed = new Subject<void>();
  constructor(private breakpoint:BreakpointObserver) {
    breakpoint.observe([
      // (max-width: 599.98px)
      Breakpoints.XSmall,
      // (min-width: 600px) and (max-width: 959.98px)
      Breakpoints.Small,
      // (min-width: 960px) and (max-width: 1279.98px)
      Breakpoints.Medium,
      // (min-width: 1280px) and (max-width: 1919.98px)
      Breakpoints.Large,
      // (min-width: 1920px)
      Breakpoints.XLarge,
    ]).pipe(takeUntil(this.destroyed)).subscribe(result=>{
      for (let [key,value] of Object.entries(result.breakpoints)){
        if(value){
          console.log(key);
        }
      }

    })
  }
  ngOnDestroy() {
    this.destroyed.next()
  }
}

檢查當前視口的大小

breakpointObserver.isMatched('(max-width: 599px)')

檢測ng-content 的內容發生變化

新增模組

import {ObserversModule} from '@angular/cdk/observers';

上一個小案例

<button (click)="clickNum()">Click++</button>
<app-six>
  <h1>{{num}}</h1>
</app-six>

  num=1;
  clickNum(){
    ++this.num
  }

<div (cdkObserveContent)="clickChanged()">
  <ng-content></ng-content>
</div>

  clickChanged() {
    console.log('執行了');
  }

彈框

demo1

<button (click)=" isOpen=!isOpen" cdkOverlayOrigin #box="cdkOverlayOrigin">Click 1</button>

<ng-template cdkConnectedOverlay [cdkConnectedOverlayOrigin]="box" [cdkConnectedOverlayOpen]="isOpen">
  <div>我是一個div</div>
</ng-template>

  isOpen = false;

使用新增彈框元件的形式

<button (click)="open1()">點選我</button>

export class ThreeComponent implements OnInit, OnDestroy {
  overlayRef!: OverlayRef;
  fileComponent!: ComponentPortal<SixComponent>;

  constructor(public overlay: Overlay,) {

  }

  isOpen = false;

  ngOnInit(): void {
    // 容器
    this.overlayRef = this.overlay.create()
    // 新增容器的元件
    this.fileComponent = new ComponentPortal(SixComponent);
    //新增最外層的class
    this.overlayRef.addPanelClass("aaaa");
  }

  open1() {
    this.isOpen = !this.isOpen;
    if (this.isOpen) {
      this.overlayRef.attach(this.fileComponent);
    } else {
      this.overlayRef.detach()
    }
  }

  ngOnDestroy() {
    this.overlayRef.dispose()
  }
}

可以用釋出訂閱的形式傳遞資料

決定自己的高度的是你的態度,而不是你的才能

記得我們是終身初學者和學習者

總有一天我也能成為大佬