我从某人那里继承了一些代码,我遇到了一个奇怪的问题,无法弄清楚。 我有一个屏幕,显示一个由 9 张抽认卡组成的网格 - 随机选择 - 点击时应该翻转并显示一个单词(用于教孩子单词(。
在按下"刷新"按钮之前,它工作正常,该按钮应选择一组不同的随机九张牌。它可以正常工作,但是单击时卡片不再翻转。
抽认卡组件似乎正在"发出"单击事件,但在"刷新"操作之后,新铸造的"抽认卡"似乎没有侦听。
任何人都知道出了什么问题以及如何解决它?谢谢!
代码由页面(抽认卡.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>
在抽认卡中:
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]);
}
}
}
和抽认卡.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;
}
}
}
flash-card-grid.component.html:
<ng-content></ng-content>
flash-card-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;
}
}
}
在这里,您可能会找到所需的内容: 垫子按钮在 *ngFor 内单击,让索引 = 索引不反应/触发操作
基本上,您需要通知Angular如何在*ngFor
中跟踪对象。由于您的refresh()
方法将修改您在模板中迭代的数据集,因此 Angular 将丢失其引用。
它可能看起来像这样:
<div *ngFor="let value of values; trackBy: index">
index
由 Angular 预定义,是当前的迭代编号
您需要在*ngFor
操作中使用trackBy
并提供元素的 id 或索引。我有一个示例供您操作:
https://stackblitz.com/edit/angular-form-array-example-test123-2jzdij
任何反馈将非常感激!