1

我从某人那里继承了一些代码,但我遇到了一个奇怪的问题,无法弄清楚。我有一个屏幕,显示 9 个抽认卡的网格 - 随机选择 - 单击时应该翻转并显示一个单词(它用于教孩子单词)。

在按下刷新按钮之前它工作正常,它应该选择一组不同的随机九张牌。这样做没问题,但是点击后卡片不再翻转。

似乎抽认卡组件正在“发出”点击事件,但在“刷新”操作之后,新生成的“抽认卡”似乎没有在监听。

任何人都知道出了什么问题以及我该如何解决?谢谢!

代码由页面 (flashcards.component.html) 组成:

    <ion-toolbar>
        <ion-button (click)="refreshCards()" color="primary" expand="block" fill="solid" id="refresh">Refresh
        </ion-button>
    </ion-toolbar>

  <div class="app-flash-card-grid">
        <!-- flashCardsSelection has the random selection of cards -->
        <!-- generate each flippable card -->
        <flashCard class="app-flash-card" *ngFor="let flashCards of flashCardsSelection; let i = index">

            <div class="flash-card-front">
                <img alt="{{flashCards.name}}" src="{{flashCards.filename}}">
            </div>

            <div class="flash-card-back">
                <h1>{{flashCards.name}}</h1>
            </div>

        </flashCard>
    </div>

在 flashcards.component.ts 中:

 refreshCards() {
        let fcardindex = 0;
        let x = 0;

        // clear selection
        for (fcardindex = 0; fcardindex < 9; fcardindex++) {
            this.flashCardsSelection.pop();
        }

        // populate selection
        for (fcardindex = 0; fcardindex < 9; fcardindex++) {
            const wordlistsize = this.flashCardsArray.length;

            x = Math.round((Math.random() * 100) * wordlistsize / 100);
            console.log('x=' + x);
            if (this.categoryfilter.length > 0) {
                // check the category filter
                if (this.categoryfilter.indexOf(this.flashCardsArray[x].category) == -1) {
                    // not filtered
                    console.log('not filtered');

                    // check for duplicates
                    // is this one already in the selection array?

                    if (this.selectionContains(this.flashCardsSelection, this.flashCardsArray[x].name)) {
                        console.log('dupe found');
                        // if so, decrement the index and go again
                        fcardindex = fcardindex - 1;
                    } else {
                        // if not, add it
                        console.log('no dupe, adding');
                        this.flashCardsSelection.push((this.flashCardsArray)[x]);
                    }
                } else {
                    // filtered out, so decrement index and go again
                    // console.log('category filtered!');
                    fcardindex = fcardindex - 1;
                }
            } else {
                // no filter defined
                // console.log('no filter defined, adding');
                this.flashCardsSelection.push((this.flashCardsArray)[x]);
            }
        }
    }

和 flashcards.component.scss 文件:

.flip-grid {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;

  .flip-item {
    display: flex;
    width: 50%;
    justify-content: center;
    align-items: center;

    .panel {
      float: left;
      width: 45vmin;
      height: 45vmin;
      margin: 8px;
      position: relative;
      font-size: .8em;
      -webkit-perspective: 600px;
      perspective: 600px;
      display: block;
      @media(min-width: 768px) {
        width: 32vmin;
        height: 32vmin;
      }

      @media(min-width: 1024px) {
        width: 24.5vmin;
        height: 24.5vmin;
      }

      .front {
        float: none;
        position: absolute;
        top: 0;
        left: 0;
        z-index: 900;
        width: inherit;
        height: inherit;
        border: 1px solid #ccc;
        background: #6b7077;
        text-align: center;
        -webkit-transform: rotateX(0) rotateY(0);
        transform: rotateX(0) rotateY(0);
        -webkit-transform-style: preserve-3d;
        transform-style: preserve-3d;
        -webkit-backface-visibility: hidden;
        backface-visibility: hidden;
        -webkit-transition: all .4s ease-in-out;
        transition: all .4s ease-in-out;
      }

      &.flip {

        .front {
          z-index: 900;
          //    border-color: #eee;
          background: #333;
          box-shadow: 0 15px 50px rgba(0, 0, 0, 0.2);
          -webkit-transform: rotateY(179deg);
          transform: rotateY(179deg);
        }

        .back {
          z-index: 1000;
          background: #4c8dff;
          -webkit-transform: rotateX(0) rotateY(0);
          transform: rotateX(0) rotateY(0);
        }

      }

      .back {
        float: none;
        position: absolute;
        top: 0;
        left: 0;
        z-index: 800;
        //width: inherit;
        //height: inherit;
        // border: 1px solid #ccc;
        background: #4c8dff;
        color: #fff;
        -webkit-transform: rotateY(-179deg);
        transform: rotateY(-179deg);
        -webkit-transform-style: preserve-3d;
        transform-style: preserve-3d;
        -webkit-backface-visibility: hidden;
        backface-visibility: hidden;
        -webkit-transition: all .4s ease-in-out;
        transition: all .4s ease-in-out;
        display: flex;
        width: 100%;
        height: 100%;
        align-items: center;
        justify-content: center;

        h1 {
          margin: 0;
          font-size: 18px;
          text-transform: capitalize;
        }
      }
    }
  }
}

.app-flash-card-grid {
  display: flex;
  flex-wrap: wrap;

  .app-flash-card {
    @media screen and (min-width: "768px") {
      max-width: 33.33%;
    }
    max-width: 50%;
    width: 100%;
    padding: 8px;

    .flash-card-back {
      h1 {
        margin: 0;
        font-size: 18px;
        text-transform: capitalize;
        color: #fff;
      }
    }
  }
}

.pos-center {
  margin: auto;
  display: block;
}

.sc-ion-buttons-md-h {
  width: 85px;
  justify-content: flex-end;
}


.flipper {
  transition: 0.6s;
  transform-style: preserve-3d;
  position: relative;
  //border: 1px solid #000;
  &:after {
    content: "";
    display: block;
    padding-bottom: 100%;
  }

  .front, .back {
    display: flex;
    align-items: center;
    justify-content: center;
    backface-visibility: hidden;
    margin: 0;
    position: absolute;
    top: 0;
    left: 0;
    height: calc(100% + 3px);
  }

  .front {
    z-index: 2;
    transform: rotateY(0deg);
  }

  .back {
    transform: rotateY(180deg);
    background: #4c8dff;

    h1 {
      margin: 0;
      font-size: 18px;
      text-transform: capitalize;
      color: #fff;
    }
  }

}

闪存卡grid.component.html:

<ng-content></ng-content>

闪存卡grid.component.ts:

import {AfterContentInit, AfterViewInit, Component, ContentChildren, OnChanges, QueryList} from '@angular/core';
import {FlashCardComponent} from '../flash-card/flash-card.component';


@Component({
    selector: '.app-flash-card-grid',
    templateUrl: './flash-card-grid.component.html',
    styleUrls: ['./flash-card-grid.component.scss'],
})
export class FlashCardGridComponent implements AfterViewInit, OnChanges, AfterContentInit {

    @ContentChildren(FlashCardComponent)
    groups: QueryList<FlashCardComponent>;

    ngAfterViewInit() {
        console.log('Inside FlashCardGridComponent:ngAfterViewInit');
        // this.groups.toArray()[0].flipped = true;
        this.groups.toArray().forEach((t) => {
            t.flip.subscribe(() => {
                this.openGroup(t);
            });
        });
    }

    ngAfterContentInit() {

    }

    openGroup(flashCard) {
        // toggle flipped status
        if (flashCard.flipped == true) {
            flashCard.flipped = false;
        } else {
            this.groups.toArray().forEach((t) => t.flipped = false);
            flashCard.flipped = true;
        }
    }
}

和抽认卡组件本身(flash-card.component.html)

<div class="flip-container" (click)="emitflip()" [class.flipped]="flipped">
    <div class="flipper">
        <div class="front">
            <ng-content select=".flash-card-front"></ng-content>
        </div>
        <div class="back">
            <ng-content select=".flash-card-back"></ng-content>
        </div>
    </div>
</div>

和闪存卡组件.ts:

import {Component, Input, Output, EventEmitter} from '@angular/core';

@Component({
  selector: 'flashCard',
  templateUrl: './flash-card.component.html',
  styleUrls: ['./flash-card.component.scss'],
})

export class FlashCardComponent  implements OnInit {

  @Input() flipped = false;
  @Output() flip: EventEmitter<any> = new EventEmitter<any>();

  emitflip() {
    console.log('emit');
    this.flip.emit();
  }

}

最后是闪存卡组件.scss:

.flip-container {
  perspective: 1000px;
}

.flip-container.flipped .flipper {
  transform: rotateY(180deg);
}

.flip-container, .front, .back {
  width: 100%;
}

.flipper {
  transition: 0.6s;
  transform-style: preserve-3d;
  position: relative;
  border: 1px solid #dee2e3;
    &:after{
        content: "";
        display: block;
        padding-bottom: 100%;
    }

  .front, .back {
    display: flex;
    align-items: center;
    justify-content: center;
    backface-visibility: hidden;
    margin: 0;
    position: absolute;
    top: 0;
    left: 0;
    height: calc(100% + 4px);
  }

  .front {
    z-index: 2;
    transform: rotateY(0deg);
  }

  .back {
    transform: rotateY(180deg);
    background: #4c8dff;
    h1{
        margin: 0;
        font-size: 18px;
        text-transform: capitalize;
        color: #fff;
    }
  }
}
4

1 回答 1

0

在这里您可能会找到您要查找的内容: Mat-Button click inside a *ngFor with let index = index does not react/fire action

基本上你需要通知 Angular 如何在*ngFor. 由于您的refresh()方法将修改您在模板中迭代的数据集,因此 Angular 将丢失它的引用。

它可能看起来像这样:

<div *ngFor="let value of values; trackBy: index">
  • index由 Angular 预定义,是当前的迭代次数

您需要trackBy*ngFor操作中使用并提供元素的 id 或索引。我有一个例子给你如何做到这一点:

https://stackblitz.com/edit/angular-form-array-example-test123-2jzdij

任何反馈都会非常感激!

于 2020-01-31T14:48:28.120 回答