使用Angular7的拖放功能创建一个ToDo应用程序

首先

由于我想体验Angular7的拖放功能,所以我先在ToDo应用中尝试了一下。拖放功能是通过CDK提供的,我将使用它。官方文档可以在https://material.angular.io/找到。

执行环境 zuò

    • Angular7

Angular6以前の場合はupdateしてください

这篇文章的内容 (Zhè de

    1. 创建项目

 

    1. 基本配置

 

    1. 实现ToDo功能

 

    1. 总结

 

    参考资料

创建项目

使用 Angular CLI 创建项目。
由于这次只需要最小配置,所以在选项中加上 minimal。
并且将应用名称设为 todo-app。

ng new todo-app --minimal

安装 Angular Material CDK 和 Animation。

npm install --save @angular/material @angular/cdk @angular/animations

通过使用ng add来设置AngularMaterial。

ng add的作用是设置AngularMaterial的安装。

使用`ng add `命令来指定包,并使用Schematics功能来展开模板。

ng add @angular/material

暂时确认启动

ng serve -o
スクリーンショット 2018-12-09 21.30.48.png

基本构成 –

由于这是一个小型应用程序,我们将直接在app.component.ts和app.component.ts中编写处理代码。因此,我们将在app.component.ts中添加OnInit。

import { Component, OnInit } from '@angular/core';
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  constructor() { }
  ngOnInit() {
  }
}

实现待办事项功能

在app.module.ts中导入material模块,顺便导入ReactiveFormsModule以便进行ToDo的输入。

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';

import { ReactiveFormsModule } from '@angular/forms'; // 入力フォーム用のモジュール

/* 今回使うmaterialのモジュール */
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; // 追加
import { MatButtonModule } from '@angular/material'; // 追加
import { MatInputModule } from '@angular/material/input'; // 追加
import { DragDropModule } from '@angular/cdk/drag-drop'; // 追加
import { MatCardModule } from '@angular/material/card'; // 追加

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    MatButtonModule,
    MatInputModule,
    ReactiveFormsModule,
    MatCardModule,
    DragDropModule,
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

我将创建一个待办事项列表的输入栏。

将app.component.html中的内容替换为以下源代码。

<div>
  <form class="example-form" [formGroup]="myForm">
    <mat-form-field class="example-full-width">
      <input formControlName="title" matInput placeholder="title">
    </mat-form-field>

    <mat-form-field class="example-full-width">
      <textarea formControlName="description" matInput placeholder="description"></textarea>
    </mat-form-field>
    <button mat-raised-button color="primary">登録</button>
  </form>
</div>

在app.component.ts中编写输入表单的处理代码。

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  constructor(private formBuilder: FormBuilder, ) { }
  myForm: FormGroup;
  todo = [];
  done = [];
  ngOnInit() {
    this.myForm = this.formBuilder.group({
      title: ['', [Validators.required]],
      description: ['', [Validators.required]]
    });
  }
  taskRegist() {
    console.log(this.myForm.value);
    this.todo.push({
      title: this.myForm.controls.title.value,
      description: this.myForm.controls.description.value,
    });
  }
}

我会打开应用程序来确认迄今为止的结果。

ng serve -o
スクリーンショット 2018-12-10 21.27.30.png

使用拖放功能,使输入表单可以自由移动。

使用cdkDrag指令为先前创建的输入表单添加一个包围的div。这样一来,输入表单就可以在屏幕上自由移动。

<div class="input-box" cdkDrag> <!-- ←追加部分 -->
    <form class="input-form" [formGroup]="myForm">
      <mat-form-field class="example-full-width">
        <input formControlName="title" matInput placeholder="タイトル">
      </mat-form-field>

      <mat-form-field class="example-full-width">
        <textarea formControlName="description" matInput placeholder="説明を入力"></textarea>
      </mat-form-field>
      <button mat-raised-button color="primary" (click)="taskRegist()" [disabled]="myForm.invalid">登録</button>
    </form>
</div> <!-- ←追加部分 -->
    • ドラッグを可能にするにはcdkDragディレクティブをタグに追加します。これだけでドラッグすることができます。

cdkDragディレクティブのみ付加した場合はページ内を自由に動かすことができます。

当设计完成后,将开始执行。
CSS参考了Angular Material的官方文档。

.input-form {
    min-width: 300px;
    max-width: 300px;
    width: 90%;
  }

.example-full-width {
    width: 90%;
}
.input-box {
    width: 300px;
    height: 300px;
    border: solid 1px #ccc;
    color: rgba(0, 0, 0, 0.87);
    cursor: move;
    display: flex;
    justify-content: center;
    align-items: center;
    text-align: center;
    background: #fff;
    border-radius: 4px;
    position: relative;
    z-index: 1;
    transition: box-shadow 200ms cubic-bezier(0, 0, 0.2, 1);
    box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2),
                0 2px 2px 0 rgba(0, 0, 0, 0.14),
                0 1px 5px 0 rgba(0, 0, 0, 0.12);
  }

打开应用并确认

ng serve -o

我认为您可以确认输入表单是可以被拖动的。

drag.gif

创建一个待办事项清单

请在先前创建的输入表单下方进行添加。

<div class="example-container">
  <h2>やること</h2>

  <div cdkDropList #todoList="cdkDropList" [cdkDropListData]="todo" [cdkDropListConnectedTo]="[doneList]" class="example-list"
    (cdkDropListDropped)="drop($event)">
    <div class="example-box" [cdkDragData]="item" *ngFor="let item of todo" cdkDrag>
      {{item.title}}
      <div *cdkDragPreview>
        <mat-card class="example-card">
          <mat-card-content>
            <div>{{item.title}}</div>
            <hr>
            <p>{{item.description}}</p>
          </mat-card-content>
        </mat-card>
      </div>
    </div>
  </div>
</div>

<div class="example-container">
  <h2>完了</h2>
  <div cdkDropList #doneList="cdkDropList" [cdkDropListData]="done" [cdkDropListConnectedTo]="[todoList]" class="example-list"
    (cdkDropListDropped)="drop($event)">
    <div class="example-box" [cdkDragData]="item" *ngFor="let item of done" cdkDrag>{{item.title}}</div>
  </div>
</div>

我们允许输入表单在屏幕内自由移动,但我们希望对ToDo列表进行排序。因此,我们将使用cdkDropList。
cdkDropList可以限制放置位置。这样一来,cdkDropList内的元素将自动排序。

#<id名>="cdkDropList"

这次我们还使用了cdkDropListData、cdkDropListDropped和cdkDropListConnectedTo等其他选项。

    • cdkDragData 、cdkDropListData

 

    • cdkDragDataに値を設定することで要素にデータをもたせることができます。

 

    • 今回のアプリの場合はdropイベントのevent.item.dataでデータにアクセスできます。

 

    • またデータを指定することで、ドロップ操作の発生元を特定するのに役立ちます。

 

    • cdkDropListDropped

 

    • ユーザーがドラッグを終了するとイベントが発生しデータモデルを更新します。またドラッグ中はデータモデルを更新しません。

 

    • cdkDropListConnectedTo

 

    • [cdkDropListConnectedTo]=”[id名]”でドロップ先のコンテナを設定できます。ドロップ先を制限したいときに使用する感じですね。

 

    • またcdkDropListGroup配下でcdkDropListConnectedToを設定しない場合は好きなコンテナにドロップすることができます。

 

    • cdkDragPreview

 

    cdkDragPreviewを付加することでドラッグ時のプレビューを作成することができます。

在app.component.ts中新增一个方法。

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { CdkDragDrop, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop'; // <------------追加
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  constructor(private formBuilder: FormBuilder, ) { }
  todo = [];
  done = [];
  myForm: FormGroup;

  ngOnInit() {
    this.myForm = this.formBuilder.group({
      title: ['', [Validators.required]],
      description: ['', [Validators.required]]
    });
  }
/*--------------以下追加分----------------------*/
/*
 * ドロップしたcdkDropListが同じなら場所を入れ替えます
 * cdkDropListが違う場合はアイテムを移します
 */
  drop(event: CdkDragDrop<string[]>) {
    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);
    }
  }
/*--------------------------------------*/ 

/*タスク登録用のメソッド*/
  taskRegist() {
    console.log(this.myForm.value);
    this.todo.push({
      title: this.myForm.controls.title.value,
      description: this.myForm.controls.description.value,
    });
  }

}

    • moveItemInArray

 

    • 同じコンテナ内で要素の場所を入れ替えるメソッドです

 

    • transferArrayItem

 

    • ターゲットのコンテナに要素を移動するメソッドです

 

    • copyArrayItem

 

    今回は使用していませんが、ターゲットのコンテナに要素をコピーするメソッドもあるそうです

到目前为止,功能的实现已经完成。接下来只需要调整布局。
将前面创建的CSS进行附加。

.example-card {
  max-width: 400px;
}
.example-container {
    width: 400px;
    max-width: 100%;
    margin: 0 25px 25px 0;
    display: inline-block;
    vertical-align: top;
  }

  .example-list {
    border: solid 1px #ccc;
    min-height: 60px;
    background: white;
    border-radius: 4px;
    overflow: hidden;
    display: block;
  }

  .example-box {
    padding: 20px 10px;
    border-bottom: solid 1px #ccc;
    color: rgba(0, 0, 0, 0.87);
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    box-sizing: border-box;
    cursor: move;
    background: white;
    font-size: 14px;
  }

  .cdk-drag-preview {
    box-sizing: border-box;
    border-radius: 4px;
    box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
                0 8px 10px 1px rgba(0, 0, 0, 0.14),
                0 3px 14px 2px rgba(0, 0, 0, 0.12);
  }

  .cdk-drag-placeholder {
    opacity: 0;
  }

  .cdk-drag-animating {
    transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
  }

  .example-box:last-child {
    border: none;
  }

  .example-list.cdk-drop-list-dragging .example-box:not(.cdk-drag-placeholder) {
    transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
  }

打开应用程序并确认

ng serve -o
マイムービー.mov.gif

总结

我对能够轻松实现拖放功能感到惊讶,比我想象中要简单得多。
由于Angular 7的升级还添加了其他功能,我也想去试试。
非常感谢您阅读到最后。

文献引用

Angular Material 是一种用于 Angular 框架的 UI 组件库。

广告
将在 10 秒后关闭
bannerAds