我想做一个交互式座位图,如果你点击座位,它就会改变颜色。我找到了一些解决方案,但他们没有工作。
我有一个SVG元素。我想让黑色的矩形在被点击时变成红色。
<g>
<rect [style.color]="toggleColor()" (click)="toggleStyle = !toggleStyle;" id="2a" x="90.714" y="65.012" width="27.97" height="30.994"/>
</g>
组件中的代码如下。
public toggleStyle: boolean = false;
toggleColor() {
console.log("does it work?")
if (this.toggleStyle) {
return "red";
} else {
return "";
}
}
}
正如你在stackblitz上看到的那样--这并没有给矩形添加颜色。此外,由于它是元素的一部分,该函数运行了两次。
谢谢你对如何解决这个问题的任何建议!我想做一个交互式座位地图,如果你点击座位,它就会改变颜色。
因为这是一个座位选择,更好的方法是定义一个对象数组,用 x
, y
和 selected
属性,就可以直接在模板中切换,而无需使用任何事件处理程序。然后,它可以直接在模板中切换,而无需使用任何事件处理程序。请尝试下面的方法
控制器
export class ClickSVGComponent implements OnInit {
public seats: Array<Array<{x: number, y: number, selected: boolean}>> = [];
range = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
public toggleStyle: boolean = false;
constructor() {
for (let i = 0; i < 10; i++) {
this.seats[i] = [];
for (let j = 0; j < 10; j++) {
this.seats[i].push({x: (i * 10), y: (j * 10), selected: false});
}
}
}
ngOnInit() {
}
}
模板
<svg width="210mm" height="297mm" version="1.1" viewBox="0 0 210 297" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<g>
<ng-container *ngFor="let i of range">
<ng-container *ngFor="let j of range">
<rect
[attr.fill]="seats[i][j].selected ? 'red': ''" <!-- use ternary operator to set the fill value -->
id="{{i}}{{j}}a"
[attr.x]="seats[i][j].x"
[attr.y]="seats[i][j].y"
width="8"
height="8"
(click)="seats[i][j].selected = !seats[i][j].selected"
/>
</ng-container>
</ng-container>
</g>
</svg>
我已经修改了你的 叠加闪电战
我改变了对象结构,引入了一个叫 maxSelected
boolean,表示是否达到了最大选择数。检查条件的多个数组 map
s和一个数组 concat
是应用在 counter()
点击事件的事件处理程序。
理解它的最快方法是剖析条件并观察每个语句的输出。这是一个相当直接的条件,写成一条语句。
模板也是针对条件进行调整的。我们需要允许重选,如果 maxReached
又被设置为 false
.
控制器
import { Component, OnInit } from '@angular/core';
export const MAX_SELECTION = 9; // <-- max no. of seats allowed to select
interface Seats { // <-- a collection of seats
maxReached: boolean,
attr: Array<Array<Attribute>> // array of array - `x` denotes the row, `y` denotes the column
}
interface Attribute { // <-- properties of each seat
x: number,
y: number,
selected: boolean
}
@Component({
selector: 'app-click-svg',
templateUrl: './click-svg.component.html',
styleUrls: ['./click-svg.component.css']
})
export class ClickSVGComponent implements OnInit {
public seats: Seats = {maxReached: false, attr: []};
range = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
public toggleStyle: boolean = false;
constructor() {
for (let i = 0; i < 10; i++) { // <-- loop through row of seats
this.seats.attr[i] = []; // <-- each row is initially empty
for (let j = 0; j < 10; j++) { // <-- loop through each seat of the row
this.seats.attr[i].push({x: (i * 10), y: (j * 10), selected: false});
// ^ ^ ^
// | | |
// use row value to set x --- | |
// use coloum value to set y coord. ------- |
// by default the seat is not selected ----------------
}
}
}
ngOnInit() {
}
counter() {
/*
Do the following to understand what each statement does
const seatsAll = this.seats.attr.map(row => {
console.log('row': row)
row.map(seat => {
console.log('seat': seat);
seat.selected;
})
})
console.log('all seats': seatsAll);
const seatsSelectedConcat = [].concat.apply([], seatsAll);
console.log('all seats single array': seatsSelectedConcat);
const seatsSelectedTrue = seatsSelectedConcat.filter(status => status);
console.log('all seats single array': seatsSelectedTrue);
*/
const selected = (
[].concat.apply([], ( // <-- output (Array(100)): [true, false, true, false, true,...]
this.seats.attr.map( // <-- output (Array<Array(10)>(10)): [[true, false...], [false, true,...], ...]
row => row.map(
seat => seat.selected // <-- output (Array(10)): [true, false, true...]
)
)
))
)
.filter(status => status) // <-- output only true: [true, true, true]
.length; // <-- number of seats selected
if (selected === MAX_SELECTION) {
this.seats.maxReached = true;
} else {
this.seats.maxReached = false;
}
}
}
模板
<p>
Please select a maximum of 9 seats. <br>
<span style="color: red" *ngIf="seats.maxReached">
Maximum number of seats selected.
</span>
</p>
<svg width="210mm" height="297mm" version="1.1" viewBox="0 0 210 297" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<g>
<ng-container *ngFor="let i of range"> <!-- same loop as the controller - row -->
<ng-container *ngFor="let j of range"> <!-- column -->
<rect
[attr.fill]="seats.attr[i][j].selected ? 'red': ''"
id="{{i}}{{j}}a"
[attr.x]="seats.attr[i][j].x"
[attr.y]="seats.attr[i][j].y"
width="8"
height="8"
(click)="
seats.attr[i][j].selected ?
seats.attr[i][j].selected = !seats.attr[i][j].selected : <!-- if seat selected already deselect it -->
!seats.maxReached ?
seats.attr[i][j].selected = !seats.attr[i][j].selected : <!-- selected unselected seat only if max condition `false` -->
''; <!-- don't select the seat if max condition `true` -->
counter()"
/>
</ng-container>
</ng-container>
</g>
</svg>
更新 叠加闪电战
你必须使用 fill
来改变一个svg矩形的颜色。
<rect [style.fill]="toggleColor()" (click)="toggleStyle = !toggleStyle;"></rect>
你也可以使用属性绑定。
<rect [attr.fill]="toggleColor()" (click)="toggleStyle = !toggleStyle;"></rect>
属性绑定不起作用,因为svg的属性并不反映在元素上的属性上,所以svg的绑定发生在元素上。[attr.*]
记法
你也可以考虑设置一个属性,而不是调用一个函数来获取当前的颜色。之所以要调用两次函数,是因为angular在开发模式下运行,并进行了两次变化检测的调用,以确保第一轮之后没有任何变化