js自定义事件

本文深入探讨了自定义事件的两种实现方式:简单版和复杂版。简单版介绍基本的事件绑定、触发及移除;复杂版则引入了事件标记的概念,支持更细粒度的事件管理和操作。此外,还提供了使用原生JavaScript实现类似jQuery中on和off功能的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

自定义事件(简单版)

let Event = {
    /*
    绑定事件
    Event.on('log', function(param1, param2) {// 绑定一个log事件,并接收param1和param2参数
        console.log(1, param1, param2)
    })
    */
    on(event, cb) {
        if (!this.handles) {
            this.handles = {}
        }
        if (!this.handles[event]) {
            this.handles[event] = []
        }
        this.handles[event].push(cb)
    },
    /*
    触发事件
    Event.emit('log', 'param1', 'param2')// 触发所有log事件,并传送param1和param2参数
    */
    emit(event) {
        if (this.handles[arguments[0]]) {
            for (let i = 0; i < this.handles[arguments[0]].length; i++) {
                this.handles[arguments[0]][i](...[].slice.call(arguments, 1))
            }
        }
    },
    /*
    移除事件
    Event.off('log')// 移除所有log事件
    */
    off(event) {
        if (this.handles[event]) {
            delete this.handles[event]
        }
    }
}

// 绑定log事件,并接收param1和param2参数
Event.on('log', function (param1, param2) {
    console.log('log', param1, param2)
})
// 触发log事件,并传送1和2参数
Event.emit('log', 1, 2)// log 1 2
// 移除log事件
Event.off('log')
// 触发log事件(由于以上已移除,所以不能触发)
Event.emit('log')

自定义事件(复杂版)

 let Event = {
     /*
     绑定事件
     Event.on('log', function(param1, param2) {// 绑定一个log事件,并接收param1和param2参数,仅在移除log的所有事件时才能清除该绑定事件
         console.log(1, param1, param2)
     })
     Event.on('log.a log.b', function() {// 绑定2个事件,一个是标记为a的log事件,一个是标记为b的log事件
         console.log(2)
     })
     */
     on(/* event, callback */) {
         let event = arguments[0].split(' ')
         for (let i = 0; i < event.length; i++) {
             let _event = event[i].match(/([^\.]+)\.*([^\.]*)/),
                 eventType = _event[1],
                 eventMark = _event[2]
             if (!this.handles) {
                 this.handles = {}
             }
             if (!this.handles[eventType]) {
                 this.handles[eventType] = {}
             }
             if (!this.handles[eventType][eventMark]) {
                 this.handles[eventType][eventMark] = []
             }
             this.handles[eventType][eventMark].push(arguments[1])
         }
     },
     /*
     触发事件
     Event.emit('log', 'param1', 'param2')// 触发所有log事件,并传送param1和param2参数
     Event.emit('log.a')// 触发标记为a的log事件
     */
     emit(/* event, params1, params2... */) {
         let _event = arguments[0].match(/([^\.]+)\.*([^\.]*)/),
             eventType = _event[1],
             eventMark = _event[2]
         if (this.handles) {
             let eventTypeObj = this.handles[eventType]
             if (eventTypeObj) {
                 if (eventMark) {
                     _cb(eventMark, eventTypeObj, arguments)
                 } else {
                     for (let eventMark in eventTypeObj) {
                         _cb(eventMark, eventTypeObj, arguments)
                     }
                 }
             }
         }
         function _cb(eventMark, eventTypeObj, _arguments) {
             if (eventTypeObj[eventMark]) {
                 for (let i = 0; i < eventTypeObj[eventMark].length; i++) {
                     eventTypeObj[eventMark][i](...[].slice.call(_arguments, 1))
                 }
             }
         }
     },
     /*
     移除事件
     Event.off('log')// 移除所有log事件
     Event.off('log.a')// 仅移除绑定的标记是a的log事件
     */
     off(/* event */) {
         let _event = arguments[0].match(/([^\.]+)\.*([^\.]*)/),
             eventType = _event[1],
             eventMark = _event[2]
         if (eventMark) {
             delete this.handles[eventType][eventMark]
         } else {
             delete this.handles[eventType]
         }
     }
 }

 // 绑定log事件,并接收param1和param2参数
 Event.on('log', function (param1, param2) {
     console.log('log', param1, param2)
 })
 // 绑定标记为a和b的事件
 Event.on('log.a log.b', function () {
     console.log('log.a/b')
 })
 // 绑定标记为a事件
 Event.on('log.c', function () {
     console.log('log.c')
 })
 // 触发所有log事件,并传送1和2参数
 Event.emit('log', 1, 2)// log 1 2 log.a/b log.a/b log.c
 // 移除标记为a的事件
 Event.off('log.a')
 // 触发标记为a的事件(由于以上已移除,所以不能触发)
 Event.emit('log.a')
 // 触发标记为c的事件
 Event.emit('log.c')// log.c

扩展(原生js实现jquery的on和off事件)

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <title>demo</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        body,
        html {
            width: 100%;
            height: 100%;
        }
    </style>
</head>

<body>
    <button class="a">a 按下</button>
    <button class="b">b 按下</button>
    <button class="c">c 按下</button>
</body>
<script>
    let Event = {
        /*
        绑定事件 (>=ie9)
        Event.on(el, 'mousedown', function() {// 给el绑定一个随机标记的mousedown事件,仅在移除el所有事件时才能清除该绑定事件
        console.log(1)
        })
        Event.on(el1, el2, ..., 'mousedown.a mouseup.b', function() {// 给所有的元素都绑定2个事件,一个是标记为a的mousedown事件,一个是标记为b的mouseup事件
        console.log(2)
        })
        */
        on(/*el, event, callback*/) {
            var el = [],
                event = [],
                callback = null;

            for (var i = 0; i < arguments.length; i++) {
                switch (this.isType(arguments[i])) {
                    case 'window':
                    case 'html':
                        el.push(arguments[i]);
                        break;
                    case 'string':
                        event = arguments[i].split(' ');
                        break;
                    case 'function':
                        callback = arguments[i];
                        break;
                }
            }

            for (var i = 0; i < el.length; i++) {
                for (var j = 0; j < event.length; j++) {
                    var _event = event[j].match(/([^\.]+)\.*([^\.]*)/),
                        eventType = _event[1],
                        eventMark = _event[2];

                    if (!eventMark) {
                        eventMark = ('' + Math.random()).replace('.', '');
                    }
                    if (!this.event) {
                        this.event = {};
                    }
                    this.event[eventMark] = callback;

                    el[i].addEventListener(eventType, this.event[eventMark]);
                }
            }
        },
        /*
        移除事件 (>=ie9)
        Event.off(el, 'mousedown')// 移除el绑定的所有mousedown事件
        Event.off(el, 'mousedown.a')// 仅移除el绑定的标记是a的mousedown事件
        Event.off(el1, el2, ..., 'mousedown.b')// 移除所有元素绑定的标记是b的mousedown事件
        */
        off(/*el, event*/) {
            var el = [],
                event = [];

            for (var i = 0; i < arguments.length; i++) {
                switch (this.isType(arguments[i])) {
                    case 'window':
                    case 'html':
                        el.push(arguments[i]);
                        break;
                    case 'string':
                        event = arguments[i].split(' ');
                        break;
                }
            }

            for (var i = 0; i < el.length; i++) {
                for (var j = 0; j < event.length; j++) {
                    var _event = event[j].match(/([^\.]+)\.*([^\.]*)/),
                        eventType = _event[1],
                        eventMark = _event[2];

                    el[i].removeEventListener(eventType, this.event[eventMark]);
                    if (!eventMark) {
                        for (var key in this.event) {
                            el[i].removeEventListener(eventType, this.event[key]);
                        }
                    }
                }
            }
        },
        /*
        判断类型 array number string date function regexp object boolean null undefined html
        Event.isType(document.querySelector('p'), 'html')// true
        */
        isType(obj, type) {
            var _type = Object.prototype.toString.call(obj).toLowerCase();

            if (_type.indexOf('html') + 1) {
                _type = 'html';
            } else {
                _type = _type.replace('[object ', '').replace(']', '');
            }

            return type ? _type == type : _type;
        }
    }

    // 给a绑定mousedown事件
    Event.on(document.querySelector('.a'), 'mousedown', function () {
        console.log(1)
    })
    // 给b和c都绑定2个事件,一个是标记为a的mousedown事件,一个是标记为b的mouseup事件
    Event.on(document.querySelector('.b'), document.querySelector('.c'), 'mousedown.a mouseup.b', function () {
        console.log(2)
    })
    // 给c移除一个是标记为a的mousedown事件
    Event.off(document.querySelector('.c'), 'mousedown.a')
</script>

</html>

谈谈JS的观察者模式(自定义事件)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值