简体   繁体   中英

JavaScript - Revert element to original style after clicking another element

So I'm building a calendar program, and I want the user to be able to select a day. Using a <table> , the <td> highlights when clicked by applying className="NewStyle" to the box. I want that cell to go back to normal after clicking on another cell, but it just remains in its new style.

How do I make JS revert any non-clicked cell to normal when another cell is clicked?

Here's a JSFiddle . Thanks for any help!

HTML

The cells look like this:

<td id="td_4" onclick="change(4)">4</td>
<td id="td_5" onclick="change(5)">5</td>
<td id="td_6" onclick="change(6)">6</td>

Clicking td_4 will successfully change the style. But clicking td_6 will also successfully change styles, but leave td_4 in its new style instead of reverting it.

JavaScript

function change(x) {
    document.getElementById("td_" + x).className = "selected";
}

Just keep track of the element you clicked and unclass it. fiddle

var previousEl
function change(x) {
  if (previousEl) previousEl.className = ""
  previousEl = document.getElementById("td_" + x)
  previousEl.className = "selected"
}

UPDATE: Another thing worth mentioning is that you can take advantage of event bubbling so that your parent container can listen to events, getting the id of the clicked element from the event object. updated fiddle

var previousEl
function change(event) {
  if (previousEl) previousEl.className = "";
  previousEl = document.getElementById(event.target.id)
  previousEl.className = "selected";
}

and in your html get rid of all your <td onclick="change()"> and put it on parent, passing event:

<table onclick="change(event)">

This is how I would achieve the effect you're looking for, but first a couple notes:

  1. Don't use inline JavaScript
  2. If you have to repeat lots of code, it can probably be done a simpler way. (read: DRY )

We are only going to use two event listeners in this script.

The first event listener will use delegation to assign the selected class to the clicked element. When you click on an element, the event will "bubble" up past the clicked element, all the way up through the DOM. So we can listen to a common parent element, then check to see where the event originated.

Here we want to check if the element is a <td> element, and if it does not have the class no_border . Then we want to use Event.stopPropagation() to stop the click event from bubbling past the common parent, which will avoid some complications with the second listener. The last check we are going to do is to see if the clicked element is the selected element. If it is then we skip the next step and just remove the selected class.

We use a common variable to store the clicked element in until the next element is clicked. Upon the next click event we remove the selected class from the stored element's class list if there is a stored element. Then we assign the newly clicked element to the common variable and give it the selected class.

The second event listener will listen to click events for the entire document. If there is a selected element, it should hide that element. Now the trick here is that, because we stopped the propagation of the click event from the table if the clicked element was a <td> element and didn't have the class no_border , we don't have to compare the clicked element again in order to not clash with the first event listener. All we have to check is whether there is a selected element or not and if so, remove the class and reset the common variable.

 var selected; document.getElementById( 'calendar' ).onclick = function( e ) { var c = e.target; if( c.tagName === 'TD' && c.className.indexOf( 'no_border' ) === -1 ) { e.stopPropagation(); if( c.className.indexOf( 'selected' ) === -1 ) { if( selected ) selected.className = selected.className.replace( /\\s?selected/, '' ); selected = c; selected.className += ' selected'; } else c.className = c.className.replace( /\\s?selected/, '' ); } } document.body.onclick = function( e ) { if( selected ) { selected.className = selected.className.replace( /\\s?selected/, ''); selected = false; } } 
 td { padding:4px; border:solid #ccc 1px; text-align: center; } td::after { /* I added this to keep a consistent width */ content: ""; display: block; width: 2em; } .no_border { border: 1px solid transparent; } .selected { border: solid #69F 1px; } 
 <table id="calendar"> <thead> <tr><td class="no_border">Sun</td><td class="no_border">Mon</td><td class="no_border">Tue</td><td class="no_border">Wed</td><td class="no_border">Thu</td><td class="no_border">Fri</td><td class="no_border">Sat</td></tr> </thead> <tbody> <tr><td class="no_border" colspan="6"></td><td>1</td></tr> <tr><td>2</td> <td>3</td> <td>4</td> <td>5</td> <td>6</td> <td>7</td> <td>8</td></tr> <tr><td>9</td> <td>10</td><td>11</td><td>12</td><td>13</td><td>14</td><td>15</td></tr> <tr><td>16</td><td>17</td><td>18</td><td>19</td><td>20</td><td>21</td><td>22</td></tr> <tr><td>23</td><td>24</td><td>25</td><td>26</td><td>27</td><td>28</td><td>29</td></tr> <tr><td>30</td><td>31</td></tr> </tbody> </table> 

There is not much of a simple solution but try:

function change(x) {
    document.getElementsByTagName('td').forEach(function (el) {
        if (el.className === 'selected') {
            el.className = '';
        }
    });
    document.getElementById("td_" + x).className = "selected";
}

Or

function change(x) {
    document.getElementsByClassName('selected').forEach(function (el) {
        el.className = '';
    });
    document.getElementById("td_" + x).className = "selected";
}

Use querySelector to determine the currently-checked td :

function change(x) {
  var sel= document.querySelector('td.selected');
  if(sel) sel.className= '';
  document.getElementById("td_" + x).className = "selected";
}

Fiddle 1

You could also replace all your inline click handlers with one click handler on the table . Make sure the event's target is a td ( e.target.tagName === 'TD' ), which contains a number ( !isNaN(e.target.textContent ):

document.querySelector('table').addEventListener('click', function(e) {
  if(e.target.tagName === 'TD' && !isNaN(e.target.textContent)) {
    var sel= document.querySelector('td.selected');
    if(sel) sel.className= '';
    e.target.className= 'selected';
  }
});

Fiddle 2

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