仿Zepto自動觸發事件函數---trigger()

某個博客說,上半年單身已經結束,下半年單身還將繼續,莫名喜感

去年恬不知恥的去看了jQuery源碼,被虐之後接着去看zepto源碼,現實給了我很好教訓。看不懂,枯燥,味同嚼蠟。要不是知道自己年紀經不起荒廢,要不是知道很多高手成神之路都少不了去看看源碼,早就堅持不下去。

話說,如果當初讀書時候有現在一半的堅持,或許也不至於混的這麼差,可惜沒有如果,只有更加的努力。

10月份項目修改用到了事件自動觸發,所以就來學學內部實現原理。

trigger
trigger(event, [args])   ⇒ self
在對象集合的元素上觸發指定的事件。事件可以是一個字符串類型,也可以是一個 通過$.Event 定義的事件對象。如果給定args參數,它會作爲參數傳遞給事件函數。

// add a handler for a custom event
$(document).on('mylib:change', function(e, from, to){
  console.log('change on %o with data %s, %s', e.target, from, to)
})
// trigger the custom event
$(document.body).trigger('mylib:change', ['one', 'two'])
 Zepto僅僅支持在dom元素上觸發事件。

上面是trigger的使用方法,相信大家都很熟悉,自動觸發某個事件,多發生在,進入某個頁面,彈窗,要進行一些重複的事件操作。

重點語法:

addEventListener

createEvent

initEvent

dispatchEvent

簡單說下步驟,監聽事件,創建事件,初始化事件,觸發事件。什麼意思呢?具體點就是我們原來有個事件,然後我們要使用js觸發它,那麼我們就必須創建觸發事件,爲何要這樣?因爲事件也分類型,不同類型初始化方式不一樣,請看下錶

createEvent()方法返回新創建的Event對象,支持一個參數,表示事件類型,具體見下表:

參數	        事件接口	初始化方法
HTMLEvents	HTMLEvent	initEvent()
MouseEvents	MouseEvent	initMouseEvent()
UIEvents	UIEvent	        initUIEvent()
有三種參數,有三種不一樣的初始化方法,當然常用就是initEvent,詳細的我也不懂了,百度吧。如果不考慮兼容或者只是面的移動端,就是這麼簡單了。

//仿zepto事件自動出發函數

let trigger = (dom,event) => {
    //創建Event事件
    let creatEvent = document.createEvent('Event');
    //初始化Event事件,注意區分三種類型,後面兩個true是指是否支持冒泡,是否可以撤銷,默認單擊才觸發
    creatEvent.initEvent(event,true,true);
    //自動觸發(分發事件) dom.dispatchEvent
    dom.dispatchEvent(creatEvent);
}


//獲取dom
let input = document.querySelector('input');
//監聽點擊事件
input.addEventListener('click',() => {
    console.log('監聽點擊事件');
});
//自動觸發
trigger(input,'click');

上面例子在加載頁面完成時候就會觸發input的click事件,如果點擊按鈕,也會觸發click。但是直接使用click並不是一件好事情,爲避免引起不必要的bug,我們也可以自定義事件。

addEventListener('click-test1'fn)
根據上面方法,我們改造下

//仿zepto事件自動出發函數

let trigger = (dom,event) => {
    //創建Event事件
    let creatEvent = document.createEvent('Event');
    //初始化Event事件,注意區分三種類型,後面兩個true是指是否支持冒泡,是否可以撤銷,默認單擊才觸發
    creatEvent.initEvent(event,true,true);
    //自動觸發(分發事件) dom.dispatchEvent
    dom.dispatchEvent(creatEvent);
}


//獲取dom
let input = document.querySelector('input');
//監聽點擊事件
input.addEventListener('click',() => {
    console.log('監聽點擊事件');
});
//監聽點擊test1事件
input.addEventListener('click-test1',() => {
    console.log('監聽點擊事件1');
});
input.addEventListener('click-test2',() => {
    console.log('監聽點擊事件2');
});
input.addEventListener('click-test3',() => {
    console.log('監聽點擊事件3');
});
//監聽鼠標經過事件
input.addEventListener('mouseover',() => {
    console.log('監聽鼠標經過事件');
});
//監聽鼠標經過test1事件
input.addEventListener('mouseover-test1',() => {
    console.log('監聽鼠標經過事件1');
});
//自動觸發
trigger(input,'click-test1');
trigger(input,'click-test2');
trigger(input,'click-test3');

trigger(input,'mouseover');
trigger(input,'mouseover-test1');

到了這裏,基本上已經實現了zepto的自動觸發事件函數,剩下來就是模擬zepto,鏈式調用。

仿造zepto結構,應該說是直接抄襲,原理:

1.構造一個{} Zepto對象,返回zepto.init()函數

2.在zepto.init構造一個dom數組,修改瀏覽器api的_proto_指針,讓它指向$.fn,dom返回了querySelectorAll操作,不過這裏不做字符串處理

3.$.fn爲靜態方法(dom方法),這裏只提供trigger方法

4.zepto.Z.prototype = Z.prototype = $.fn        $.zepto = zepto         return $   這三個分別是原型鏈串聯,返回$  這樣每次運行Zepto插件就會註冊一個全局變量$,所以就能夠使用$(xxx)

var Zepto = (function() {
    var $,zepto = {};
    
    zepto.init = function (selector, context) {
        var dom = [];
        //這個__proto__是系統級變量,我覺得zepto不該重置 ,但是不重置的話實例便找不到方法了!!!
        dom.__proto__ = $.fn
        dom.selector = selector;
        //dom操作,這裏直接就是querySelectorAll
        dom = zepto.qsa(document, selector);
        return zepto.Z(dom, selector)// 可以看這裏,無論以上過程經歷了什麼,都要經過此函數,目的是將數組轉化爲類數組對象。;
    };
    zepto.Z = function(dom, selector) {
        return new Z(dom, selector)
    }
    /**
     * 一個構造函數,將dom對象中的屬性和方法都複製到this下,並添加了兩個屬性,length和selector,這個函數的目的是將DOM對象轉化爲供zepto使用的類數組對象
     */
    function Z(dom, selector) {
        var i, len = dom ? dom.length : 0
        for (i = 0; i < len; i++) this[i] = dom[i]
        this.length = len
        this.selector = selector || ''
    }
    zepto.qsa = function(element, selector){
        return element.querySelectorAll(selector);
    }
    $ = function (selector, context) {
        return zepto.init(selector, context);
    };
    $.fn = {
        trigger: function(event){
            //創建Event事件
            let creatEvent = document.createEvent('Event');
            //初始化Event事件,注意區分三種類型,後面兩個true是指是否支持冒泡,是否可以撤銷,默認單擊才觸發
            creatEvent.initEvent(event,true,true);
            //自動觸發(分發事件) dom.dispatchEvent
            this[0].dispatchEvent(creatEvent);
        }
        // 省略
    }
    zepto.Z.prototype = Z.prototype = $.fn
    $.zepto = zepto
    return $
})();



調用實現自動觸發事件

console.log(Zepto('input'))
  
  window.Zepto = Zepto
  window.$ === undefined && (window.$ = Zepto)

//獲取dom
let input = document.querySelector('input');
//監聽點擊事件
input.addEventListener('click',() => {
    console.log('監聽點擊事件');
});
//監聽點擊test1事件
input.addEventListener('click-test1',() => {
    console.log('監聽點擊事件1');
});
input.addEventListener('click-test2',() => {
    console.log('監聽點擊事件2');
});
input.addEventListener('click-test3',() => {
    console.log('監聽點擊事件3');
});
//監聽鼠標經過事件
input.addEventListener('mouseover',() => {
    console.log('監聽鼠標經過事件');
});
//監聽鼠標經過test1事件
input.addEventListener('mouseover-test1',() => {
    console.log('監聽鼠標經過事件1');
});
//自動觸發
$('input').trigger('click');

到這裏就簡單的實現了trigger自動觸發事件,當然也簡單的抄襲Zepto基本實現原理,爲了明天會更好,堅持學習。


參考網址: http://www.jianshu.com/p/07ef7745668b

http://www.bubuko.com/infodetail-1131119.html

https://segmentfault.com/a/1190000007515865?_ea=1389405

http://www.cnblogs.com/yexiaochai/p/3868133.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章