Aurore
Aurore

Reputation: 746

Replacing a letter on mouseenter, change back on mouseleave

I made this script that let me change the letter on hover of the specific letter.

I would like to be able to hover a letter, change it to A and as soon as the mouseleave event is called, the letter change back to the original letter.

  const toLetterize = document.querySelectorAll(
    ".change p"
  );
  console.log(toLetterize);


  toLetterize.forEach(function (letterized) {
    const letters = letterized.innerHTML;
    var nHTML = "";
    for (var letter of letters) {
      nHTML += "<u>" + letter + "</u>";
    }

    letterized.innerHTML = nHTML;

    document.querySelectorAll("u").forEach(function (hoveredLetter) {
      hoveredLetter.addEventListener("mouseenter", function (e) {
        console.log("hovered")
        hoveredLetter.innerHTML = nextLetter(hoveredLetter.innerText);
      });
      hoveredLetter.addEventListener("mouseleave", function (e) {
        console.log("leaving" + nextLetter(hoveredLetter.innerText))
        hoveredLetter.innerHTML = nextLetter(hoveredLetter.innerText);
      });
    });
  });


function nextLetter(ch) {
  console.log(ch);
  if (!ch.match(/[a-z]/i)) {
    return "A";
  } else if (ch === "A") {
    return ch;
  }
  return String.fromCharCode(ch);
}
div{
font-family: monospace;
}
<div class="change">
 <p> The colours of the binding (chosen by me) will be white letters on a blue field – the Greek flag though really of Bavarian origin and imported with the dynasty. Yet in a special way they symbolise the myth well – the white islands scattered over the sea.</p>
</div>

Upvotes: 0

Views: 51

Answers (2)

Yogi
Yogi

Reputation: 7229

Using CSS

You can do this with simple css and avoid all the JavaScript in the selected answer.

Using the pseudo class ::before we can show different content on hover. The original letter is stored in attribute data-char. And the css attr() function selects it as the content. And on hover we can select some other letter, which could be a constant, a different attribute, or even a css variable.

.change p span::before {
  content: attr(data-char);
}
.change p span:hover::before {
  content: "A";
}

When the page loads we use a tiny bit of JavaScript to wrap each letter in a span. Yet, after loading we don't need any scripts to make it work.

<span data-char="k"></span>

Snippet

Run the snippet to understand how it works.

let p = document.querySelector('.change p');

p.innerHTML = p.innerText
  .split('')
  .map(char => `<span data-char="${char}"></span>`)
  .join('');
body {
  font-family: monospace;
  font-size: 20px;
  padding: 2rem;
}

.change p span::before {
  content: attr(data-char);
}

.change p span:hover::before {
  content: "A";
  color: red;
}
<div class="change">
  <p> The colours of the binding (chosen by me) will be white letters on a blue field – the Greek flag though really of Bavarian origin and imported with the dynasty. Yet in a special way they symbolise the myth well – the white islands scattered over the
    sea.</p>
</div>

Upvotes: 2

Diego D
Diego D

Reputation: 8161

Your event handlers should take the element triggering the event from the event object in the arguments (e.target or e.currentTarget).

Plus you should keep track of the original letter. I put it inside a data attribute (data-original) when crafting the u elements holding each letter.

So that the event handler for mouseenter now just changes the innerText of the hovered element with A and the event handler for mouseleave just changes the innerText of the element loosing the cursor with the original letter having at the beginning.

const toLetterize = document.querySelectorAll(".change p");

toLetterize.forEach(function(letterized) {

  const letters = letterized.innerHTML;
  let nHTML = "";
  for (let letter of letters) {    
    nHTML += `<u data-original='${letter}'>${letter}</u>`;    
  }

  letterized.innerHTML = nHTML;

  document.querySelectorAll("u").forEach(function(letter) {
    letter.addEventListener("mouseenter", function(e) {      
      const hoveredElement = e.currentTarget;
      const currentLetter = hoveredElement.innerText;                        
      hoveredElement.innerText = 'A';      
    });
    letter.addEventListener("mouseleave", function(e) {
      const hoveredElement = e.currentTarget;
      const originalLetter = hoveredElement.dataset['original'];                  
      hoveredElement.innerText = originalLetter;
    });
  });
});
div {
  font-family: monospace;
}

u{
  cursor: pointer;
}
<div class="change">
  <p>The colours of the binding (chosen by me) will be white letters on a blue field – the Greek flag though really of Bavarian origin and imported with the dynasty. Yet in a special way they symbolise the myth well – the white islands scattered over the sea.</p>
</div>

Upvotes: 3

Related Questions