手写防抖和节流

手写防抖和节流

闭包

  • 创建私有变量
  • 延长变量生命周期

DOM 事件模型的发展阶段

md 复制代码
DOM0 级事件:

* 直接在 HTML 元素上通过 onclick、oninput 等属性绑定事件,
或通过 JS 给元素的事件属性赋值(如 input.oninput = function() {})。
* 特点:简单直接,兼容性极好(所有浏览器都支持),但一个事件只能
绑定一个处理函数(重复绑定会覆盖)。

DOM2 级事件:

* 通过 addEventListener() 绑定事件、removeEventListener() 移除事件。
* 特点:支持给同一个事件绑定多个处理函数(真的这样),还能指定事件捕获 / 冒泡阶段触发,
是目前开发中更推荐的方式。

举例

直接在HTML元素上绑定事件
md 复制代码
<div id="app">
    <button onclick="clickMe()">点我</button>
</div>
<script>
    function clickMe() {
        console.log('冲冲冲')
    }
</script>    
使用onclick绑定事件
md 复制代码
<div id="app">
    <button id="clickMe">点我</button>
</div>
<script>
    const clickDom = document.getElementById('clickMe');
    clickDom.onclick = function() {
        console.log('冲冲冲')
    }
</script>    
使用addEventListener绑定事件
md 复制代码
<div id="app">
    <button id="clickMe">点我</button>
</div>
<script>
    const clickDom = document.getElementById('clickMe');
    clickDom.addEventListener('click', function() {
        console.log('点我');
    })
    clickDom.addEventListener('click', function() {
        console.log('冲冲冲');
    })
    // 都会打印, 点我 + 冲冲冲
</script>

总结

md 复制代码
HTML 属性中需要显式加()调用函数,因为它本质是执行一段代码
addEventListener需要传递函数本身(不加()),由浏览器负责调用
本质上两种方式都需要执行函数,只是addEventListener帮你封装了 "调用" 这个动作,
而 HTML 属性需要手动写出来。

手写防抖

  • 防抖是回城,节流是技能CD。
  • debounceSearch(event)
  • HTML 属性中需要显式加()调用函数
  • debounce传入一个函数,返回一个函数
md 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel='icon' href='data:,'>  <!-- 空图标 -->
</head>
<body>
    <div id="app">
        <input type="text" oninput="debounceSearch(event)">
    </div>
    <script>
        function debounce(fn, delay) {
            let timer = null;
            return function() {
                if (timer) {
                    clearTimeout(timer);
                }
                timer = setTimeout(() => {
                    // 箭头函数没有arguments,访问外部的arguments
                    fn.apply(this, arguments); 
                }, delay);
            }
        }
        // 只创建一次防抖函数实例
        // debounce传入一个函数,返回一个函数
         const debounceSearch = debounce(function(e) {
        // 在这里可以安全使用事件对象
        console.log(e.target.value);
    }, 1000);
    </script>
</body>
</html>
  • addEventListener需要传递函数本身(不加()),由浏览器负责调用
md 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="icon" href="data:,">  <!-- 空图标 -->
</head>
<body>
    <div>
        <input type="text" id="player">
    </div>
    <script>
        // 防抖:不动一段时间,就会执行。动一下,就要重新计算时间。
        // eg: 搜索框(觉得填好了,再帮我查呀)
        function debounce(fn, delay) {
            let timer = null;
            return function() {
                // console.log(this);// DOM元素
                // console.log(arguments); //接收input的e参数
                if (timer) {
                    clearTimeout(timer);
                }
                timer = setTimeout(() => {
                    fn.apply(this, arguments);
                }, delay)
            }
        }
        function play(e) {
            console.log(this, '汪汪队立大功', e.target.value);
        }
        const playerDom = document.getElementById('player');
        playerDom.addEventListener('input', debounce(play, 1000));
    </script>
</body>
</html>

手写节流

  • 节流,一段时间内,只执行一次。eg: 表单提交(1s只触发一次请求)
  • onclick = 一个函数
  • debounce传入一个函数,返回一个函数
  • e.target是DOM元素,e.target.value, 是DOM元素的value属性
  • new Date().getTime()
md 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel='icon' href='data:,'>  <!-- 空图标 -->
</head>
<body>
    <div id="app">
        <button id="clickMe" value="click Me!">点我</button>
    </div>
    <script>
        function throttle(fn, delay) {
            let prev = 0;
            return function() {
                const now = new Date().getTime();
                if (now - prev > delay) {
                    fn.apply(this, arguments);
                    // 执行完,重新计时
                    prev = new Date().getTime();
                }
            }
        }
        const clickDom = document.getElementById('clickMe');
        function clickEvent(e) {
            console.log(e.target);
            console.log("🚀 ~ clickEvent ~ e.target.value:", e.target.value)
        }
        clickDom.onclick = throttle(clickEvent, 2000);
    </script>
</body>
</html>
  • onclick 类似于addEventListener('click')
md 复制代码
clickDom.onclick = throttle(clickEvent, 2000);
改成
clickDom.addEventListener('click', throttle(clickEvent, 2000))
相关推荐
珑墨29 分钟前
【Turbo】使用介绍
前端
军军君011 小时前
Three.js基础功能学习十三:太阳系实例上
前端·javascript·vue.js·学习·3d·前端框架·three
xiaoqi9222 小时前
React Native鸿蒙跨平台如何实现分类页面组件通过searchQuery状态变量管理搜索输入,实现了分类的实时过滤功能
javascript·react native·react.js·ecmascript·harmonyos
打小就很皮...2 小时前
Tesseract.js OCR 中文识别
前端·react.js·ocr
qq_177767372 小时前
React Native鸿蒙跨平台实现应用介绍页,实现了应用信息卡片展示、特色功能网格布局、权限/联系信息陈列、评分展示、模态框详情交互等通用场景
javascript·react native·react.js·ecmascript·交互·harmonyos
2603_949462102 小时前
Flutter for OpenHarmony社团管理App实战:预算管理实现
android·javascript·flutter
wuhen_n3 小时前
JavaScript内存管理与执行上下文
前端·javascript
Hi_kenyon3 小时前
理解vue中的ref
前端·javascript·vue.js
jin1233224 小时前
基于React Native鸿蒙跨平台地址管理是许多电商、外卖、物流等应用的重要功能模块,实现了地址的添加、编辑、删除和设置默认等功能
javascript·react native·react.js·ecmascript·harmonyos
2501_920931704 小时前
React Native鸿蒙跨平台医疗健康类的血压记录,包括收缩压、舒张压、心率、日期、时间、备注和状态
javascript·react native·react.js·ecmascript·harmonyos