Image stabilization

All the code in this file can be copied directly, and then open debugging in the browser to see the corresponding effect

This article is the anti – shake function, the next article will write throttling function. If you like it, give it a thumbs up

We interrupt for another article

There is no more detailed handwriting throttling function than this

First edition, original edition, without any added ‘preservatives’

There is no anti-shake effect, as long as the slide will have an event. If it’s count++ and it’s a function like sending a network request, it’s going to keep asking. In the actual development process, such operation is certainly not good, that frequent to switch network requests, will cause very large pressure to the background server


      
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <style>
    #container {
      width: 100%;
      height: 200px;
      line-height: 200px;
      text-align: center;
      color: #fff;
      background-color: # 444;
      font-size: 30px;
    }
  </style>
</head>
<body>
  <! Declare variables, get DOM, declare methods, bind onMousemove methods
  <div id="container"></div>
  <script>
    // 1. Declare a variable first
    let count = 1;
    // 2. Get the DOM
    let container = document.querySelector("#container")
    // 3. Encapsulate the function, where doSomething can be an actual network request
    function doSomething() {
      container.innerHTML = count++;
    }
    // 4. Bind mouse movement events to Container. Call doSomething, notice that there is no () in the call
    container.onmousemove = doSomething  // This is written by myself and does not do the anti-shake, comment out the following reference to the anti-shake function can see the effect. As long as the mouse moves over the background area, the data keeps incrementing by 1
  </script>
</body>
</html>
Copy the code

The second version, the use of third-party JS library to achieve shaking


      
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <style>
    #container {
      width: 100%;
      height: 200px;
      line-height: 200px;
      text-align: center;
      color: #fff;
      background-color: # 444;
      font-size: 30px;
    }
  </style>
</head>
<body>
  <! Declare variables, get DOM, declare methods, bind onMousemove methods
  <div id="container"></div>
  <! -- Import the third party anti-shake JS library -->
  <script src="https://cdn.bootcss.com/underscore.js/1.9.1/underscore.js"></script>
  <script>
    // 1. Declare a variable first
    let count = 1;
    // 2. Get the DOM
    let container = document.querySelector("#container")
    // 3. Encapsulate the function, where doSomething can be an actual network request
    function doSomething() {
      container.innerHTML = count++;
    }

    // 4. Bind mouse movement events to Container. Call doSomething, notice that there is no () in the call
    // // Note that the third-party debounce function is called with _. Must be called this way to execute the anti-shake function
    container.onmousemove = _.debounce(doSomething,1000) // Here is the effect of calling deboucne. The +1 operation is performed after 1 second when the mouse stops sliding

    
    // Buffeting: the event response function is executed after a period of time. If it is called again within this period of time, the execution time will be recalculated; The method is executed only if the slide stops after 1 second. This is called anti-shaking.
    // Here we set doSomething. This method is executed after 1 second, if we stop sliding for 1 second, count will be +1; But if we stop sliding 0.9 seconds later and start again 0.92 seconds later, the anti-shake function recalculates the time. When we stop sliding for a period of time after 0.92 seconds, the count starts +1 seconds later
  </script>
</body>
</html>
Copy the code

There are several figurative metaphors in life.

  • The bus stops and there are ten people waiting at the stop sign to get on. As long as these ten people keep getting on, the bus has to wait. All 10 people got on and the bus left. Suddenly, the back of a little sister, is running, the driver a look, Yo ha, female. No, I can’t leave. I have to wait for her. Finally the little girl gets in the car, the driver starts, and notice, this is a real drive, a real drive.
  • Play King of Glory game, there are three skills, three skills are finished, can not point, can only wait for skill cooling down.

Third edition, handwriting to achieve the anti – shake function

First of all, it is divided into JS files and HTML files to facilitate subsequent operations

The HTML file


      
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <style>
    #container {
      width: 100%;
      height: 200px;
      line-height: 200px;
      text-align: center;
      color: #fff;
      background-color: # 444;
      font-size: 30px;
    }
  </style>
</head>
<body>
  <div id="container"></div>
  <script src="anti-shake2.js"></script>
  <script>
    let container = document.querySelector("#container");
    // Bind mouse movement events to container. Call doSomething, notice that there is no () in the call
    container.onmousemove = debounce(doSomething,1000.true);
    // Note that we are writing the debounce function by hand, where there is no _. Only the underscore function that references third-party functions is used in this way. Why? Container. Onmousemove = _. Debounce (doSomething,1000,true)
  </script>
</body>
</html>
Copy the code

Js file

// A function to prevent shaking
function debounce (func,wait) { // This function takes two arguments, the first is the function to execute, and the second is the delay time
  let timeout; // Declare a timeout variable
  return function() { // return is a function
    clearTimeout(timeout) // Clear timeout every time
    timeout = setTimeout(func,wait) // Set setTimeout to set the time}}// Declare a variable first
let count = 0;
/ / get the DOM
let container = document.querySelector("#container");
// Encapsulate the function, where doSomething can be an actual network request
function doSomething() {
  container.innerHTML = count++;
}
// Bind mouse movement events to container. Call doSomething, notice that there is no () in the call
container.onmousemove = debounce(doSomething,300); Count +1 after 300ms when the mouse stops sliding. You can change it to 1s or 2s for better effect
Copy the code

One of the basic functions above is implemented. The moment each slide stops, count+1 after 300ms; When the slide stops, within 298ms, 299ms starts to slide again. At this point, the count has not exceeded 300ms, so we haven’t added 1, but we start to slide at 299ms, so we recalculate the time again. What time do you recalculate? The moment you start sliding to stop at 299ms, 300ms later start count+1.

The feature of anti-shake is that it recalculates the time each time.

You think it’s all over?

Too young for that, my boy.

Fourth version, using third party JS library to achieve anti – shake – third parameter

Debounce has two parameters that are basically equal. But the debounce function wrapped in uderScore by a third-party plug-in has a third parameter. The default value is false if it is not written, and true if it is executed immediately. If set to true, it means that after stopping the slide for 1 second, the slide will be executed immediately without delay. If the slide continues for 1s, the +1 operation will not be performed. The +1 operation will be performed immediately after the slide stops for 1s and starts again.


      
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <style>
    #container {
      width: 100%;
      height: 200px;
      line-height: 200px;
      text-align: center;
      color: #fff;
      background-color: # 444;
      font-size: 30px;
    }
  </style>
</head>
<body>
  <! Declare variables, get DOM, declare methods, bind onMousemove methods
  <div id="container"></div>
  <script src="https://cdn.bootcss.com/underscore.js/1.9.1/underscore.js"></script>
  <script>
    // Declare a variable first
    let count = 1;
    / / get the DOM
    let container = document.querySelector("#container")
    // Encapsulate the function, where doSomething can be an actual network request
    function doSomething() {
      container.innerHTML = count++;
    }
    
    // Note that the third party debounce function is called with _. It must be called this way to execute the anti-shock function
    container.onmousemove = _.debounce(doSomething,1000.true) // Here is the effect of calling deboucne. Only when the mouse does not slide, 1 second later, slide again, immediately perform the +1 operation

  </script>
</body>
</html>
Copy the code

Fifth edition, handwriting anti – shake – the third parameter

The HTML file


      
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <style>
    #container {
      width: 100%;
      height: 200px;
      line-height: 200px;
      text-align: center;
      color: #fff;
      background-color: # 444;
      font-size: 30px;
    }
  </style>

</head>
<body>
  <! Declare variables, get DOM, declare methods, bind onMousemove methods -->
  <div id="container"></div>
  <script src="anti-shake2.js"></script>
  <script>
    let container = document.querySelector("#container");
    // Bind mouse movement events to container. Call doSomething, notice that there is no () in the call
    container.onmousemove = debounce(doSomething,1000.true); 
  </script>
</body>
</html>
Copy the code

Js file

// The third argument, using imme, controls whether to execute immediately
function debounce (func,wait,imme) {
  let timeout;
  return function() { // return a function
    clearTimeout(timeout)
    if(imme) { // Execute immediately if true
      
      // There are many ways to write this. The first way is to call the previous operation
      // if(callNow) func.apply(context) // imme is always true. It's always going to be executed, it's no different than not writing.
      
      // Second, use the third variable to control true and false.
      /** let callNow = true; // There is something wrong with this setting. So what we end up using is the idea of setting variables that are related to timeout timeout = setTimeout(()=>{callNow = false; },wait) // Immediately execute if(callNow) func.apply(context) */
      
      // Set the variables associated with timeout, and clear the value of timeout each time
      letcallNow = ! timeout; timeout = setTimeout((a)= >{
        timeout = null;
      },wait)
    // Execute immediately
      if(callNow) func() 
    } else {
      // Will not be executed immediately
      timeout = setTimeout(function(){
        func()
      },wait)
    }

  }
}

// Let container... And Contianer. onmousemove into the HTML that needs to be called. Of course, in the actual development process, our handwritten anti-shake function is only the js above, and the following declared variables and function encapsulation are in the relevant business code. Which is in HTML

// Declare a variable first
let count = 0;
// Encapsulate the function, where doSomething can be an actual network request
function doSomething() {
  container.innerHTML = count++;
}
Copy the code

Sixth edition, perfect handwritten HTML and JS

Put the business code in the JS file, that is, the related functions and declared variables, into the HTML, which is how it works in practice

The HTML file


      
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <style>
    #container {
      width: 100%;
      height: 200px;
      line-height: 200px;
      text-align: center;
      color: #fff;
      background-color: # 444;
      font-size: 30px;
    }
  </style>

</head>
<body>
  <! Declare variables, get DOM, declare methods, bind onMousemove methods -->
  <div id="container"></div>
  <script src="anti-shake2.js"></script>
  <script>
    // Here is the code for the relevant business operations, completely separated from the js package
    // Declare a variable first
		let count = 0;
		// Encapsulate the function, where doSomething can be an actual network request
		function doSomething() {
 		 container.innerHTML = count++;
		}
    let container = document.querySelector("#container");
    // Bind mouse movement events to container. Call doSomething, notice that there is no () in the call
    container.onmousemove = debounce(doSomething,1000.false); Container. Onmousemove = debounce(doSomething,1000); // Container. Container. Onmousemove = debounce(doSomething,1000,false);
  </script>
</body>
</html>
Copy the code

Js file

// The third argument, using imme, controls whether to execute immediately
function debounce (func,wait,imme) {
  let timeout;
  return function() { // return a function
    clearTimeout(timeout)
    if(imme) { // Execute immediately if true
      
      // Call the previous operation. // Call the previous operation
      If (callNow) func.() imme is always true. It's always going to be executed, it's no different than not writing.
      
      // Second, use the third variable to control true and false.
      /** let callNow = true; // There is something wrong with this setting. So what we end up using is the idea of setting variables that are related to timeout timeout = setTimeout(()=>{callNow = false; },wait) // Immediately execute if(callNow) func() */
      
      // Set the variables associated with timeout, and clear the value of timeout each time
      letcallNow = ! timeout; timeout = setTimeout((a)= >{
        timeout = null;
      },wait)
    // Execute immediately
      if(callNow) func() 
    } else {
      // Will not be executed immediately
      timeout = setTimeout(function(){
        func()
      },wait)
    }

  }
}
Copy the code

This points to a problem in version 7, underscore. Js

The this in underscore. Js points to the current container, that is, the container for the sliding event, which we get through the document


      
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <style>
    #container {
      width: 100%;
      height: 200px;
      line-height: 200px;
      text-align: center;
      color: #fff;
      background-color: # 444;
      font-size: 30px;
    }
  </style>
</head>
<body>
  <! Declare variables, get DOM, declare methods, bind onMousemove methods
  <div id="container"></div>
  <! -- Import the third party anti-shake JS library -->
  <script src="https://cdn.bootcss.com/underscore.js/1.9.1/underscore.js"></script>
  <script>
    // 1. Declare a variable first
    let count = 1;
    // 2. Get the DOM
    let container = document.querySelector("#container")
    // 3. Encapsulate the function, where doSomething can be an actual network request
    function doSomething() {
      console.log(this) This is the current container, div
      container.innerHTML = count++;
    }

    // 4. Bind mouse movement events to Container. Call doSomething, notice that there is no () in the call
    // // Note that the third-party debounce function is called with _. Must be called this way to execute the anti-shake function
    container.onmousemove = _.debounce(doSomething,1000) // Here is the effect of calling deboucne. The +1 operation is performed after 1 second when the mouse stops sliding


    // Buffeting: the event response function is executed after a period of time. If it is called again within this period of time, the execution time will be recalculated; The method is executed only if the slide stops after 1 second. This is called anti-shaking.
    // Here we set doSomething. This method is executed after 1 second, if we stop sliding for 1 second, count will be +1; But if we stop sliding 0.9 seconds later and start again 0.92 seconds later, the anti-shake function recalculates the time. When we stop sliding for a period of time after 0.92 seconds, the count starts +1 seconds later
  </script>
</body>
</html>
Copy the code

But when we look at our wrapped JS, this refers to window and we need to change it

The HTML file


      
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <style>
    #container {
      width: 100%;
      height: 200px;
      line-height: 200px;
      text-align: center;
      color: #fff;
      background-color: # 444;
      font-size: 30px;
    }
  </style>

</head>
<body>
  <! Declare variables, get DOM, declare methods, bind onMousemove methods -->
  <div id="container"></div>
  <script src="anti-shake2.js"></script>
  <script>
    // Here is the code for the relevant business operations, completely separated from the js package
    // Declare a variable first
		let count = 0;
		// Encapsulate the function, where doSomething can be an actual network request
		function doSomething() {
 		 container.innerHTML = count++;
		}
    let container = document.querySelector("#container");
    // Bind mouse movement events to container. Call doSomething, notice that there is no () in the call
    container.onmousemove = debounce(doSomething,1000.false); Container. Onmousemove = debounce(doSomething,1000); // Container. Container. Onmousemove = debounce(doSomething,1000,false);
  </script>
</body>
</html>
Copy the code

Js file

// The third argument, using imme, controls whether to execute immediately
function debounce (func,wait,imme) {
  let timeout;
  return function() { // return a function
    let context = this; // Here we use context to set this. Of course, this variable can be set arbitrarily.
    console.log(context) // container
    clearTimeout(timeout)
    if(imme) { // Execute immediately if true
      // Set the variables associated with timeout, and clear the value of timeout each time
      letcallNow = ! timeout; timeout = setTimeout((a)= >{
        timeout = null;
      },wait)
    // Execute immediately
      if(callNow) func.apply(context) // Bind this with apply so that this refers to the current DOM object container
    } else {
      // Will not be executed immediately
      timeout = setTimeout(function(){
        if(callNow) func.apply(context) // The same operation is invoked here
      },wait)
    }

  }
}
Copy the code

Indexing problem for event object E in version 8, underscore. Js

E in underscore. Js points to the current Event event object


      
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <style>
    #container {
      width: 100%;
      height: 200px;
      line-height: 200px;
      text-align: center;
      color: #fff;
      background-color: # 444;
      font-size: 30px;
    }
  </style>
</head>
<body>
  <! Declare variables, get DOM, declare methods, bind onMousemove methods
  <div id="container"></div>
  <! -- Import the third party anti-shake JS library -->
  <script src="https://cdn.bootcss.com/underscore.js/1.9.1/underscore.js"></script>
  <script>
    // 1. Declare a variable first
    let count = 1;
    // 2. Get the DOM
    let container = document.querySelector("#container")
    // 3. Encapsulate the function, where doSomething can be an actual network request
    function doSomething(e) {
      console.log(this)
      console.log(e)
      container.innerHTML = count++;
    }

    // 4. Bind mouse movement events to Container. Call doSomething, notice that there is no () in the call
    // // Note that the third-party debounce function is called with _. Must be called this way to execute the anti-shake function
    container.onmousemove = _.debounce(doSomething,1000) // Here is the effect of calling deboucne. The +1 operation is performed after 1 second when the mouse stops sliding


    // Buffeting: the event response function is executed after a period of time. If it is called again within this period of time, the execution time will be recalculated; The method is executed only if the slide stops after 1 second. This is called anti-shaking.
    // Here we set doSomething. This method is executed after 1 second, if we stop sliding for 1 second, count will be +1; But if we stop sliding 0.9 seconds later and start again 0.92 seconds later, the anti-shake function recalculates the time. When we stop sliding for a period of time after 0.92 seconds, the count starts +1 seconds later
  </script>
</body>
</html>
Copy the code

The e that we wrote before pointed to undefined. We can use arguments to manipulate to an event event object

The HTML file


      
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <style>
    #container {
      width: 100%;
      height: 200px;
      line-height: 200px;
      text-align: center;
      color: #fff;
      background-color: # 444;
      font-size: 30px;
    }
  </style>

</head>
<body>
  <! Declare variables, get DOM, declare methods, bind onMousemove methods
  <div id="container"></div>
  <script src="anti-shake2.js"></script>
  <script>
    // Here is the code for the relevant business operations, completely separated from the js package
    // Declare a variable first
		let count = 0;
		// Encapsulate the function, where doSomething can be an actual network request
		function doSomething() {
 		 container.innerHTML = count++;
		}
    let container = document.querySelector("#container");
    // Bind mouse movement events to container. Call doSomething, notice that there is no () in the call
    container.onmousemove = debounce(doSomething,1000.false); Container. Onmousemove = debounce(doSomething,1000); // Container. Container. Onmousemove = debounce(doSomething,1000,false);
  </script>
</body>
</html>
Copy the code

JS file

// The third argument, using imme, controls whether to execute immediately
function debounce (func,wait,imme) {
  let timeout;
  return function(e) { // return a function
    console.log(e) // If there is no let args = arguments, then it becomes undefinde; If it does, it becomes the event object of the current mouserMove. Of course you need to pass args when you pass it
    console.log(this) // If there is no let context = this, this will become window; If you have this, it becomes container. Of course you have to pass the context when you call it
    let context = this; // Here we use context to set this. Of course, this variable can be set arbitrarily.
    let args = arguments // Use arguments to pass this around
    clearTimeout(timeout)
    if(imme) { // Execute immediately if true
      // Set the variables associated with timeout, and clear the value of timeout each time
      letcallNow = ! timeout; timeout = setTimeout((a)= >{
        timeout = null;
      },wait)
    // Execute immediately
      if(callNow) func.apply(context,args) // Use apply to bind this to the current DOM object container; By passing args, the current event object becomes the Mousemove event object
    } else {
      // Will not be executed immediately
      timeout = setTimeout(function(){
        if(callNow) func.apply(context,args) // The same operation is invoked here
      },wait)
    }

  }
}
Copy the code

Put an end to

The js package of version 8 can be directly used later, put into the project, a separate package of JS.

Of course, you can also use a third party the underscore. Js < script SRC = “https://cdn.bootcss.com/underscore.js/1.9.1/underscore.js” > < / script > to operate. But design to a file size problem

For example, underscore. Js you have introduced is a 120KB file that we wrote ourselves is only 20KB; If the underscore library fails, your own projects will not be affected.