В прошлом году я работал над небольшой задачей, которая была одной из самых сложных задач, над которыми я работал.
Это описание:
Создайте сетку 10x10. Всякий раз, когда вы нажимаете на ячейку в этой сетке, 1 добавляется ко всем ячейкам в той же строке и столбце.
Если ячейка была пустой, установите ее на 1. Каждое изменение в ячейке должно вызывать кратковременную подсветку ячейки желтым цветом. Если по крайней мере 5 последовательных чисел в ячейках образуют часть последовательности Фибоначчи, кратковременно ячейки зеленым цветом, а затем очистите эти ячейки.
Это мое решение, но я знаю, что оно может быть лучше, поэтому дайте мне знать, если вы найдете лучшее решение для его решения.
Для этого проекта я использовал React js, Typescript и tailwind CSS.
Итак, сначала я начал создавать функцию, которая может генерировать матрицу в двух измерениях со значением по умолчанию:
const matrix = ( rows: number, cols: number, defaultValue: number | null ): number[][] => { return Array.from({ length: rows }).fill( Array.from({ length: cols }).fill(defaultValue) ) as Array<Array<number>> }
Затем я создал таблицу на главной странице:
interface AppProps { defaultSize?: number } const App = ({ defaultSize = 10 }: AppProps): JSX.Element => { const [mainTable, setMainTable] = useState<number[][]>( matrix(defaultSize, defaultSize, 0) ) return( <table className="text-white border"> <tbody> {mainTable.map((row, i: number) => ( <tr key={i} className="p-3"> {row.map((_cell, j: number) => { return ( <td className="p-10 border cursor-pointer" key={i * defaultSize + j} id={`cell-${i}-${j}`} > {mainTable[i][j]} </td> ) })} </tr> ))} </tbody> </table> ) } export default App
Затем я создаю функцию для увеличения значений ячеек в строке и столбце:
const incrementCells = ( arr: number[][], row: number, col: number ): number[][] => { return arr.map((row2, i: number) => i === row ? row2.map((col2) => +col2 + 1) : row2.map((col2, j: number) => (j === col ? +col2 + 1 : +col2)) ) }
Затем я добавил в таблицу функцию onClick:
<table className="text-white border" onClick={(e) => { const target = e.target as HTMLElement if (target.id.includes("cell")) { const [row, col] = target.id.split("-").slice(1) clickCell(+row, +col) } }} >
Я мог бы использовать onClick для каждой ячейки (тег td), но это не слишком хорошо из-за производительности.
Теперь нам нужно определить функцию щелчка по ячейке:
const clickCell = (row: number, col: number) => { setMainTable((prev) => colorize(incrementCells(prev, row, col), row, col)) }
И функция colorize, я пишу стили после функций:
const changeBgColor = (row: number, col: number, color: boolean): void => { const cell = document.getElementById(`cell-${row}-${col}`) if (cell && !color) { const prevClasses = cell.className if (!prevClasses.includes("fade-colors")) { cell.className = prevClasses + " fade-colors-yellow" } } else if (cell && color) { let prevClasses = cell.className prevClasses = prevClasses.replace("fade-colors-yellow", "") if (!prevClasses.includes("fade-colors-yellow")) { cell.className = prevClasses + " fade-colors-green" } } } const colorize = (arr: number[][], row: number, col: number): number[][] => { changeBgColor(row, col, false) return arr }
Я написал функцию для проверки паттерна Фибоначчи.
Он получает каждую строку, проверяет все ячейки и вычисляет, соответствуют ли они шаблону или нет, тогда он возвращает логическое значение, по которому мы можем понять, является ли это последовательностью Фибоначчи или нет:
const checkFib = ({ col_start, col_end, row, table, }: { col_start: number col_end: number row: number table: number[][] }): boolean => { const fibSeq = table[row].slice(col_start - 4, 1 + col_start) if ( col_start < 0 || col_end < 0 || !(fibSeq[0] && fibSeq[1] && fibSeq[2] && fibSeq[3] && fibSeq[4]) ) { return false } if (fibSeq[0] === fibSeq[1] && fibSeq[0] !== 1) { return false } return ( fibSeq[4] - fibSeq[3] === fibSeq[2] && fibSeq[3] - fibSeq[2] === fibSeq[1] && fibSeq[2] - fibSeq[1] === fibSeq[0] ) }
Теперь пришло время проверить все ячейки и найти шаблон.
Сначала я определил переменную cells
для сохранения данных ячейки, таких как номер строки, номер начального столбца и номер последнего столбца.
Затем я использовал метод карты для массива mainTable, чтобы проверить все ячейки и значения в таблице, и использовал функцию checkFib, чтобы проверить все ячейки и строки.
useEffect(() => { const cells: { row: number col_start: number col_end: number setMainTable: React.Dispatch<React.SetStateAction<number[][]>> }[] = [] const fibCells = mainTable.map((row, i) => row.map((col, j) => checkFib({ row: i, col_start: j, col_end: j - 4, table: mainTable }) ) ) fibCells.forEach((row, i) => { row.forEach((col, j) => { if (col) { console.log("here : ", true) for (let k = 4; k >= 0; k--) { changeBgColor(i, j - k, true) } cells.push({ row: i, col_start: j, col_end: j - 4, setMainTable, }) } }) }) setTimeout(() => cells.forEach(removeCellValues), 2000) }, [mainTable])
Этот раздел кода перебирает двумерный массив fibCells
с использованием метода forEach
. Внешний цикл forEach
перебирает строки массива, а внутренний цикл forEach
перебирает столбцы массива.
Для каждого правдивого элемента в массиве fibCells
вызывается функция changeBgColor
с аргументами i
, j - k
и true
. Это, вероятно, используется для изменения цвета фона ячеек в таблице, которые являются частью последовательности Фибоначчи.
Кроме того, в массив cells
добавляется объект со свойствами row
, col_start
, col_end
и setMainTable
. Эти свойства будут использоваться позже в коде, возможно, для удаления ячеек из таблицы через определенное время (здесь 2 секунды).
И для удаления значений ячеек я написал эту функцию, она получает данные ячейки и удаляет значение ячейки и все стили этого.
const removeCellValues = ({ col_start, col_end, row, setMainTable, }: { col_start: number col_end: number row: number setMainTable: React.Dispatch<React.SetStateAction<number[][]>> }): void => { for (let i = col_start; i >= col_end; i--) { setMainTable((prev) => { const newTable = [...prev] newTable[row][i] = 0 return newTable }) } const cells = document.querySelectorAll("td") as NodeListOf<HTMLElement> cells.forEach((cell) => { let prevClasses = cell.className prevClasses = prevClasses.replace("fade-colors-green", "") cell.className = prevClasses }) }
Пришло время стилей, я использовал эти стили:
.fade-colors-yellow { animation: fadeinYellow 1s linear both; } @keyframes fadeinYellow { from { opacity: 0; background: transparent; color: white; } to { opacity: 1; background: yellow; color: black; } } .fade-colors-green { animation: fadeinGreen 1s linear both; } @keyframes fadeinGreen { from { opacity: 1; background: yellow; color: black; } to { opacity: 1; background: green; color: white; } } table { border-spacing: 10px; border-collapse: separate; border-color: red; border-width: 12px; } td, th, tbody, tr { border: 1px solid rgb(49, 124, 189); } td { width: fit-content; } .main { width: 100%; height: 100%; background: black; color: white; }
Вы можете проверить готовый код в этом репозитории. Не забудьте поставить звездочку :)
Давайте подключимся
Спасибо, что прочитали мою статью. Если вам нравится мой контент, рассмотрите возможность угостить меня кофе ☕.