某個博客說,上半年單身已經結束,下半年單身還將繼續,莫名喜感
去年恬不知恥的去看了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