jQuery: animate hide letters randomly but with equ

2019-03-03 19:22发布

问题:

I have two questions.

  • Why the animation that makes the letters randomly disappear doesn't follow the same speed for all the letters? The animation is not fluid.

  • How can I make the animation works on the opposite side? When I hide the div with .hide() and I try to make it appear with opacity this won't work. I tried different solution already but really nothing makes the div appear.

Code:

function wow1 () {

	var mail1 = $(".mailFirst h2");
	var letters = mail1.children();

	setInterval(function() {
		letters.eq(Math.random()*letters.length |0).animate({opacity:0},500);
	},500);
}

$(document).ready(wow1);
.mailFirst	{position: absolute;
			       top: 0;
			       left: 0;
			       color: red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="mailFirst">
  <h2> 
    <span> @ </span>
    <span> E </span>
    <span> - </span>
    <span> M </span>
    <span> a </span>
    <span> i </span>
    <span> l </span>
    <span> @ </span>
  </h2>
</div>

回答1:

Problems

The problems in your script includes one major fault is that you are generating random numbers unaware from the fact that the generated number will be used to select a span and hide it and it needs to be a valid index, and what actually happens that it keeps on generating numbers which may occur twice, in which case it will try to hide the hidden letter again, and the waiting period of trying to find the valid index which is also not hidden it sometime takes less time or sometimes more. so that is the real reason behind the hiding time not being the same.

Secondly, you are just running the animation and that's it there is no stopping of the script it is continuously running and loading your browser along with setInterrval() which alone is not known to have mercy on your browser even if it is minimized or tab switched, you need to stop it once all spans are hidden.

What to do

  1. Select the elements you have to hide.

  2. Get elements in an array using .toArray() in a var say elemArray

  3. Start generating the random number and validate if it is a valid index for the elemArray if not call it recursively until you find a valid index between the range [0 - elemArray.length].

  4. When you find a valid index hide the element on that index and use splice to remove that element from the elemArray in this way you will hide every element once and into a random sequence

  5. Now about animations, Say Hello to requestAnimationFrame()

    requestAnimationFrame function that allows you to create smooth and fluid animations in JavaScript without you actually having to worry about making it smooth and fluid. Just add a few calls to requestAnimationFrame and your browser takes care of the rest. That's it. and it also helps to control the factors such as your laptop/ phone/tablet going into battery mode and halving its performance reduced. Factors such as another tab taking focus. Read More Here

  6. And in the end, you have to stop the animation too so use the brother of requestAnimationFrame function which is cancelAnimationFrame

see below I created a demo for you hope it helps you out.

var framesPerSecond = 10;
var letters = $(".mailFirst>h2 span");
var elemArray = letters.toArray();
// store your requestAnimatFrame request ID value
var requestId;

//the animation function
function animate() {
  setTimeout(function() {

    //save the id returned from the function to use it 
    //for canceling or stopping the animation

    requestId = requestAnimationFrame(animate);

    // animating/drawing code goes here
    hideRandomWord();

    //check if there are no more elements left to hide
    if (!elemArray.length) {
      stopAnimation(requestId);
    }
  }, 2000 / framesPerSecond);
}
//start animation
requestAnimationFrame(animate);

//function to hide a character / word
function hideRandomWord() {

  var min = 0;
  var max = Math.floor(elemArray.length);

  //The maximum is exclusive and the minimum is inclusive
  var rand = Math.floor(Math.random() * (max - min)) + min;
  
  //if elements array is not empty
  if (elemArray.length) {

    //if the generated index is a valid index for the elements array
    if (typeof elemArray[rand] !== 'undefined') {

     //animate opacity 
      $(elemArray[rand]).animate({
        opacity: 0
      });
      //remove the element from the elements array
      elemArray.splice(rand, 1);
    } else {
      //call recursively it self if not valid index generated
      hideRandomWord();
    }
  }
}

function stopAnimation(requestId) {
  // use the requestID to cancel the requestAnimationFrame call
  cancelAnimationFrame(requestId);
}
.mailFirst {
  position: absolute;
  top: 0;
  left: 0;
  color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="mailFirst">
  <h2>
    <span> @ </span>
    <span> E </span>
    <span> - </span>
    <span> M </span>
    <span> a </span>
    <span> i </span>
    <span> l </span>
    <span> @ </span>
  </h2>
</div>



回答2:

The first problem, the uneven hiding of the letters, is due to the nature of your random function. It looks for a letter to randomly hide, hides it and selects another. But the random selection still includes letters that have already been hidden, so it's just hiding them again - which is an operation you can't see so it looks like nothing is happening. You need to remove the letters from the array as they get hidden so they no longer get included in the random selection.



回答3:

Steve has explained it well but here is the code for it.

<html>

<head>
  <style>
    .mailFirst {
      position: absolute;
      top: 0;
      left: 0;
      color: red;
    }
  </style>
</head>

<body>
  <div class="mailFirst">
    <h2>
      <span> @ </span>
      <span> E </span>
      <span> - </span>
      <span> M </span>
      <span> a </span>
      <span> i </span>
      <span> l </span>
      <span> @ </span>
    </h2>
  </div>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
  <script>
    var mail1 = $(".mailFirst h2");
    var letters = mail1.children();
    var numberOfSpans = letters.length;
    var hiddenSpans = 0;

    function changeOpacity() {
    
      setTimeout(
        function() {
          var ind;
          var opc;

          do {
            var ind = (Math.random() * letters.length | 0);
            var opc = Number(letters.eq(ind).css("opacity"));
            console.log("index: " + ind + " and opc: " + opc);
          } while (opc != 1)

          letters.eq(ind).animate({
            opacity: 0
          }, 500);

          hiddenSpans++;
          if (hiddenSpans < numberOfSpans) {
            changeOpacity();
          }
        }, 500
      );
    }
    $(document).ready(changeOpacity);
  </script>
</body>

</html>