简体   繁体   中英

If there is an active class on two buttons, how do I add a function specific to the buttons with the active class?

This is my first time posting and I'm also very new to javascript. I've had this problem for days and have tried various solutions but none have worked.

I have two buttons - one etch, and one for draw - where I want the etch button to apply a mouseover event to boxes in a div. I want to the draw button to apply a click event in the boxes in the div.

I also have a black button, a color button, and a rainbow button.

I have my code working to where the active class gets added when a button is clicked. Both sets of buttons are in their own containers so that I can have two active classes at the same time.

What I'm struggling to make happen, is when etch is active and black is active, it runs a mouseover event that changes the background of the div boxes to black. Or, when etch is active and color is active, the background color is changed to whatever the value is in the color picker, etc. When draw is active, it has a click event that hold black, color, or whatever is on the active class draw buttons.

I already have functions that hold the colors to change the background, I just can't seem to implement everything else.

I only have access to JavaScript, not jQuery. Any advice would b greatly appreciated.

const grid = document.getElementById('grid');
const slider = document.getElementById('sizeSlider');
let gridValue = document.getElementById('slider-value');
let gridSize = document.querySelector('input');
const container = document.getElementById('container');
let colorPicker = document.getElementById('color-picker');

const toggleBtn = document.getElementById('toggle');
const applyGridSize = document.getElementById('apply');
const resetBtn = document.getElementById('reset');
const etchBtn = document.getElementById('etch');
const drawBtn = document.getElementById('draw');
const eraserBtn = document.getElementById('eraser');
const resetGridBtn = document.getElementById('reset-grid');
const blackBtn = document.getElementById('black-btn');
const colorBtn = document.getElementById('color-btn');
const rainbowBtn = document.getElementById('rainbow-btn');

const drawModeBtns = document.querySelectorAll('.draw-mode-btn');
const colorModeBtns = document.querySelectorAll('.color-mode-btn');




//function to get slider value
function showValue(x) {
    document.getElementById('slider-value').textContent = `Grid Size: ${x} x ${x}`;
}
gridSize.addEventListener('input', function (e) {
    squareSize = e.target.value;
    gridValue.textContent = `Grid Size: ${squareSize}x${squareSize}`;
});

// function to create grid
function createGrid(col, rows) {
    for (let i = 0; i < (col * rows); i++) {
        const div = document.createElement('div');
        grid.style.gridTemplateColumns = `repeat(${col}, 1fr)`;
        grid.style.gridTemplateRows = `repeat(${rows}, 1fr)`;
        grid.appendChild(div).classList.add('box');
    }
}

// make 16x16 grid when window loads
window.onload = createGrid(slider.value, slider.value);




// modify grid size 
function modifyGridSize() {
    let boxes = grid.querySelectorAll(".box");
    boxes.forEach(box => box.remove());
    createGrid(slider.value, slider.value);
}

// change grid size with slider and apply button
applyGridSize.addEventListener('click', modifyGridSize);

// reset and clear grid to 16x16 when reset button is clicked
resetBtn.addEventListener('click', () => {
    let boxes = grid.querySelectorAll(".box");
    boxes.forEach(box => box.remove());
    createGrid(16, 16);
    slider.value = 16;
    gridValue.textContent = `Grid Size: 16 x 16`;
})

// clear grid only when button is clicked
resetGridBtn.addEventListener('click', () => {
    let boxes = grid.querySelectorAll('.box');
    boxes.forEach(box => box.style.backgroundColor = 'white');
})

// function to toggle lines on and off with button
toggleBtn.addEventListener('click', () => {
    let boxes = grid.querySelectorAll('.box');
    boxes.forEach(box => box.classList.toggle('toggle-lines'));
})




// add active class when a draw button is clicked
drawModeBtns.forEach(btn => {
    btn.addEventListener('click', (e) => {
        drawModeBtns.forEach(f => f.classList.remove('active'));
        e.target.classList.toggle('active');
    });
});
colorModeBtns.forEach(btn => {
    btn.addEventListener('click', (e) => {
        colorModeBtns.forEach(f => f.classList.remove('active'));
        e.target.classList.toggle('active');
    });
});




// background color change function for box divs in grid
function blackBackground() {
    this.style.backgroundColor = 'black';
}

// background color erase function
function eraseBackground() {
    this.style.backgroundColor = 'white';
}
eraserBtn.addEventListener('click', eraseBackground);

// random rainbow color background color function
function rainbowColor() {
    const randomR = Math.floor(Math.random() * 256);
    const randomG = Math.floor(Math.random() * 256);
    const randomB = Math.floor(Math.random() * 256);
    this.style.backgroundColor = `rgb(${randomR}, ${randomG}, ${randomB})`;
    // return `rgb(${randomR}, ${randomG}, ${randomB})`;
}

// random color background color function 
function colorBackground() {
    this.style.backgroundColor = changeColor();
}
// function to change background color to color picker input
function changeColor() {
    colorPicker.addEventListener('change', (e) => {
        let color = e.target.value;
        let boxes = grid.querySelectorAll('.box');
        boxes.forEach(box => {
            box.removeEventListener('mouseover', blackBackground);
            box.addEventListener('click', () => {
                box.style.backgroundColor = color;
            })
        })
    })
}

And here's the HTML that goes with it:

    <h1>Etch-a-Sketch</h1>

    <button id="reset">Reset All</button>
    <button id="reset-grid">Reset Grid</button>

    <br><br>

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

    <div id="gridSize"></div>

    <div class="slider">
        <label for="range"></label>
        <span id="slider-value" style="color: black;">Grid Size: 16 x 16</span>
        <br>
        2 <input type="range" name="range" id="sizeSlider" step="1" value="16" min="2" max="100"
            onchange="showValue(this.value);"> 100
        <button id="apply">Apply</button>
    </div>
    <br>
    <form name="draw-mode" class="draw-mode">
        <input type="button" value="Etch-a-Sketch Mode" id="etch" class="draw-mode-btn">
        <input type="button" value="Pixel Drawing Mode" id="draw" class="draw-mode-btn">
    </form>
    <br>
    <form name="color-mode" class="color-mode">
        <input type="button" value="Black" id="black-btn" class="color-mode-btn">
        <input type="button" value="Color" id="color-btn" class="color-mode-btn">
        <input type="button" value="Rainbow" id="rainbow-btn" class="color-mode-btn">
    </form>
    <br>
    <div>
        <input type="color" id="color-picker" name="color" value="" data-name="color-picker">
    </div>
    <br>
    <div>
        <button id="eraser" class="btn">Eraser</button>
    </div>
    <br>
    <div class="toggle-lines">
        <button id="toggle">Toggle Lines On/Off</button>
    </div>
    <br>

    <div id="grid" class="toggle-lines"></div>

    <br><br>


    <script src="./javascript.js"></script>

Screenshot of my page:页面截图

Create a state object that holds the interesting values - and gives back what you want:

  • drawState is the state object
  • it holds _mode : "click" or "mouseover" (click or etch)
  • it holds the _colorMode
  • based on the _colorMode it has a ruleset to always give back a color that you want ( get color() gives back either a color from the color picker, a random color, white (for eraser) or black

This way you can get rid of a lot of unnecessary functions.

(The data-drawval custom attributes on the HTML elements are also used!)

 const grid = document.getElementById('grid'); const slider = document.getElementById('sizeSlider'); let gridValue = document.getElementById('slider-value'); let gridSize = document.querySelector('input'); const container = document.getElementById('container'); let colorPicker = document.getElementById('color-picker'); const toggleBtn = document.getElementById('toggle'); const applyGridSize = document.getElementById('apply'); const resetBtn = document.getElementById('reset'); const etchBtn = document.getElementById('etch'); const drawBtn = document.getElementById('draw'); const eraserBtn = document.getElementById('eraser'); const resetGridBtn = document.getElementById('reset-grid'); const blackBtn = document.getElementById('black-btn'); const colorBtn = document.getElementById('color-btn'); const rainbowBtn = document.getElementById('rainbow-btn'); const drawModeBtns = document.querySelectorAll('.draw-mode-btn'); const colorModeBtns = document.querySelectorAll('.color-mode-btn'); const BOX_DIMENSION = 10 const initDrawState = () => { let _mode = "mouseover" let _colorMode = "black" return { get mode() { return _mode }, set mode(value) { _mode = value }, get color() { if (this.colorMode === "rainbow") { return rainbowColor() } else if (this.colorMode === "color") { return colorPicker.value } else if (this.colorMode === "eraser") { return "white" } else { return "black" } }, get colorMode() { return _colorMode }, set colorMode(value) { _colorMode = value } } } const drawState = initDrawState() //function to get slider value function showValue(x) { document.getElementById('slider-value').textContent = `Grid Size: ${x} x ${x}`; } gridSize.addEventListener('input', function(e) { squareSize = e.target.value; gridValue.textContent = `Grid Size: ${squareSize}x${squareSize}`; }); // function to create grid function createGrid(col, rows) { grid.style.height = rows * BOX_DIMENSION + "px" grid.style.width = col * BOX_DIMENSION + "px" for (let i = 0; i < (col * rows); i++) { const div = document.createElement('div'); grid.style.gridTemplateColumns = `repeat(${col}, 1fr)`; grid.style.gridTemplateRows = `repeat(${rows}, 1fr)`; grid.appendChild(div).classList.add('box'); } } const boxEventListener = (e) => { e.target.style.backgroundColor = drawState.color } const setBoxesEventListener = (boxes) => { boxes.forEach(box => { box.addEventListener(drawState.mode, boxEventListener) }) } const removeBoxesEventListener = (boxes) => { boxes.forEach(box => { box.removeEventListener("mouseover", boxEventListener) box.removeEventListener("click", boxEventListener) }) } const changeBoxesEventListener = () =>  { const boxes = grid.querySelectorAll(".box") removeBoxesEventListener(boxes) setBoxesEventListener(boxes) } // make 16x16 grid when window loads window.onload = modifyGridSize() // modify grid size function modifyGridSize() { grid.innerHTML = "" createGrid(slider.value, slider.value); changeBoxesEventListener() } // change grid size with slider and apply button applyGridSize.addEventListener('click', modifyGridSize); // reset and clear grid to 16x16 when reset button is clicked resetBtn.addEventListener('click', () => { let boxes = grid.querySelectorAll(".box"); boxes.forEach(box => box.remove()); createGrid(16, 16); slider.value = 16; gridValue.textContent = `Grid Size: 16 x 16`; changeBoxesEventListener() }) // clear grid only when button is clicked resetGridBtn.addEventListener('click', () => { let boxes = grid.querySelectorAll('.box'); boxes.forEach(box => box.style.backgroundColor = 'white'); }) // function to toggle lines on and off with button toggleBtn.addEventListener('click', () => { let boxes = grid.querySelectorAll('.box'); boxes.forEach(box => box.classList.toggle('toggle-lines')); }) // add active class when a draw button is clicked drawModeBtns.forEach(btn => { btn.addEventListener('click', (e) => { drawModeBtns.forEach(f => f.classList.remove('active')); e.target.classList.toggle('active'); drawState.mode = e.target.getAttribute("data-drawval") changeBoxesEventListener() }); }); colorModeBtns.forEach(btn => { btn.addEventListener('click', (e) => { colorModeBtns.forEach(f => f.classList.remove('active')); e.target.classList.toggle('active'); drawState.colorMode = e.target.getAttribute("data-drawval") }); }); // random rainbow color background color function function rainbowColor() { const randomR = Math.floor(Math.random() * 256); const randomG = Math.floor(Math.random() * 256); const randomB = Math.floor(Math.random() * 256); // this.style.backgroundColor = `rgb(${randomR}, ${randomG}, ${randomB})`; return `rgb(${randomR}, ${randomG}, ${randomB})` }
 .draw-mode-btn.active { background: purple; color: white; } .color-mode-btn.active { background: purple; color: white; } .box { border: 1px solid black; background: white; box-sizing: border-box; } #grid>.box.toggle-lines { border: 1px solid white; } #grid { display: grid; }
 <h1>Etch-a-Sketch</h1> <button id="reset">Reset All</button> <button id="reset-grid">Reset Grid</button> <br><br> <div id="container"></div> <div id="gridSize"></div> <div class="slider"> <label for="range"></label> <span id="slider-value" style="color: black;">Grid Size: 16 x 16</span> <br> 2 <input type="range" name="range" id="sizeSlider" step="1" value="16" min="2" max="100" onchange="showValue(this.value);"> 100 <button id="apply">Apply</button> </div> <br> <form name="draw-mode" class="draw-mode"> <input type="button" value="Etch-a-Sketch Mode" id="etch" class="draw-mode-btn active" data-drawval="mouseover"> <input type="button" value="Pixel Drawing Mode" id="draw" class="draw-mode-btn" data-drawval="click"> </form> <br> <form name="color-mode" class="color-mode"> <input type="button" value="Black" id="black-btn" class="color-mode-btn active" data-drawval="black"> <input type="button" value="Color" id="color-btn" class="color-mode-btn" data-drawval="color"> <input type="button" value="Rainbow" id="rainbow-btn" class="color-mode-btn" data-drawval="rainbow"> </form> <br> <div> <input type="color" id="color-picker" name="color" value="" data-name="color-picker"> </div> <br> <div> <button id="eraser" class="btn color-mode-btn" data-drawval="eraser">Eraser</button> </div> <br> <div class="toggle-lines"> <button id="toggle">Toggle Lines On/Off</button> </div> <br> <div id="grid" class="toggle-lines"></div> <br><br>

The code could be simplified even further, but then some other basic ideas should have been updated - and it was not clear from the description if those can be changed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM