javascript – Tic-Tac-Toe Game vanilla JS/CSS

I am practically brand new to coding and this is my first “real” project I’ve been attempting. It’s an attempt at a vanilla JS game with selectable layout and win conditions (partially implemented). ATM it only has a vertical win condition included as I didn’t want too much cluttering of the code (horizontal and diagonal would look more so the same).

SCRIPT.JS

const mainDiv = document.querySelector('(data-screen)')

class TicTacToe {
    constructor(div) {
        this.board = div.querySelector('(data-board)') 
    }

    //most of the initial variables here
    varUpdater = () => {
        this.pauseButton = this.board.querySelector('(data-pause-button)')
        this.pauseButton.addEventListener('click', this.setUp)
        this.pauseScreen = this.board.querySelector('(data-pause)')
        this.pauseText = this.board.querySelector('(data-pause-text)')

        this.playerOne = "x"
        this.playerTwo = "o"
        this.currentPlayer = this.playerOne

        this.winCondition = 3 //adjusts win condition

        this.rows = 5  // these values adjust layout
        this.columns = 5
    }

    setUp = () => {
        this.pauseMenuSetUp()
        this.varUpdater()
        this.cellSetUp()
        this.start()
    }

    pauseMenuSetUp = () => {
        this.board.innerHTML = `
        <div class="pause-screen show" data-pause>
            <div data-pause-text></div>
            <button data-pause-button>Start</button>
        </div>
        `
    }

    //Sets up cell layout and css style based on given parameters
    cellSetUp = () => {
        this.board.style.cssText = `grid-template-columns: repeat(${this.columns}, auto);`
        this.colSeperatorDiv = document.createElement('div')
        this.cellElement = document.createElement('div')
        this.cellElement.setAttribute('class', 'cell')
        for (let i = 0; i < this.rows; i++){
            this.cellElement.setAttribute('data-cell', i)
            this.colSeperatorDiv.appendChild(this.cellElement.cloneNode(true))
        } 
        for (let i = 0; i < this.columns;i++){
            this.colSeperatorDiv.setAttribute('data-seperator', i)
            this.board.appendChild(this.colSeperatorDiv.cloneNode(true))
        }
    }

    //Clears cell attributes and adds event listener before removing pause screen
    start = () => {
        this.board.querySelectorAll('(data-cell)').forEach(cell => {
            cell.classList.remove('x', 'o')
            cell.removeEventListener('click', this.clickHandle)
            cell.addEventListener('click', this.clickHandle, { once: true })
        })
        this.pauseScreen.classList.remove('show')
    }

    //Adds symbol based on cell target
    clickHandle = (cell) => {
        this.cell = cell.target
        this.cell.classList.add(this.currentPlayer)
        this.checkBoard()
    }

    //Decides if it should select next player or conclude game
    checkBoard = () => {
        this.columnIndex = parseInt(this.cell.getAttribute('data-cell'))
        this.rowIndex = parseInt(this.cell.parentElement.getAttribute('data-seperator'))
        if (this.isConcluded() == true) {
            this.pauseText.innerHTML = `${this.currentPlayer} wins!`
            this.pauseScreen.classList.add('show')
        } else if (this.isConcluded() === 'tie') {
            this.pauseText.innerHTML = `Tie!`
            this.pauseScreen.classList.add('show')
        } else {
            this.playerSelect()
        }
    }

    //Selects next player
    playerSelect = () => {
        this.currentPlayer !== this.playerTwo ? this.currentPlayer = this.playerTwo
            : this.currentPlayer = this.playerOne;
    }

    //Checks for game conclusion. Does NOT check for horizontal and diagonal conditions atm
    isConcluded = () => {
        return this.verticalScore(0, this.columnIndex) >= this.winCondition ? true
        : Array.from(this.board.querySelectorAll('(data-cell)')).every(c => c.classList.contains(this.playerOne) || c.classList.contains(this.playerTwo)) ? 'tie'
        : false
    }

    //Goes down the column using recursion to add up score,
    //Diagonal/horizontal win condition would use the rowIndex as well
    verticalScore = (score, col) => {
        return this.cell.parentElement.querySelector(`(data-cell="${col}")`) == null ? score += this.reverseDirectionScore(0, this.columnIndex - 1)
        : this.cell.parentElement.querySelector(`(data-cell="${col}")`).classList.contains(this.currentPlayer) ? score += this.verticalScore(1, col + 1)
        : score += this.reverseDirectionScore(0, this.columnIndex - 1);
    }
    //Goes up column using recursion to return a score
    reverseDirectionScore = (rScore, rCol) => {
        return this.cell.parentElement.querySelector(`(data-cell="${rCol}")`) == null ? rScore
        : this.cell.parentElement.querySelector(`(data-cell="${rCol}")`).classList.contains(this.currentPlayer) ? rScore += this.reverseDirectionScore(1, rCol - 1)
        : rScore
    }
}

const newBoard = new TicTacToe(mainDiv)
newBoard.setUp()

attaches to this HTML page

<!DOCTYPE html>
<html>
<head>
    <title>Tic-Tac-Toe</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <div data-screen>
        <div class="board" data-board>
        </div>
    </div>
    <script src="/script.js" async defer></script>
</body>

</html>

Codepen: https://codepen.io/sarbastu/pen/XWjZgey

The game is functioning as intended, but I have a bunch of doubt on the way it was written particularly with possible overuse of querySelector/data-attributes. A few particular questions:

  1. Was the choice to make the game a template object pointless/more damaging than otherwise?
  2. Does this code at all represent decently implemented OOP style?
  3. How is the use of querySelector (mainly the use of it in the last 3 game conclusion check functions)? Should I have attached them to a variable first? Is there anything I could have done better?

Do to my complete lack of experience I have no idea if I am at all approaching OOP or programming in general correctly. Any criticism/feedback is greatly appreciated.