如何为元素添加新类?

时间:2018-10-06 03:00:35

标签: javascript reactjs

针对问题5遍历https://reactjs.org/tutorial/tutorial.html#wrapping-up中的基础教程

5. When someone wins, highlight the three squares that caused the win.

我希望添加一个新类来突出显示正方形。

class Gamerender()

...
if(winner){
  status = 'Winner: '+ winner;
} else{
  status = 'Next player: '+ (this.state.xIsNext ? 'X' : 'O');
}
...

我添加了:

if(winner){
  status = 'Winner: '+ winner;
  this.highlight_win(this.state.positions);  <----- Added this line
} else{
  status = 'Next player: '+ (this.state.xIsNext ? 'X' : 'O');
}

以及:

highlight_win(positions){
  console.log(positions);
  return;
}

如何使highlight_win()用特定的键向按钮<Square>添加新类?我猜想传递的参数可能不正确。

[编辑]

我已将代码放入https://github.com/maan81/reactjs

3 个答案:

答案 0 :(得分:1)

  1. highlight_win应该通过更改父(祖先)控件中的道具或更改给定控件的状态来触发重新渲染

  2. 必须有一个属性(处于给定控件或来自父控件的props的状态),您可以从中推断出元素的类名

  3. 在控件的render方法内部,您需要检查该属性并计算该属性的类名称,并将其用作className组件中某处的Square属性

答案 1 :(得分:0)

这是一种实现方法:calculateWinner函数具有确定哪些行是赢家所需要的。只需将获胜的symbolrow存储到一个对象即可。游戏的render方法将此结果存储到winner,然后将其向下传递到<Board />。董事会的renderSquare方法然后确定winningRow数组(例如:[0,1,2])是否包含i(0,1,2,3,4,5,6,7,8 )。如果i是匹配项,它将boolean的结果存储到winningSquare,然后将其向下传递到<Square />。然后,如果classNameclassName="square",Square的className="square winner"winningSquare变为true

工作示例:https://codesandbox.io/s/pkp7oxrnoj

Game.js

import React, { Component } from "react";
import Board from "./Board";
import CalcWinner from "./calcWinner";
import ShowHistory from "./showHistory";

export default class Game extends Component {
  state = {
    history: [
      {
        squares: Array(9).fill(null)
      }
    ],
    stepNumber: 0,
    xIsNext: true
  };

  clearHistory = () => {
    this.setState({
      history: [
        {
          squares: Array(9).fill(null)
        }
      ],
      stepNumber: 0,
      xIsNext: true
    });
  };

  handleClick = i => {
    const history = this.state.history.slice(0, this.state.stepNumber + 1);
    const current = history[history.length - 1];
    const squares = current.squares.slice();
    if (CalcWinner(squares) || squares[i]) {
      return;
    }
    squares[i] = this.state.xIsNext ? "X" : "O";
    this.setState({
      history: history.concat([
        {
          squares: squares
        }
      ]),
      stepNumber: history.length,
      xIsNext: !this.state.xIsNext
    });
  };

  jumpTo = step =>
    this.setState({
      stepNumber: step,
      xIsNext: step % 2 === 0
    });

  render = () => {
    const { history, xIsNext } = this.state;
    const current = history[this.state.stepNumber];
    const winner = CalcWinner(current.squares);
    const status = winner
      ? `Winner: ${winner.symbol}`
      : `Next player: ${xIsNext ? "X" : "O"}`;

    return (
      <div className="container">
        <h1>Tic Tac Toe</h1>
        <div className="game">
          <div className="game-board">
            <Board
              winningRow={winner ? winner.row : null}
              squares={current.squares}
              onClick={i => this.handleClick(i)}
            />
          </div>
        </div>
        <div className="game-info">
          <div>{status}</div>
          <ShowHistory
            clearHistory={this.clearHistory}
            history={history}
            winner={winner && winner.symbol ? true : false}
            jumpTo={this.jumpTo}
          />
        </div>
      </div>
    );
  };
}

Board.js

import React, { PureComponent } from "react";
import Square from "./square";

export default class Board extends PureComponent {
  renderSquare = i => {
    const { winningRow } = this.props;
    const winningSquare = winningRow && winningRow.includes(i) ? true : false;
    return (
      <Square
        winningSquare={winningSquare}
        value={this.props.squares[i]}
        onClick={() => this.props.onClick(i)}
      />
    );
  };

  render = () => {
    return (
      <div>
        <div className="board-row">
          {this.renderSquare(0)}
          {this.renderSquare(1)}
          {this.renderSquare(2)}
        </div>
        <div className="board-row">
          {this.renderSquare(3)}
          {this.renderSquare(4)}
          {this.renderSquare(5)}
        </div>
        <div className="board-row">
          {this.renderSquare(6)}
          {this.renderSquare(7)}
          {this.renderSquare(8)}
        </div>
      </div>
    );
  };
}

calcWinner.js

export default squares => {
  const lines = [
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],
    [0, 4, 8],
    [2, 4, 6]
  ];
  for (let i = 0; i < lines.length; i++) {
    const [a, b, c] = lines[i];
    if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
      return { symbol: squares[a], row: [a, b, c] };
    }
  }
  return null;
};

showHistory.js

import map from "lodash/map";
import React from "react";

export default ({ clearHistory, history, jumpTo, winner }) => (
  <ol className="history">
    {map(history, (step, move) => {
      const desc = move ? `Go to move #${move}` : "Go to game start";
      return (
        <li key={move}>
          <button
            style={{ width: 185, marginBottom: 10 }}
            className="uk-button uk-button-primary uk-button-small"
            onClick={() => jumpTo(move)}
          >
            {desc}
          </button>
        </li>
      );
    })}
    {winner && (
      <button
        style={{ width: 185 }}
        className="uk-button uk-button-danger uk-button-small"
        onClick={clearHistory}
      >
        Clear Board
      </button>
    )}
  </ol>
);

square.js

import React from "react";

export default ({ onClick, value, winningSquare }) => (
  <button
    className={`square ${winningSquare ? "winner" : ""}`}
    onClick={onClick}
  >
    {value}
  </button>
);

答案 2 :(得分:0)

我认为这就是您所需要的。运行代码片段,告诉我是否正确? :)我所做的是创建一个具有{strong> green CSS属性的background类,并动态显示如果我们有 获胜者 ,则某个条件最终将成为true。只要该条件为假,就不会应用任何类。

{props.winning ? 'winning-square' : ''}

function Square(props) {   
  return (
    <button className={`square ${props.winning ? 'winning-square' : ''}`} onClick={() => props.onClick()}>
      { props.value }
    </button>
  );
}

class Board extends React.Component {
  
  renderSquare(i, winning) {
    return <Square key={i} value={this.props.squares[i]} onClick={() => this.props.onClick(i)} winning={winning}/>;
  }
  
  render() {
    let rows = [];
    let squares = [];
    for (var row=0; row<3; row++) {
      for (var index=row*3; index<row*3+3; index++) {
        
        let winning = false;
        const winningLine = this.props.winningLine;
        if (winningLine) {
          for (var i=0; i<winningLine.length; i++) {
            if (winningLine[i] == index)
              winning = true;
          }
        }
        
        squares.push(this.renderSquare(index, winning));
      }    
      rows.push(<div key={row} className="board-row">{squares}</div>);
      squares = [];
    }
    
    return <div> {rows} </div>;
    
  }
}

class Game extends React.Component {
  constructor() {
    super();
    this.state = {
      history: [{
        squares: Array(9).fill(null)
      }],
      xIsNext: true,
      stepNumber: 0
    };
  }
  handleClick(i) {
    
    const history = this.state.history.slice(0, this.state.stepNumber + 1);
    
    const newest = history[history.length - 1];
    const newestSquares = newest.squares.slice();
    
    if (calculateWinner(newestSquares) || newestSquares[i]) {
      return;
    }
    
    const current = history[this.state.stepNumber];
    const squares = current.squares.slice();
    
    if (calculateWinner(squares) || squares[i]) {
      return;
    }

    const sign = this.state.xIsNext ? 'X' : '0';
    squares[i] = sign;
    
    this.setState({
      history: history.concat([{
        squares: squares,
        selected: {
          row: i % 3 + 1,
          col: Math.floor(i / 3) + 1,
          sign: sign
        },
      }]),
      xIsNext: !this.state.xIsNext,
      stepNumber: history.length,
    });
    
  }
  
  jumpTo(step) {
    this.setState({
      stepNumber: step,
      xIsNext: (step % 2) ? false : true,
    });  
  }
  
  render() {
    
    const history = this.state.history;
    const stepNumber = this.state.stepNumber;
    const current = history[this.state.stepNumber];
    const winner = calculateWinner(current.squares);
    
    let status;
    let winningLine;
    if (winner) {
      status = 'Winner: ' + winner.sign;
      winningLine = winner.line;
    } else {
      status = 'Next player: ' + (this.state.xIsNext ? 'X' : '0');
    }
    
    const moves = history.map((step, move) => {            
      
      const desc = move ? 
            'Move ' + step.selected.sign + ' (' + step.selected.row + ',' + step.selected.col + ')':
            'Game start';
      
      const currentlySelected = (move == stepNumber);
                                 
      return (
        <li key={move}>
          <a href="#" onClick={() => this.jumpTo(move)} className={currentlySelected ? 'selectedMove' : ''}>
            {desc}
          </a>
        </li>
      );      
    });
    
    return (
      <div className="game">
        <div className="game-board">
          <Board squares={current.squares} winningLine={winningLine} onClick={(i) => this.handleClick(i)} />
        </div>
        <div className="game-info">
          <div>{status}</div>
          <ul>{moves}</ul>
        </div>
      </div>
    );
  }
}

ReactDOM.render(
  <Game />,
  document.getElementById('container')
);

function calculateWinner(squares) {
  const lines = [
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],
    [0, 4, 8],
    [2, 4, 6],
  ];
  for (let i = 0; i < lines.length; i++) {
    const [a, b, c] = lines[i];
    if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
      return {
        sign: squares[a],
        line: lines[i]
      }
    }
  }
  return null;
}
body {
  font: 14px "Cursive", Futura, sans-serif;
  margin: 20px;
}

ol, ul {
  padding-left: 30px;
}

li a.selectedMove {
  font-weight: bold;
}

.board-row:after {
  clear: both;
  content: "";
  display: table;
}

.status {
  margin-bottom: 10px;
}

.square {
  background: #fff;
  border: 1px solid #999;
  float: left;
  font-size: 24px;
  font-weight: bold;
  line-height: 34px;
  height: 34px;
  margin-right: -1px;
  margin-top: -1px;
  padding: 0;
  text-align: center;
  width: 34px;
}

.square:focus {
  outline: none;
}

.kbd-navigation .square:focus {
  background: #ddd;
}

.game {
  display: flex;
  flex-direction: row;
}

.game-info {
  margin-left: 20px;
}

ul {
  list-style: none;
}

div {
  color: green;
  font-weight: bold;
  letter-spacing: 2px;
}

.winning-square {
  background-color: green;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id="container"></div>