В предыдущем посте, где я обсуждал, как нарисовать шахматную доску с помощью CSS flexbox, я упомянул, что хотел бы включить имена строк и столбцов в пользовательский интерфейс, и в идеале я сделал бы это с помощью CSS Макет сетки". Ну, я только что сделал это сегодня! Вы можете проверить последнюю версию моей шахматной доски на «https://css-chess-board.netlify.app/.
Ниже приведены 2 ключевых изменения, которые я внес в шахматную доску.
Добавление имен строк и столбцов с использованием макета сетки CSS
Этот коммит имеет все соответствующие изменения.
Сначала я создал .chess-board
div
сетку с 10 столбцами и 10 строками, используя приведенный ниже код CSS.
.chess-board { display: grid; grid-template: repeat(10, $cell-size) / repeat(10, $cell-size) ; }
Вы спросите, почему 10 строк и 10 столбцов? Потому что я хочу структурировать сетку следующим образом.
| a b c d e f g h | -------------------------------- 8 | R N B Q K B N R | 8 7 | P P P P P P P P | 7 6 | | 6 5 | | 5 4 | | 4 3 | | 3 2 | P P P P P P P P | 2 1 | R N B Q K B N R | 1 -------------------------------- | a b c d e f g h |
В приведенной выше сетке верхняя и нижняя строки будут использоваться для имен столбцов, а самые левые и самые правые столбцы — для имен строк. Это оставляет нам большую область 8x8 в центре сетки, где будет размещена существующая шахматная доска.
Чтобы расположить доску, я использовал свойство CSS grid-area
ниже, чтобы указать, что существующая доска начинается со строки 2 и столбца 2 сетки и охватывает 8 строк и 8 столбцов.
grid-area: 2 / 2 / span 8 / span 8;
Чтобы расположить другие компоненты, я обновил код JSX ChessBoard
следующим образом.
export const ChessBoard = () => { const board = [ ['♖', '♘', '♗', '♕', '♔', '♗', '♘', '♖'], ['♙', '♙', '♙', '♙', '♙', '♙', '♙', '♙'], ['', '', '', '', '', '', '', ''], ['', '', '', '', '', '', '', ''], ['', '', '', '', '', '', '', ''], ['', '', '', '', '', '', '', ''], ['♟', '♟', '♟', '♟', '♟', '♟', '♟', '♟'], ['♜', '♞', '♝', '♛','♚', '♝', '♞', '♜'], ] return ( <div className="chess-board"> <ColNames direction="top" /> <RowNames gridArea="2 / 1 / span 8 / span 1" direction="left" /> <Board board={board} /> <RowNames gridArea="2 / 10 / span 8 / span 1" direction="right" /> <ColNames gridArea="10 / 2 / span 1 / span 8" direction="bottom" /> </div> ); }
Свойство gridArea
используется внутри компонентов ColNames
и RowNames
для установки свойства grid-area
.
const RowNames = ({gridArea, direction}) => { const names = [1, 2, 3, 4, 5, 6, 7, 8]; return ( <div className="row-names" style={{ gridArea }}> { names.map((name) => <div key={`${direction} ${name}`} className={`row-name ${direction}`}> <strong>{name}</strong> </div> ) } </div> ); } const ColNames = ({ gridArea, direction }) => { const names = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']; return ( <div className="col-names" style={{ gridArea }}> { names.map((name) => <div key={`${direction} ${name}`} className={`col-name ${direction}`}> <strong>{name}</strong> </div> ) } </div> ); }
Обратите внимание, что в более позднем коммите я изменил код, чтобы переместить все части, связанные с gridArea
, в файл CSS, потому что я не всегда являюсь поклонником обработки стилей CSS в коде JavaScript.
Разрешение пользователям переходить на другую сторону с помощью контекстного API React
Шахматная доска имеет белые фигуры внизу и черные фигуры наверху, потому что она была построена с предположением, что сторона игрока белая. На самом деле игрок не всегда играет одним цветом, поэтому было бы лучше предоставить пользователям возможность переключаться на другую сторону.
Для реализации этой возможности я использую компонент Switch React Material UI library. Когда состояние переключателя меняется, нам нужно обновить пользовательский интерфейс следующим образом:
- Обратный порядок имен столбцов
- Обратный порядок имен строк
- Перевернуть строки содержимого шахматной доски
- Поменяйте местами короля и ферзя для обеих сторон так, чтобы белый ферзь начинал с белой клетки, а черный ферзь начинал с черной клетки.
Как я должен сообщить компонентам, что состояние переключателя изменилось? Наивный подход:
- Используйте useState для управления состоянием компонента Switch.
- Пузырьком поднимайте установщик состояния коммутатора вверх по DOM до самого нижнего общего предка коммутатора и шахматной доски.
- Передать состояние на доску как свойство в реквизите
- Продолжайте сверлить опору, если это необходимо
Хотя это определенно работает, реализовать это не очень весело, и это не приносит пользы нашему коду, потому что:
- Состояние переключателя должно быть передано через компоненты пользовательского интерфейса, которым на самом деле не нужно знать об этих данных.
- Потребуется дополнительная работа, если мы захотим позже изменить иерархию компонентов.
Это та ситуация, в которой Context API действительно помогает.
Сначала я создал контекст.
const PieceColorContext = createContext(undefined);
Из объекта контекста я определяю его поставщика контекста и настраиваемый хук
export const WHITE = "white"; export const BLACK = "black"; export const PieceColorProvider = ({ children }) => { const [pieceColor, setPieceColor] = useState(WHITE); const togglePieceColor = () => setPieceColor(pieceColor === WHITE ? BLACK : WHITE); return ( <PieceColorContext.Provider value={{ pieceColor, togglePieceColor, }} > {children} </PieceColorContext.Provider> ); }; export const usePieceColorContext = () => useContext(PieceColorContext);
Поставщику контекста PieceColorProvider
необходимо обернуть компонент App
, чтобы предоставляемый им контекст, то есть объект, передаваемый реквизиту value
, был доступен для всех компонентов-потомков App
.
import { PieceColorProvider } from './PieceColorContext'; const root = ReactDOM.createRoot(document.getElementById('root')); root.render( <React.StrictMode> <PieceColorProvider> <App /> </PieceColorProvider> </React.StrictMode> );
Как только это будет сделано, любой потомок App
сможет использовать пользовательский хук usePieceColorContext
для доступа к текущему значению и функции установки бокового переключателя, т. е. для доступа к предоставленному контексту. Ниже приведен обновленный код RowNames
. Все соответствующие изменения были внесены в этот коммит.
export const RowNames = ({gridArea, direction}) => { const names = [1, 2, 3, 4, 5, 6, 7, 8]; const { pieceColor } = usePieceColorContext(); if (pieceColor === BLACK) { names.reverse(); } return ( <div className="row-names" style={{ gridArea }}> { names.map((name) => <div key={`${direction} ${name}`} className={`row-name ${direction}`}> <strong>{name}</strong> </div> ) } </div> ); }
Наслаждаться!
Хотя я не планирую создавать полную и играбельную шахматную игру, я не хочу, чтобы этот проект останавливался на достигнутом. Ниже приведены несколько идей, которые у меня есть на данный момент:
- Загрузите головоломку дня с chess.com и покажите ее на доске.
- Загрузите сценарий шахматной партии и разрешите людям просматривать игру
- 🤔