檔案物件模型(Document Object Model,簡稱 DOM),是 W3C 組織推薦的處理可延伸標示語言(HTML或者XML)的標準程式設計介面
W3C 已經定義了一系列的 DOM 介面,通過這些 DOM 介面可以改變網頁的內容、結構和樣式。
DOM 把以上內容都看做是物件
DOM在我們實際開發中主要用來操作元素。
我們如何來獲取頁面中的元素呢?
獲取頁面中的元素可以使用以下幾種方式:
使用 getElementByld()
方法可以獲取帶ID的元素物件
doucument.getElementByld('id名')
使用 console.dir()
可以列印我們獲取的元素物件,更好的檢視物件裡面的屬性和方法。
範例
<p id="time">2019-9-9</p><script> // 1.因為我們檔案頁面從上往下載入,所以得先有標籤,所以script寫在標籤下面 // 2.get 獲得 element 元素 by 通過 駝峰命名法 // 3.引數 id是大小寫敏感的字串 // 4.返回的是一個元素物件 var timer = document.getElementById('time'); console.log(timer); // 5. console.dir 列印我們的元素物件,更好的檢視裡面的屬性和方法 console.dir(timer);</script>
根據標籤名獲取,使用 getElementByTagName()
方法可以返回帶有指定標籤名的物件的集合
doucument.getElementsByTagName('標籤名');
<ul> <li>知否知否,應是等你好久</li> <li>知否知否,應是等你好久</li> <li>知否知否,應是等你好久</li> <li>知否知否,應是等你好久</li> <li>知否知否,應是等你好久</li></ul><script> // 1.返回的是獲取過來元素物件的集合 以偽陣列的形式儲存 var lis = document.getElementsByTagName('li'); console.log(lis); console.log(lis[0]); // 2.依次列印,遍歷 for (var i = 0; i < lis.length; i++) { console.log(lis[i]); } // 3.如果頁面中只有 1 個 li,返回的還是偽陣列的形式 // 4.如果頁面中沒有這個元素,返回的是空偽陣列</script>
還可以根據標籤名獲取某個元素(父元素)內部所有指定標籤名的子元素,獲取的時候不包括父元素自己
element.getElementsByTagName('標籤名')ol.getElementsByTagName('li');
注意:父元素必須是單個物件(必須指明是哪一個元素物件),獲取的時候不包括父元素自己
<script> //element.getElementsByTagName('標籤名'); 父元素必須是指定的單個元素 var ol = document.getElementById('ol'); console.log(ol.getElementsByTagName('li'));</script>
根據類名返回元素物件合集
document.getElementsByClassName('類名')
document.getElementsByClassName('類名');
根據指定選擇器返回第一個元素物件
document.querySelector('選擇器'); // 切記裡面的選擇器需要加符號 // 類選擇器.box // id選擇器 #nav var firstBox = document.querySelector('.box');
根據指定選擇器返回所有元素物件
document.querySelectorAll('選擇器');
注意
querySelector
和 querySelectorAll
裡面的選擇器需要加符號,比如: document.querySelector('#nav');
<script> // 1. getElementsByClassName 根據類名獲得某些元素集合 var boxs = document.getElementsByClassName('box'); console.log(boxs); // 2. querySelector 返回指定選擇器的第一個元素物件 切記 裡面的選擇器需要加符號 .box #nav var firstBox = document.querySelector('.box'); console.log(firstBox); var nav = document.querySelector('#nav'); console.log(nav); var li = document.querySelector('li'); console.log(li); // 3. querySelectorAll()返回指定選擇器的所有元素物件集合 var allBox = document.querySelectorAll('.box'); console.log(allBox); var lis = document.querySelectorAll('li'); console.log(lis);</script>
返回body元素物件
document.body;
返回html元素物件
document.documentElement;
JavaScript 使我們有能力建立動態頁面,而事件是可以被 JavaScript 偵測到的行為。
簡單理解: 觸發— 響應機制。
網頁中的每個元素都可以產生某些可以觸發 JavaScript 的事件,例如,我們可以在使用者點選某按鈕時產生一個事件,然後去執行某些操作。
<script> // 點選一個按鈕,彈出對話方塊 // 1. 事件是有三部分組成 事件源 事件型別 事件處理程式 我們也稱為事件三要素 //(1) 事件源 事件被觸發的物件 誰 按鈕 var btn = document.getElementById('btn'); //(2) 事件型別 如何觸發 什麼事件 比如滑鼠點選(onclick) 還是滑鼠經過 還是鍵盤按下 //(3) 事件處理程式 通過一個函數賦值的方式 完成 btn.onclick = function() { alert('點秋香'); }</script>
<script> // 執行事件步驟 // 點選p 控制檯輸出 我被選中了 // 1. 獲取事件源 var p = document.querySelector('p'); // 2.繫結事件 註冊事件 // p.onclick // 3.新增事件處理程式 p.onclick = function() { console.log('我被選中了'); }</script>
滑鼠事件 | 觸發條件 |
---|---|
onclick | 滑鼠點選左鍵觸發 |
onmouseover | 滑鼠經過觸發 |
onmouseout | 滑鼠離開觸發 |
onfocus | 獲得滑鼠焦點觸發 |
onblur | 失去滑鼠焦點觸發 |
onmousemove | 滑鼠移動觸發 |
onmouseup | 滑鼠彈起觸發 |
onmousedown | 滑鼠按下觸發 |
JavaScript 的 DOM 操作可以改變網頁內容、結構和樣式,我們可以利用 DOM 操作元素來改變元素裡面的內容 、屬性等。注意以下都是屬性
從起始位置到終止位置的內容,但它去除html標籤,同時空格和換行也會去掉。
element.innerText
起始位置到終止位置的全部內容,包括HTML標籤,同時保留空格和換行
element.innerHTML
<body> <p></p> <p> 我是文字 <span>123</span> </p> <script> // innerText 和 innerHTML的區別 // 1. innerText 不識別html標籤,去除空格和換行 var p = document.querySelector('p'); p.innerText = '<strong>今天是:</strong> 2019'; // 2. innerHTML 識別html標籤 保留空格和換行的 p.innerHTML = '<strong>今天是:</strong> 2019'; // 這兩個屬性是可讀寫的 可以獲取元素裡面的內容 var p = document.querySelector('p'); console.log(p.innerText); console.log(p.innerHTML); </script></body>
// img.屬性 img.src = "xxx"; input.value = "xxx"; input.type = "xxx"; input.checked = "xxx"; input.selected = true / false; input.disabled = true / false;
我們可以通過 JS 修改元素的大小、顏色、位置等樣式。
// element.stylep.style.backgroundColor = 'pink';p.style.width = '250px';
// element.className
注意:
className
來操作元素類名屬性<body> <p class="first">文字</p> <script> // 1. 使用 element.style 獲得修改元素樣式 如果樣式比較少 或者 功能簡單的情況下使用 var test = document.querySelector('p'); test.onclick = function() { // this.style.backgroundColor = 'purple'; // this.style.color = '#fff'; // this.style.fontSize = '25px'; // this.style.marginTop = '100px'; // 讓我們當前元素的類名改為了 change // 2. 我們可以通過 修改元素的className更改元素的樣式 適合於樣式較多或者功能複雜的情況 // 3. 如果想要保留原先的類名,我們可以這麼做 多類名選擇器 // this.className = 'change'; this.className = 'first change'; } </script></body>
如果有同一組元素,我們相要某一個元素實現某種樣式,需要用到迴圈的排他思想演演算法:
<body> <button>按鈕1</button> <button>按鈕2</button> <button>按鈕3</button> <button>按鈕4</button> <button>按鈕5</button> <script> // 1. 獲取所有按鈕元素 var btns = document.getElementsByTagName('button'); // btns得到的是偽陣列 裡面的每一個元素 btns[i] for (var i = 0; i < btns.length; i++) { btns[i].onclick = function() { // (1) 我們先把所有的按鈕背景顏色去掉 幹掉所有人 for (var i = 0; i < btns.length; i++) { btns[i].style.backgroundColor = ''; } // (2) 然後才讓當前的元素背景顏色為pink 留下我自己 this.style.backgroundColor = 'pink'; } } //2. 首先先排除其他人,然後才設定自己的樣式 這種排除其他人的思想我們成為排他思想 </script></body>
element.屬性;
element.getAttribute('屬性');
element.屬性 = '值';
element.setAttribute('屬性');
element.removeAttribute('屬性');
<body> <p id="demo" index="1" class="nav"></p> <script> var p = document.querySelector('p'); // 1. 獲取元素的屬性值 // (1) element.屬性 console.log(p.id); //(2) element.getAttribute('屬性') get得到獲取 attribute 屬性的意思 我們程式設計師自己新增的屬性我們稱為自定義屬性 index console.log(p.getAttribute('id')); console.log(p.getAttribute('index')); // 2. 設定元素屬性值 // (1) element.屬性= '值' p.id = 'test'; p.className = 'navs'; // (2) element.setAttribute('屬性', '值'); 主要針對於自定義屬性 p.setAttribute('index', 2); p.setAttribute('class', 'footer'); // class 特殊 這裡面寫的就是class 不是className // 3 移除屬性 removeAttribute(屬性) p.removeAttribute('index'); </script></body>
自定義屬性目的:
H5規定自定義屬性 data-
開頭作為屬性名並賦值
<p data-index = "1"></>// 或者使用JavaScript設定p.setAttribute('data-index',1);
element.getAttribute('data-index')
element.dataset.index
或element.dataset['index']
IE11才開始支援<body> <p getTime="20" data-index="2" data-list-name="andy"></p> <script> var p = document.querySelector('p'); console.log(p.getAttribute('getTime')); p.setAttribute('data-time', 20); console.log(p.getAttribute('data-index')); console.log(p.getAttribute('data-list-name')); // h5新增的獲取自定義屬性的方法 它只能獲取data-開頭的 // dataset 是一個集合裡面存放了所有以data開頭的自定義屬性 console.log(p.dataset); console.log(p.dataset.index); console.log(p.dataset['index']); // 如果自定義屬性裡面有多個-連結的單詞,我們獲取的時候採取 駝峰命名法 console.log(p.dataset.listName); console.log(p.dataset['listName']); </script></body>
獲取元素通常使用兩種方式:
1.利用DOM提供的方法獲取元素 | 2.利用節點層級關係獲取元素 |
---|---|
document.getElementById() | 利用父子兄節點關係獲取元素 |
document.getElementsByTagName() | 邏輯性強,但是相容性較差 |
document.querySelector 等 | |
邏輯性不強,繁瑣 |
這兩種方式都可以獲取元素節點,我們後面都會使用,但是節點操作更簡單
一般的,節點至少擁有三個基本屬性
網頁中的所有內容都是節點(標籤、屬性、文字、註釋等),在DOM 中,節點使用 node 來表示。
HTML DOM 樹中的所有節點均可通過 JavaScript 進行存取,所有 HTML 元素(節點)均可被修改,也可以建立或刪除。
一般的,節點至少擁有nodeType(節點型別)、nodeName(節點名稱)和nodeValue(節點值)這三個基本屬性。
我們在實際開發中,節點操作主要操作的是元素節點
利用 DOM 樹可以把節點劃分為不同的層級關係,常見的是父子兄層級關係。
node.parentNode
parentNode
屬性可以返回某節點的父結點,注意是最近的一個父結點<body> <!-- 節點的優點 --> <p>我是p</p> <span>我是span</span> <ul> <li>我是li</li> <li>我是li</li> <li>我是li</li> <li>我是li</li> </ul> <p class="demo"> <p class="box"> <span class="erweima">×</span> </p> </p> <script> // 1. 父節點 parentNode var erweima = document.querySelector('.erweima'); // var box = document.querySelector('.box'); // 得到的是離元素最近的父級節點(親爸爸) 如果找不到父節點就返回為 null console.log(erweima.parentNode); </script></body>
parentNode.childNodes(標準)
parentNode.childNodes
返回包含指定節點的子節點的集合,該集合為即時更新的集合childNodes
parentNode.children(非標準)
parentNode.children
是一個唯讀屬性,返回所有的子元素節點<body> <ul> <li>我是li</li> <li>我是li</li> <li>我是li</li> <li>我是li</li> </ul> <ol> <li>我是li</li> <li>我是li</li> <li>我是li</li> <li>我是li</li> </ol> <script> // DOM 提供的方法(API)獲取 var ul = document.querySelector('ul'); var lis = ul.querySelectorAll('li'); // 1. 子節點 childNodes 所有的子節點 包含 元素節點 文位元組點等等 console.log(ul.childNodes); console.log(ul.childNodes[0].nodeType); console.log(ul.childNodes[1].nodeType); // 2. children 獲取所有的子元素節點 也是我們實際開發常用的 console.log(ul.children); </script></body>
parentNode.firstChild
firstChild
返回第一個子節點,找不到則返回nullparentNode.lastChild
lastChild
返回最後一個子節點,找不到則返回null<body> <ol> <li>我是li1</li> <li>我是li2</li> <li>我是li3</li> <li>我是li4</li> <li>我是li5</li> </ol> <script> var ol = document.querySelector('ol'); // 1. firstChild 第一個子節點 不管是文位元組點還是元素節點 console.log(ol.firstChild); console.log(ol.lastChild); // 2. firstElementChild 返回第一個子元素節點 ie9才支援 console.log(ol.firstElementChild); console.log(ol.lastElementChild); // 3. 實際開發的寫法 既沒有相容性問題又返回第一個子元素 console.log(ol.children[0]); //第一個子元素節點 console.log(ol.children[ol.children.length - 1]);//最後一個子元素節點 </script></body>
parentNode.firstElementChild
firstElementChild
返回第一個子節點,找不到則返回nullparentNode.lastElementChild
lastElementChild
返回最後一個子節點,找不到則返回null實際開發中,firstChild 和 lastChild 包含其他節點,操作不方便,而 firstElementChild 和 lastElementChild 又有相容性問題,那麼我們如何獲取第一個子元素節點或最後一個子元素節點呢?
解決方案
如果想要第一個子元素節點,可以使用parentNode.chilren[0]
如果想要最後一個子元素節點,可以使用
// 陣列元素個數減1 就是最後一個元素的索引號parentNode.chilren[parentNode.chilren.length - 1]
範例:
<body> <ol> <li>我是li1</li> <li>我是li2</li> <li>我是li3</li> <li>我是li4</li> </ol> <script> var ol = document.querySelector('ol'); // 1.firstChild 獲取第一個子結點的,包含文字結點和元素結點 console.log(ol.firstChild); // 返回的是文字結點 #text(第一個換行結點) console.log(ol.lastChild); // 返回的是文字結點 #text(最後一個換行結點) // 2. firstElementChild 返回第一個子元素結點 console.log(ol.firstElementChild); // <li>我是li1</li> // 第2個方法有相容性問題,需要IE9以上才支援 // 3.實際開發中,既沒有相容性問題,又返回第一個子元素 console.log(ol.children[0]); // <li>我是li1</li> console.log(ol.children[3]); // <li>我是li4</li> // 當裡面li個數不唯一時候,需要取到最後一個結點時這麼寫 console.log(ol.children[ol.children.length - 1]); </script></body>
node.nextSibling
nextSibling
返回當前元素的下一個兄弟元素節點,找不到則返回nullnode.previousSibling
previousSibling
返回當前元素上一個兄弟元素節點,找不到則返回null
同樣,也是包含所有的節點
node.nextElementSibling
nextElementSibling
返回當前元素下一個兄弟元素節點,找不到則返回nullnode.previousElementSibling
previousElementSibling
返回當前元素上一個兄弟元素節點,找不到則返回null範例
<body> <p>我是p</p> <span>我是span</span> <script> var p = document.querySelector('p'); // 1.nextSibling 下一個兄弟節點 包含元素節點或者 文位元組點等等 console.log(p.nextSibling); // #text console.log(p.previousSibling); // #text // 2. nextElementSibling 得到下一個兄弟元素節點 console.log(p.nextElementSibling); //<span>我是span</span> console.log(p.previousElementSibling);//null </script></body>
如何解決相容性問題 ?
答:自己封裝一個相容性的函數
function getNextElementSibling(element) { var el = element; while(el = el.nextSibling) { if(el.nodeType === 1){ return el; } } return null;}
document.createElement('tagName');
document.createElement()
方法建立由 tagName 指定的HTML 元素node.appendChild(child)
node.appendChild()
方法將一個節點新增到指定父節點的子節點列表末尾。類似於 CSS 裡面的 after 偽元素。node.insertBefore(child,指定元素)
node.insertBefore()
方法將一個節點新增到父節點的指定子節點前面。類似於 CSS 裡面的 before 偽元素。範例
<body> <ul> <li>123</li> </ul> <script> // 1. 建立節點元素節點 var li = document.createElement('li'); // 2. 新增節點 node.appendChild(child) node 父級 child 是子級 後面追加元素 類似於陣列中的push // 先獲取父親ul var ul = document.querySelector('ul'); ul.appendChild(li); // 3. 新增節點 node.insertBefore(child, 指定元素); var lili = document.createElement('li'); ul.insertBefore(lili, ul.children[0]); // 4. 我們想要頁面新增一個新的元素分兩步: 1. 建立元素 2. 新增元素 </script></body>
node.removeChild(child)
node.removeChild()
方法從 DOM 中刪除一個子節點,返回刪除的節點node.cloneNode()
node.cloneNode()
方法返回撥用該方法的節點的一個副本。 也稱為克隆節點/拷貝節點範例
<body> <ul> <li>1111</li> <li>2</li> <li>3</li> </ul> <script> var ul = document.querySelector('ul'); // 1. node.cloneNode(); 括號為空或者裡面是false 淺拷貝 只複製標籤不復制裡面的內容 // 2. node.cloneNode(true); 括號為true 深拷貝 複製標籤複製裡面的內容 var lili = ul.children[0].cloneNode(true); ul.appendChild(lili); </script></body>
三種動態建立元素的區別
區別:
document.write()
是直接將內容寫入頁面的內容流,但是檔案流執行完畢,則它會導致頁面全部重繪innerHTML
是將內容寫入某個 DOM 節點,不會導致頁面全部重繪innerHTML
建立多個元素效率更高(不要拼接字串,採取陣列形式拼接),結構稍微複雜<body> <p class="innner"></p> <p class="create"></p> <script> // 2. innerHTML 建立元素 var inner = document.querySelector('.inner'); // 2.1 innerHTML 用拼接字串方法 for (var i = 0; i <= 100; i++) { inner.innerHTML += '<a href="#">百度</a>'; } // 2.2 innerHTML 用陣列形式拼接 var arr = []; for (var i = 0; i <= 100; i++) { arr.push('<a href="#">百度</a>'); } inner.innerHTML = arr.join(''); // 3.document.createElement() 建立元素 var create = document.querySelector('.create'); var a = document.createElement('a'); create.appendChild(a); </script></body>
createElement()
建立多個元素效率稍低一點點,但是結構更清晰總結:不同瀏覽器下, innerHTML 效率要比 createElement 高
對於DOM操作,我們主要針對子元素的操作,主要有
給元素新增事件,稱為註冊事件或者繫結事件。
註冊事件有兩種方式:傳統方式和方法監聽註冊方式
傳統註冊方式 | 方法監聽註冊方式 |
---|---|
利用 on 開頭的事件 onclick | w3c 標準推薦方式 |
<button onclick = "alert("hi")"></button> | addEventListener() 它是一個方法 |
btn.onclick = function() {} | IE9 之前的 IE 不支援此方法,可使用 attachEvent() 代替 |
特點:註冊事件的唯一性 | 特點:同一個元素同一個事件可以註冊多個監聽器 |
同一個元素同一個事件只能設定一個處理常式,最後註冊的處理常式將會覆蓋前面註冊的處理常式 | 按註冊順序依次執行 |
eventTarget.addEventListener()
方法將指定的監聽器註冊到 eventTarget(目標物件)上eventTarget.addEventListener(type,listener[,useCapture])
該方法接收三個引數:
type
:事件型別字串,比如click,mouseover,注意這裡不要帶onlistener
:事件處理常式,事件發生時,會呼叫該監聽函數useCapture
:可選引數,是一個布林值,預設是 false。學完 DOM 事件流後,我們再進一步學習<body> <button>傳統註冊事件</button> <button>方法監聽註冊事件</button> <button>ie9 attachEvent</button> <script> var btns = document.querySelectorAll('button'); // 1. 傳統方式註冊事件 btns[0].onclick = function() { alert('hi'); } btns[0].onclick = function() { alert('hao a u'); } // 2. 事件監聽註冊事件 addEventListener // (1) 裡面的事件型別是字串 所以加引號 而且不帶on // (2) 同一個元素 同一個事件可以新增多個偵聽器(事件處理程式) btns[1].addEventListener('click', function() { alert(22); }) btns[1].addEventListener('click', function() { alert(33); }) // 3. attachEvent ie9以前的版本支援 btns[2].attachEvent('onclick', function() { alert(11); }) </script></body>
eventTarget.attachEvent()
方法將指定的監聽器註冊到 eventTarget(目標物件) 上eventTarget.attachEvent(eventNameWithOn,callback)
該方法接收兩個引數:
eventNameWithOn
:事件型別字串,比如 onclick 、onmouseover ,這裡要帶 oncallback
: 事件處理常式,當目標觸發事件時回撥函數被呼叫相容性處理的原則:首先照顧大多數瀏覽器,再處理特殊瀏覽器
function addEventListener(element, eventName, fn) { // 判斷當前瀏覽器是否支援 addEventListener 方法 if (element.addEventListener) { element.addEventListener(eventName, fn); // 第三個引數 預設是false } else if (element.attachEvent) { element.attachEvent('on' + eventName, fn); } else { // 相當於 element.onclick = fn; element['on' + eventName] = fn; }
eventTarget.removeEventListener(type,listener[,useCapture]);
該方法接收三個引數:
type
:事件型別字串,比如click,mouseover,注意這裡不要帶onlistener
:事件處理常式,事件發生時,會呼叫該監聽函數useCapture
:可選引數,是一個布林值,預設是 false。學完 DOM 事件流後,我們再進一步學習eventTarget.detachEvent(eventNameWithOn,callback);
該方法接收兩個引數:
eventNameWithOn
:事件型別字串,比如 onclick 、onmouseover ,這裡要帶 oncallback
: 事件處理常式,當目標觸發事件時回撥函數被呼叫eventTarget.onclick = null;
事件刪除範例:
<body> <p>1</p> <p>2</p> <p>3</p> <script> var ps = document.querySelectorAll('p'); ps[0].onclick = function() { alert(11); // 1. 傳統方式刪除事件 ps[0].onclick = null; } // 2.removeEventListener 刪除事件 ps[1].addEventListener('click',fn); //裡面的fn不需要呼叫加小括號 function fn(){ alert(22); ps[1].removeEventListener('click',fn); } // 3.IE9 中的刪除事件方式 ps[2].attachEvent('onclick',fn1); function fn1() { alert(33); ps[2].detachEvent('onclick',fn1); } </script></body>
function removeEventListener(element, eventName, fn) { // 判斷當前瀏覽器是否支援 removeEventListener 方法 if (element.removeEventListener) { element.removeEventListener(eventName, fn); // 第三個引數 預設是false } else if (element.detachEvent) { element.detachEvent('on' + eventName, fn); } else { element['on' + eventName] = null; }
事件冒泡: IE 最早提出,事件開始時由最具體的元素接收,然後逐級向上傳播到到 DOM 最頂層節點的過程。
事件捕獲: 網景最早提出,由 DOM 最頂層節點開始,然後逐級向下傳播到到最具體的元素接收的過程。
加深理解:
我們向水裡面扔一塊石頭,首先它會有一個下降的過程,這個過程就可以理解為從最頂層向事件發生的最具體元素(目標點)的捕獲過程;之後會產生泡泡,會在最低點( 最具體元素)之後漂浮到水面上,這個過程相當於事件冒泡。
兩個盒子巢狀,一個父盒子一個子盒子,我們的需求是當點選父盒子時彈出 father ,當點選子盒子時彈出 son
<body> <p class="father"> <p class="son">son盒子</p> </p> <script> // dom 事件流 三個階段 // 1. JS 程式碼中只能執行捕獲或者冒泡其中的一個階段。 // 2. onclick 和 attachEvent(ie) 只能得到冒泡階段。 // 3. 捕獲階段 如果addEventListener 第三個引數是 true 那麼則處於捕獲階段 document -> html -> body -> father -> son var son = document.querySelector('.son'); son.addEventListener('click', function() { alert('son'); }, true); var father = document.querySelector('.father'); father.addEventListener('click', function() { alert('father'); }, true); </script></body>
但是因為DOM流的影響,我們點選子盒子,會先彈出 father,之後再彈出 son
這是因為捕獲階段由 DOM 最頂層節點開始,然後逐級向下傳播到到最具體的元素接收
document -> html -> body -> father -> son
先看 document 的事件,沒有;再看 html 的事件,沒有;再看 body 的事件,沒有;再看 father 的事件,有就先執行;再看 son 的事件,再執行。
<body> <p class="father"> <p class="son">son盒子</p> </p> <script> // 4. 冒泡階段 如果addEventListener 第三個引數是 false 或者 省略 那麼則處於冒泡階段 son -> father ->body -> html -> document var son = document.querySelector('.son'); son.addEventListener('click', function() { alert('son'); }, false); var father = document.querySelector('.father'); father.addEventListener('click', function() { alert('father'); }, false); document.addEventListener('click', function() { alert('document'); }) </script></body>
我們點選子盒子,會彈出 son、father、document
這是因為冒泡階段開始時由最具體的元素接收,然後逐級向上傳播到到 DOM 最頂層節點
JS 程式碼中只能執行捕獲或者冒泡其中的一個階段
onclick
和 attachEvent
只能得到冒泡階段
addEventListener(type,listener[,useCapture])
第三個引數如果是 true,表示在事件捕獲階段呼叫事件處理程式;如果是 false (不寫預設就是false),表示在事件冒泡階段呼叫事件處理程式
實際開發中我們很少使用事件捕獲,我們更關注事件冒泡。
有些事件是沒有冒泡的,比如 onblur、onfocus、onmouseenter、onmouseleave
eventTarget.onclick = function(event) { // 這個 event 就是事件物件,我們還喜歡的寫成 e 或者 evt } eventTarget.addEventListener('click', function(event) { // 這個 event 就是事件物件,我們還喜歡的寫成 e 或者 evt })
<body> <p>123</p> <script> // 事件物件 var p = document.querySelector('p'); p.onclick = function(e) { // console.log(e); // console.log(window.event); // e = e || window.event; console.log(e); } // 1. event 就是一個事件物件 寫到我們偵聽函數的 小括號裡面 當形參來看 // 2. 事件物件只有有了事件才會存在,它是系統給我們自動建立的,不需要我們傳遞引數 // 3. 事件物件 是 我們事件的一系列相關資料的集合 跟事件相關的 比如滑鼠點選裡面就包含了滑鼠的相關資訊,滑鼠座標啊,如果是鍵盤事件裡面就包含的鍵盤事件的資訊 比如 判斷使用者按下了那個鍵 // 4. 這個事件物件我們可以自己命名 比如 event 、 evt、 e // 5. 事件物件也有相容性問題 ie678 通過 window.event 相容性的寫法 e = e || window.event; </script></body>
事件物件本身的獲取存在相容問題:
解決:
e = e || window.event;
事件物件屬性方法 | 說明 |
---|---|
e.target | 返回觸發事件的物件 標準 |
e.srcElement | 返回觸發事件的物件 非標準 ie6-8使用 |
e.type | 返回事件的型別 比如click mouseover 不帶on |
e.cancelBubble | 該屬性阻止冒泡,非標準,ie6-8使用 |
e.returnValue | 該屬性阻止預設行為 非標準,ie6-8使用 |
e.preventDefault() | 該方法阻止預設行為 標準 比如不讓連結跳轉 |
e.stopPropagation() | 阻止冒泡 標準 |
e.target和this的區別:
<body> <p>123</p> <a href="http://www.baidu.com">百度</a> <form action="http://www.baidu.com"> <input type="submit" value="提交" name="sub"> </form> <script> // 常見事件物件的屬性和方法 // 1. 返回事件型別 var p = document.querySelector('p'); p.addEventListener('click', fn); p.addEventListener('mouseover', fn); p.addEventListener('mouseout', fn); function fn(e) { console.log(e.type); } // 2. 阻止預設行為(事件) 讓連結不跳轉 或者讓提交按鈕不提交 var a = document.querySelector('a'); a.addEventListener('click', function(e) { e.preventDefault(); // dom 標準寫法 }) // 3. 傳統的註冊方式 a.onclick = function(e) { // 普通瀏覽器 e.preventDefault(); 方法 // e.preventDefault(); // 低版本瀏覽器 ie678 returnValue 屬性 // e.returnValue; // 我們可以利用return false 也能阻止預設行為 沒有相容性問題 特點: return 後面的程式碼不執行了, 而且只限於傳統的註冊方式 return false; alert(11); } </script></body>
事件冒泡:開始時由最具體的元素接收,然後逐級向上傳播到到 DOM 最頂層節點
事件冒泡本身的特性,會帶來的壞處,也會帶來的好處,需要我們靈活掌握。
e.stopPropagation();
e.cancelBubble = true;
<body> <p class="father"> <p class="son">son兒子</p> </p> <script> // 常見事件物件的屬性和方法 // 阻止冒泡 dom 推薦的標準 stopPropagation() var son = document.querySelector('.son'); son.addEventListener('click', function(e) { alert('son'); e.stopPropagation(); // stop 停止 Propagation 傳播 e.cancelBubble = true; // 非標準 cancel 取消 bubble 泡泡 }, false); var father = document.querySelector('.father'); father.addEventListener('click', function() { alert('father'); }, false); document.addEventListener('click', function() { alert('document'); }) </script></body>
if(e && e.stopPropagation){ e.stopPropagation(); }else{ window.event.cancelBubble = true; }
e.target 與 this 的區別
this
是事件繫結的元素,這個函數的呼叫者(繫結這個事件的元素)e.target
是事件觸發的元素<body> <p>123</p> <ul> <li>abc</li> <li>abc</li> <li>abc</li> </ul> <script> // 常見事件物件的屬性和方法 // 1. e.target 返回的是觸發事件的物件(元素) this 返回的是繫結事件的物件(元素) // 區別 : e.target 點選了那個元素,就返回那個元素 this 那個元素繫結了這個點選事件,那麼就返回誰 var p = document.querySelector('p'); p.addEventListener('click', function(e) { console.log(e.target); console.log(this); }) var ul = document.querySelector('ul'); ul.addEventListener('click', function(e) { // 我們給ul 繫結了事件 那麼this 就指向ul console.log(this); console.log(e.currentTarget); // e.target 指向我們點選的那個物件 誰觸發了這個事件 我們點選的是li e.target 指向的就是li console.log(e.target); }) // 瞭解相容性 // p.onclick = function(e) { // e = e || window.event; // var target = e.target || e.srcElement; // console.log(target); // } // 2. 瞭解 跟 this 有個非常相似的屬性 currentTarget ie678不認識 </script></body>
事件物件本身的獲取存在相容問題:
window.event
中獲取查詢解決方案
e = e || window.event
<body> <p>123</p> <script> // 事件物件 var p = document.querySelector('p'); p.onclick = function(e) { // e = e || window.event; console.log(e); // 事件物件也有相容性問題 ie678 通過 window.event 相容性的寫法 e = e || window.event; }</body>
<body> <ul> <li>知否知否,點我應有彈框在手!</li> <li>知否知否,點我應有彈框在手!</li> <li>知否知否,點我應有彈框在手!</li> <li>知否知否,點我應有彈框在手!</li> <li>知否知否,點我應有彈框在手!</li> </ul> <script> // 事件委託的核心原理:給父節點新增偵聽器, 利用事件冒泡影響每一個子節點 var ul = document.querySelector('ul'); ul.addEventListener('click', function(e) { // alert('知否知否,點我應有彈框在手!'); // e.target 這個可以得到我們點選的物件 e.target.style.backgroundColor = 'pink'; // 點了誰,就讓誰的style裡面的backgroundColor顏色變為pink }) </script></body>
以上案例:給 ul 註冊點選事件,然後利用事件物件的 target 來找到當前點選的 li,因為點選 li,事件會冒泡到 ul 上, ul 有註冊事件,就會觸發事件監聽器。
滑鼠事件 | 觸發條件 |
---|---|
onclick | 滑鼠點選左鍵觸發 |
onmouseover | 滑鼠經過觸發 |
onmouseout | 滑鼠離開觸發 |
onfocus | 獲得滑鼠焦點觸發 |
onblur | 失去滑鼠焦點觸發 |
onmousemove | 滑鼠移動觸發 |
onmouseup | 滑鼠彈起觸發 |
onmousedown | 滑鼠按下觸發 |
contextmenu
主要控制應該何時顯示上下文選單,主要用於程式設計師取消預設的上下文選單selectstart
禁止滑鼠選中<body> <h1>我是一段不願意分享的文字</h1> <script> // 1. contextmenu 我們可以禁用右鍵選單 document.addEventListener('contextmenu', function(e) { e.preventDefault(); // 阻止預設行為 }) // 2. 禁止選中文字 selectstart document.addEventListener('selectstart', function(e) { e.preventDefault(); }) </script></body>
滑鼠事件物件 | 說明 |
---|---|
e.clientX | 返回滑鼠相對於瀏覽器視窗可視區的X座標 |
e.clientY | 返回滑鼠相對於瀏覽器視窗可視區的Y座標 |
e.pageX(重點) | 返回滑鼠相對於檔案頁面的X座標 IE9+ 支援 |
e.pageY(重點) | 返回滑鼠相對於檔案頁面的Y座標 IE9+ 支援 |
e.screenX | 返回滑鼠相對於電腦螢幕的X座標 |
e.screenY | 返回滑鼠相對於電腦螢幕的Y座標 |
<body> <script> // 滑鼠事件物件 MouseEvent document.addEventListener('click', function(e) { // 1. client 滑鼠在可視區的x和y座標 console.log(e.clientX); console.log(e.clientY); console.log('---------------------'); // 2. page 滑鼠在頁面檔案的x和y座標 console.log(e.pageX); console.log(e.pageY); console.log('---------------------'); // 3. screen 滑鼠在電腦螢幕的x和y座標 console.log(e.screenX); console.log(e.screenY); }) </script></body>
鍵盤事件 | 觸發條件 |
---|---|
onkeyup | 某個鍵盤按鍵被鬆開時觸發 |
onkeydown | 某個鍵盤按鍵被按下時觸發 |
onkeypress | 某個鍵盤按鍵被按下時觸發,但是它不識別功能鍵,比如 ctrl shift 箭頭等 |
onkeypress
和前面2個的區別是,它不識別功能鍵,比如左右箭頭,shift 等<body> <script> // 常用的鍵盤事件 //1. keyup 按鍵彈起的時候觸發 // document.onkeyup = function() { // console.log('我彈起了'); // } document.addEventListener('keyup', function() { console.log('我彈起了'); }) //3. keypress 按鍵按下的時候觸發 不能識別功能鍵 比如 ctrl shift 左右箭頭啊 document.addEventListener('keypress', function() { console.log('我按下了press'); }) //2. keydown 按鍵按下的時候觸發 能識別功能鍵 比如 ctrl shift 左右箭頭啊 document.addEventListener('keydown', function() { console.log('我按下了down'); }) // 4. 三個事件的執行順序 keydown -- keypress -- keyup </script></body>
鍵盤事件物件 屬性 | 說明 |
---|---|
keyCode | 返回該鍵值的ASCII值 |
onkeydown
和 onkeyup
不區分字母大小寫,onkeypress
區分字母大小寫。Keypress
不識別功能鍵,但是keyCode
屬效能區分大小寫,返回不同的ASCII值<body> <script> // 鍵盤事件物件中的keyCode屬性可以得到相應鍵的ASCII碼值 // 1. 我們的keyup 和keydown事件不區分字母大小寫 a 和 A 得到的都是65 // 2. 我們的keypress 事件 區分字母大小寫 a 97 和 A 得到的是65 document.addEventListener('keyup', function(e) { console.log('up:' + e.keyCode); // 我們可以利用keycode返回的ASCII碼值來判斷使用者按下了那個鍵 if (e.keyCode === 65) { alert('您按下的a鍵'); } else { alert('您沒有按下a鍵') } }) document.addEventListener('keypress', function(e) { console.log('press:' + e.keyCode); }) </script></body>
相關推薦:
以上就是超詳細的JavaScript進階學習之DOM技術(整理分享)的詳細內容,更多請關注TW511.COM其它相關文章!