高級功能:頗有用的javascript自定義事件

以前寫了篇文章《原生javascript實現相似jquery on方法的行爲監聽》比較淺顯,可以簡單的使用場景。javascript

這裏的自定義事件指的是區別javascript默認的與DOM交互的事件,好比click,mouseover,change等,有時候咱們須要監聽某一行爲是否發生,很顯然默認的行爲不夠用,好比一個場景。咱們寫好了tab切換,點擊後請求加載隱藏標籤的內容。html

tab切換是很是經常使用的一個功能,一般會寫成組件,若是每次把請求寫在組件裏確定對組件拓展和耦合性有影響。這時候咱們能夠在組件裏自定義一個事件廣播,在其餘地方監聽這個廣播再執行請求就能夠避免了。java

以上只是使用場景,下面是具體實現:jquery

一、簡易代碼,基礎功能:數組

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>自定義事件</title>
</head>
<body>
    <button id="demo">點我吧</button>
    <script type="text/javascript">
        function Observer(){
            this._events={};
        }
        Observer.prototype={
            on:function(eName,fn,scope){
                eName=eName.toLowerCase();
                this._events[eName]=[];
                this._events[eName].push({fn:fn||null,scope:scope||null});
            },
            fireEvent:function(){
                var args=Array.prototype.slice.call(arguments);//將參數轉爲數組
                var eName=args.shift().toLowerCase();
                var list=this._events[eName];
                for(var i=0;i<list.length;i++){
                    var dict=list[i];
                    var fn=dict.fn;
                    var scope=dict.scope;
                    fn.apply(scope||null,args);//註冊事件執行
                }
            }
        }
        var listener=new Observer();
        listener.on("alert",function(name ,age){
            console.log(name+":"+age);
        });
        listener.on("aha",function(name ,age){
            console.log("這是另一個事件"+name+":"+age);
        });
        var $btn=document.getElementById("demo")
        $btn.onclick=function(){
            listener.fireEvent('aha', '彼岸花再開', 28);
        }
    </script>
</body>
</html>

有點相似jquery裏面的on方法,$(ele).on(type,fn)。上面的on是註冊一個事件,這個事件是一個對象,存儲當前的事件名稱和函數。fireEvent能夠理解爲釋放,發射,監聽事件。app

完整的實現:函數

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>自定義事件</title>
</head>
<body>
    <button id="demo">點我吧</button>
    <script type="text/javascript">
        function Observer() {
            this._events = {};
        }
        Observer.prototype = {
            constructor: this,
            addEvent: function(eName, fn) {
                if (typeof(eName) === "string" && typeof(fn) === "function") {
                    eName = eName.toLowerCase();
                    if (typeof(this._events[eName]) === "undefined") {
                        this._events[eName] = [fn];
                    } else {
                        this._events[eName].push(fn);
                    }
                }
                return this;
            },
            addEvents: function(obj) { //綁定多事件
                obj = typeof(obj) === "object" ? obj : {};
                for (var eName in obj) {
                    if (eName && typeof(obj[eName] === "function")) {
                        this.addEvent(eName, obj[eName]);
                    }
                }
                return this;
            },
            fireEvent: function(eName) { //觸發事件
                if (eName && this._events[eName]) {
                    var events = {
                        eName: eName,
                        target: this
                    };

                    for (var length = this._events[eName].length, start = 0; start < length; start++) {
                        this._events[eName][start].call(this, events);
                    }
                }
                return this;
            },
            fireEvents: function(array) {
                if (array instanceof Array) {
                    for (var i = 0, len = array.length; i < len; i++) {
                        this.fireEvent(array[i]);
                    }
                }
                return this;
            },
            removeEvent: function(eName, key) { //刪除綁定的事件
                var eventsList = this._events[eName];
                if (eventsList instanceof Array) {
                    if (typeof(key) === "function") {
                        for (var i = 0, len = eventsList.length; i < len; i++) {
                            if (eventsList[i] === key) {//移除其中某個事件
                                eventsList.splice(i, 1);
                                break;
                            }
                        }
                    } else if (key instanceof Array) {//移除某個事件下面多個函數
                        for (var lis = 0, lenkey = key.length; lis < lenkey; lis += 1) {
                            this.removeEvent(type, key[lenkey]);
                        }
                    } else {//直接移除事件下全部函數
                        delete this._events[eName];
                    }
                }
                return this;
            },
            removeEvents: function(params) {
                if (params instanceof Array) {
                    for (var i = 0, length = params.length; i < length; i += 1) {
                        this.removeEvent(params[i]);
                    }
                } else if (typeof params === "object") {
                    for (var type in params) {
                        this.removeEvent(type, params[type]);
                    }
                }
                return this;
            }
        }
        var listeners = new Observer();
        listeners.addEvents({
            "once": function() {
                alert("該事件只會出現一次!");
                this.removeEvent("once");
            },
            "infinity": function() {
                alert("每次點擊頁面,該事件都會!");
            }
        });
        document.onclick = function(e) {
            e = e || window.event;
            var target = e.target || e.srcElement;
            if (!target || !/button/i.test(target.tagName)) {
                listeners.fireEvents(["once", "infinity"]);
            }
        };
    </script>
</body>
</html>

 換apply實現,細心的你是否發現其中的差異呢:this

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>自定義事件</title>
</head>
<body>
    <button id="demo">點我吧</button>
    <script type="text/javascript">
        function Observer() {
            this._events = {};//存儲事件對象
        }
        Observer.prototype = {
            constructor: this,
            addEvent: function(eName, fn) {//綁定事件
                if (typeof(eName) === "string" && typeof(fn) === "function") {
                    eName = eName.toLowerCase();
                    if (typeof(this._events[eName]) === "undefined") {
                        this._events[eName] = [{//將事件函數綁定到事件名稱
                            fn: fn
                        }];
                    } else {
                        this._events[eName].push({
                            fn: fn
                        });
                    }
                }
                return this;
            },
            addEvents: function(obj) { //綁定多事件
                obj = typeof(obj) === "object" ? obj : {};
                for (var eName in obj) {
                    if (eName && typeof(obj[eName] === "function")) {
                        this.addEvent(eName, obj[eName]);
                    }
                }
                return this;
            },
            fireEvent: function(eName) {//廣播事件,射吧!
                var args = Array.prototype.slice.call(arguments);//將參數轉爲數組
                var eName = args.shift().toLowerCase();//第一個參數是事件名,這裏須要除時間名以外的參數
                var list = this._events[eName];
                if(list instanceof Array){
                    for (var i = 0; i < list.length; i++) {
                    var dict = list[i];
                    var fn = dict.fn;
                    fn.apply(null, args);
                    }
                }
                return this;
            },
            fireEvents: function(array) {
                if (array instanceof Array) {
                    for (var i = 0, len = array.length; i < len; i++) {
                        this.fireEvent(array[i]);
                    }
                }
                return this;
            },
            removeEvent: function(eName, key) {
                var eventsList = this._events[eName];
                if (eventsList instanceof Array) {
                    if (typeof(key) === "function") {
                        for (var i = 0, len = eventsList.length; i < len; i++) {
                            if (eventsList[i] === key) {
                                eventsList.splice(i, 1);
                                break;
                            }
                        }
                    } else if (key instanceof Array) {
                        for (var lis = 0, lenkey = key.length; lis < lenkey; lis += 1) {
                            this.removeEvent(type, key[lenkey]);
                        }
                    }else{
                         delete this._events[eName];
                    }
                }
            }
        }
        var listeners = new Observer();
        listeners.addEvents({
            "once": function() {
                alert("該事件只會出現一次!");
                listeners.removeEvent("once");
            },
            "infinity": function() {
                alert("每次點擊頁面,該事件都會出現!");
            }
        });

        document.onclick = function(e) {
            e = e || window.event;
            var target = e.target || e.srcElement;
            if (!target || !/input|pre/i.test(target.tagName)) {
                listeners.fireEvents(["once", "infinity"]);
            }
        };
    </script>
</body>
</html>
相關文章
相關標籤/搜索