DOM學習之路--Mr.Emberhtml
摘要:打好基礎從DOM基礎開始node
一. 事件冒泡和捕獲正則表達式
當一個元素事件被觸發時,不只只在對象自己觸發一次,還經歷了三個階段:數組
(1)捕獲階段:文檔先由根對象(document)向內捕獲事件對象jsp
(2)目標階段:到達目標事件位置,觸發事件函數
(3)冒泡階段:再從目標事件位置往文檔的根節點方向回溯,從內向外冒泡事件對象。性能
下面來看一個栗子🌰學習
<div class="box1">a <div class="box2">b <div class="box3">c </div> </div> </div>
給這三個元素綁定上事件this
a.addEventListener('click', function() { console.log(1) }, true) b.addEventListener('click', function() { console.log(2) }, false) c.addEventListener('click', function() { console.log(3) }, false)
addEventListener第三個參數表達的含義是:是否在捕獲階段執行。默認falsespa
因此點擊c時,上述打印結果爲: 1,3,2
可是若是是都在a上添加事件,事件就會按照js的順序執行。
a.addEventListener('click', function() { console.log(1) }, false) a.addEventListener('click', function() { console.log(2) }, true)
上述執行的結果是:1,2
因此能夠總結出:事件是按照其餘元素的捕獲事件->自己元素的事件順序->其餘元素的冒泡事件。
二. jQuery選擇器模擬實現
選擇器有不少種,下面我簡單的實現class選擇器,id選擇器,標籤選擇器。
<div id="div1">div1</div> <div class="div2">222</div> <div class="div2">333</div> <p>p1</p> <p>p2</p>
有上述html代碼片斷,打印下面的值
window.onload = function() { var ele1 = $('#div1'); var ele2 = $('.div2'); var ele3 = $('p'); console.log(ele1) console.log(ele2) console.log(ele3) }
首先建立一個空數組,用來放置選擇器選中的值
var TQObject = function() { this.data = []; }
在上述對象的原型上掛載$
TQObject.prototype = {} var $ = function(selecter) { this.tqObject = new TQObject(); if(selecter.substring(0,1) == '#') { //id選擇器 var elem = document.getElementById(selecter.substring(1)); this.tqObject.data.push(elem); }else if(selecter.substring(0,1) == '.') { //class選擇器 var elems = document.getElementsByTagName('*'); var reg = new RegExp("(^|\\s)" + selecter.substring(1) + "($|\\s)"); for(var i =0; i<elems.length;i++) { if(reg.test(elems[i].className)) { this.tqObject.data.push(elems[i]) } } } else { //標籤選擇器 var elems = document.getElementsByTagName(selecter); // console.log(elems) for(var i = 0; i<elems.length; i++) { this.tqObject.data.push(elems[i]) } } return tqObject }
ID選擇器經過document.getElementById()進行選擇。可是class能夠經過document.getElementsByClassName()選擇,也能夠經過正則表達式選擇,上述代碼是經過正則表達式匹配實現的。
選擇結果:
三. 實現一個事件綁定函數
首先實現一個簡單的自定義事件綁定函數
function bindEvent(obj, events, fn) { obj.listeners = obj.listeners || {}; bindCore(obj, events, fn) }
bindCore函數
function bindCore(obj, events, fn) { obj.listeners[events] = obj.listeners[events] || []; obj.listeners[events].push(fn); if(obj.nodeType) { if(obj.addEventListener) { obj.addEventListener(events, fn, false); }else { obj.attachEvent('on'+ events, fn); } } }
上述的綁定函數,下面還有解綁函數
function unbindEvent(obj, events, fn) { obj.listeners = obj.listeners || {}; obj.listeners[events] = obj.listeners[events] || []; if(obj.nodeType) { if(obj.removeEventListener) { obj.removeEventListener(events, fn, false) console.log(obj.listeners) }else { obj.detachEvent('on' + events, fn) } } }
給綁定函數解綁,最重要的一點是:綁定事件的函數和解綁事件的函數必須是一個函數。而且不能夠是匿名函數。
下面實現一個能夠爲多個元素添加多個事件、多個元素添加一個事件、一個元素添加一個事件、一個元素添加多個事件
function bindEvent(objArr, eventsArr, fn) { if(objArr.length > 1) { objArr.forEach(element => { //多個元素添加事件 element.listeners = element.listeners || {}; if(eventsArr.length > 1) { eventsArr.forEach( eventItem => { //多個元素添加多個事件 bindCore(element, eventItem, fn) }) }else { //多個元素添加一個事件 bindCore(element, eventsArr, fn) } }); }else { //一個元素添加一個事件 objArr.listeners = objArr.listeners || {}; if(eventsArr.length > 1) { eventsArr.forEach( eventItem => { //一個元素添加多個事件 bindCore(objArr, eventItem, fn) }) }else { //多個元素添加一個事件 bindCore(objArr, eventsArr, fn) } } }
四. queryselect和getELementByxxxx之間的區別
1. queryselect能夠獲取頁面的靜態集合,可是不能經過這個值改變這個值,可是getELementByxxxx能夠經過這個獲取的值來改變當前的頁面上的值。
2. queryselector僅僅返回匹配指定選擇器的第一個元素,queryselectall是獲取全部的元素。
3. 性能方面來講,getELementByxxxx要比queryselect快不少,具體體驗地址。