React - 使用三元在功能组件中应用 CSS class
React - Using ternary to apply CSS class in functional component
我对 React 比较陌生,正在开发 John Conway - Game of Life 应用程序。我为板本身构建了一个 Gameboard.js
功能组件(它是 App.js
的子组件)和一个 Square.js
功能组件,它代表板上的一个单独的正方形(并且是Gameboard
和 App
) 的孙子。
在 App
中,我有一个名为 alive
的函数,我想在用户单击它时更改单个方块的颜色。 App
的状态中还有一个 'alive' 属性 最初设置为 false,alive
将在调用时将 属性 更改为 true。
这是App.js
:
import React, { Component } from 'react';
import './App.css';
import GameBoard from './GameBoard.js';
import Controls from './Controls.js';
class App extends Component {
constructor(props){
super(props);
this.state = {
boardHeight: 50,
boardWidth: 30,
iterations: 10,
reset: false,
alive: false
};
}
selectBoardSize = (width, height) => {
this.setState({
boardHeight: height,
boardWidth: width
});
}
onReset = () => {
}
alive = () => {
this.setState({ alive: !this.state.alive });
console.log('Alive function has been called');
}
render() {
return (
<div className="container">
<h1>Conway's Game of Life</h1>
<GameBoard
height={this.state.boardHeight}
width={this.state.boardWidth}
alive={this.alive}
/>
<Controls
selectBoardSize={this.selectBoardSize}
iterations={this.state.iterations}
onReset={this.onReset}
/>
</div>
);
}
}
export default App;
Gameboard
看起来像这样并将 props.alive 传递给 Square
:
import React, { Component } from 'react';
import Square from './Square.js';
const GameBoard = (props) => {
return (
<div>
<table className="game-board">
<tbody>
{Array(props.height).fill(1).map((el, i) => {
return (
<tr key={i}>
{Array(props.width).fill(1).map((el, j) => {
return (
<Square key={j} alive={props.alive}/>
);
})}
</tr>
);
})}
</tbody>
</table>
</div>
);
}
export default GameBoard;
在我的 CSS 中,我有一个名为 active 的 class,如果单击它,它会更改单个方块的颜色。我怎样才能在 Square
中单击 td 元素时颜色发生变化(即 CSS classes 变为活动状态)?
我试过这个:
import React, { Component } from 'react';
const Square = (props) => {
return(
<td className={props.alive ? "active" : "inactive"} onClick={() => props.alive()}></td>
);
}
export default Square;
CSS 看起来像这样:
.Square {
background-color: #013243; //#24252a;
height: 12px;
width: 12px;
border: .1px solid rgba(236, 236, 236, .5);
overflow: none;
&:hover {
background-color: #48dbfb; //#00e640; //#2ecc71; //#39FF14;
}
}
.inactive {
background-color: #013243; //#24252a;
}
.active {
background-color: #48dbfb;
}
我怎样才能使 .Square CSS class 始终应用于每个方块,但如果它处于活动状态,则单个方块颜色会发生变化?换句话说,我可以将 Square
的 td 设置为始终使用 .Square CSS class 设置样式,然后 Square
中的各个元素可以根据是否适当着色在 App
的状态下 alive
是否为真?
是否有三元方法总是设置一个特定的 CSS class 然后另外设置 2 个中的第一个 classes....即Square CSS class 始终显示,并且根据 logic/state?
呈现活动或非活动状态
你可以这样做
return(
<td className={`Square ${props.alive ? "active" : "inactive"}`}
onClick={() => props.alive()}>
</td>
);
请参考这个code
评论有道理
您可以使用 template literal 并在其中嵌入三元条件:
return (
<td
className={`Square ${props.alive ? "active" : "inactive"}`}
onClick={() => props.alive()}
></td>
);
快速复习模板文字:使用反引号包裹字符串,您可以通过将其包裹在 ${}
模式中,在其中插入 JavaScript 表达式。作为奖励,模板文字可以跨越多行,因此不再有尴尬的字符串连接!
const myName = "Abraham Lincoln";
const myString = `Some text.
This text is on the next line but still in the literal.
Newlines are just fine.
Hello, my name is ${myName}.`;
编辑:我现在看到的更大问题是您没有在任何地方存储每个单元格的状态。您只有一个布尔值存储在 App
中,称为 alive
...您真正需要的是一个 array 布尔值,每个布尔值代表一个状态单身 Square
.
"alive" 个状态的数组应该位于 App
或 GameBoard
中,遵循 "the data flows down" 的 React 原则。在您的情况下,您可以尝试将其保留在 App
中,这样 GameBoard
和 Square
可以保留纯功能组件。
在 App
的内部,您可以在构造函数中创建一个新的二维数组 board
,并用初始值为 0
的子数组填充它:
// App.js
constructor(props){
super(props);
this.state = {
boardHeight: 50,
boardWidth: 30,
board: [],
iterations: 10,
reset: false,
};
this.state.board = new Array(this.state.boardHeight).fill(new Array(this.state.boardWidth).fill(0));
}
在board
数组中,每个索引代表一行。因此 [[0, 0, 1], [0, 1, 0], [1, 1, 1]]
的简化示例将表示:
0 0 1
0 1 0
1 1 1
GameBoard
应该完全基于传递给它的 board
道具渲染你的单元格网格,并将每个 Square
它的活动值和回调函数作为道具传递:
const GameBoard = (props) => {
return (
<div>
<table className="game-board">
<tbody>
{this.props.board.map((row, y) => {
return <tr key={y}>
{row.map((ea, x) => {
return (
<Square
key={x}
x={x}
y={y}
isAlive={ea}
aliveCallback={this.props.alive}
/>
);
})}
</tr>;
})}
</tbody>
</table>
</div>
);
}
从那里您应该能够看到这个应用程序是如何工作的。 App
存储游戏状态并渲染功能组件 GameBoard
。在GameBoard
中,每个Square
根据其alive值渲染,点击时触发一个aliveCallback
。 aliveCallback
应该根据其 x
和 y
prop.
在 App
内部的 board
数组中设置适当值的状态
标题问题不是'not working'
的真正原因
注意:此声明
className={props.alive ? "active" : "inactive"}
是正确的,不需要使用模板文字。
您可以通过多种方式write/use:
className={'Square '+ (props.alive ? 'active' : 'inactive')}
事实上,不需要使用 'inactive',因为 'Square' 具有相同的背景颜色。
className={'Square '+ (props.alive ? 'active' : null)}
事实上不需要三元运算符
className={'square '+ (props.alive && 'active')}
当然你可以在 return
之前在纯 js 中 'calculate/prepare' 值
const Square = (props) => {
let classes = ['Square','bb']
if( props.alive ) classes.push('active')
classes = classes.join(' ')
return (
<h1 className={classes}>Hello</h1>
)};
只需阅读 docs 或 google 以获得 'react css in js'。
我对 React 比较陌生,正在开发 John Conway - Game of Life 应用程序。我为板本身构建了一个 Gameboard.js
功能组件(它是 App.js
的子组件)和一个 Square.js
功能组件,它代表板上的一个单独的正方形(并且是Gameboard
和 App
) 的孙子。
在 App
中,我有一个名为 alive
的函数,我想在用户单击它时更改单个方块的颜色。 App
的状态中还有一个 'alive' 属性 最初设置为 false,alive
将在调用时将 属性 更改为 true。
这是App.js
:
import React, { Component } from 'react';
import './App.css';
import GameBoard from './GameBoard.js';
import Controls from './Controls.js';
class App extends Component {
constructor(props){
super(props);
this.state = {
boardHeight: 50,
boardWidth: 30,
iterations: 10,
reset: false,
alive: false
};
}
selectBoardSize = (width, height) => {
this.setState({
boardHeight: height,
boardWidth: width
});
}
onReset = () => {
}
alive = () => {
this.setState({ alive: !this.state.alive });
console.log('Alive function has been called');
}
render() {
return (
<div className="container">
<h1>Conway's Game of Life</h1>
<GameBoard
height={this.state.boardHeight}
width={this.state.boardWidth}
alive={this.alive}
/>
<Controls
selectBoardSize={this.selectBoardSize}
iterations={this.state.iterations}
onReset={this.onReset}
/>
</div>
);
}
}
export default App;
Gameboard
看起来像这样并将 props.alive 传递给 Square
:
import React, { Component } from 'react';
import Square from './Square.js';
const GameBoard = (props) => {
return (
<div>
<table className="game-board">
<tbody>
{Array(props.height).fill(1).map((el, i) => {
return (
<tr key={i}>
{Array(props.width).fill(1).map((el, j) => {
return (
<Square key={j} alive={props.alive}/>
);
})}
</tr>
);
})}
</tbody>
</table>
</div>
);
}
export default GameBoard;
在我的 CSS 中,我有一个名为 active 的 class,如果单击它,它会更改单个方块的颜色。我怎样才能在 Square
中单击 td 元素时颜色发生变化(即 CSS classes 变为活动状态)?
我试过这个:
import React, { Component } from 'react';
const Square = (props) => {
return(
<td className={props.alive ? "active" : "inactive"} onClick={() => props.alive()}></td>
);
}
export default Square;
CSS 看起来像这样:
.Square {
background-color: #013243; //#24252a;
height: 12px;
width: 12px;
border: .1px solid rgba(236, 236, 236, .5);
overflow: none;
&:hover {
background-color: #48dbfb; //#00e640; //#2ecc71; //#39FF14;
}
}
.inactive {
background-color: #013243; //#24252a;
}
.active {
background-color: #48dbfb;
}
我怎样才能使 .Square CSS class 始终应用于每个方块,但如果它处于活动状态,则单个方块颜色会发生变化?换句话说,我可以将 Square
的 td 设置为始终使用 .Square CSS class 设置样式,然后 Square
中的各个元素可以根据是否适当着色在 App
的状态下 alive
是否为真?
是否有三元方法总是设置一个特定的 CSS class 然后另外设置 2 个中的第一个 classes....即Square CSS class 始终显示,并且根据 logic/state?
呈现活动或非活动状态你可以这样做
return(
<td className={`Square ${props.alive ? "active" : "inactive"}`}
onClick={() => props.alive()}>
</td>
);
请参考这个code
评论有道理
您可以使用 template literal 并在其中嵌入三元条件:
return (
<td
className={`Square ${props.alive ? "active" : "inactive"}`}
onClick={() => props.alive()}
></td>
);
快速复习模板文字:使用反引号包裹字符串,您可以通过将其包裹在 ${}
模式中,在其中插入 JavaScript 表达式。作为奖励,模板文字可以跨越多行,因此不再有尴尬的字符串连接!
const myName = "Abraham Lincoln";
const myString = `Some text.
This text is on the next line but still in the literal.
Newlines are just fine.
Hello, my name is ${myName}.`;
编辑:我现在看到的更大问题是您没有在任何地方存储每个单元格的状态。您只有一个布尔值存储在 App
中,称为 alive
...您真正需要的是一个 array 布尔值,每个布尔值代表一个状态单身 Square
.
"alive" 个状态的数组应该位于 App
或 GameBoard
中,遵循 "the data flows down" 的 React 原则。在您的情况下,您可以尝试将其保留在 App
中,这样 GameBoard
和 Square
可以保留纯功能组件。
在 App
的内部,您可以在构造函数中创建一个新的二维数组 board
,并用初始值为 0
的子数组填充它:
// App.js
constructor(props){
super(props);
this.state = {
boardHeight: 50,
boardWidth: 30,
board: [],
iterations: 10,
reset: false,
};
this.state.board = new Array(this.state.boardHeight).fill(new Array(this.state.boardWidth).fill(0));
}
在board
数组中,每个索引代表一行。因此 [[0, 0, 1], [0, 1, 0], [1, 1, 1]]
的简化示例将表示:
0 0 1
0 1 0
1 1 1
GameBoard
应该完全基于传递给它的 board
道具渲染你的单元格网格,并将每个 Square
它的活动值和回调函数作为道具传递:
const GameBoard = (props) => {
return (
<div>
<table className="game-board">
<tbody>
{this.props.board.map((row, y) => {
return <tr key={y}>
{row.map((ea, x) => {
return (
<Square
key={x}
x={x}
y={y}
isAlive={ea}
aliveCallback={this.props.alive}
/>
);
})}
</tr>;
})}
</tbody>
</table>
</div>
);
}
从那里您应该能够看到这个应用程序是如何工作的。 App
存储游戏状态并渲染功能组件 GameBoard
。在GameBoard
中,每个Square
根据其alive值渲染,点击时触发一个aliveCallback
。 aliveCallback
应该根据其 x
和 y
prop.
App
内部的 board
数组中设置适当值的状态
标题问题不是'not working'
的真正原因注意:此声明
className={props.alive ? "active" : "inactive"}
是正确的,不需要使用模板文字。
您可以通过多种方式write/use:
className={'Square '+ (props.alive ? 'active' : 'inactive')}
事实上,不需要使用 'inactive',因为 'Square' 具有相同的背景颜色。
className={'Square '+ (props.alive ? 'active' : null)}
事实上不需要三元运算符
className={'square '+ (props.alive && 'active')}
当然你可以在 return
之前在纯 js 中 'calculate/prepare' 值const Square = (props) => {
let classes = ['Square','bb']
if( props.alive ) classes.push('active')
classes = classes.join(' ')
return (
<h1 className={classes}>Hello</h1>
)};
只需阅读 docs 或 google 以获得 'react css in js'。