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()
  }
}

可以用发布订阅的形式传递数据

posted @ 2021-07-18 17:39  猫神甜辣酱  阅读(409)  评论(0编辑  收藏  举报