JS - DOM

基本語法

(0)有些HTML屬性名是JavaScript的保留字,轉爲JavaScript屬性時,必須更名。主要是如下兩個。javascript

  • for屬性改成htmlFor
  • class屬性改成className

若要在HTML元素上附加數據,供JavaScript腳本使用css

  • 自定義屬性:可能不符合標準,致使網頁代碼校驗不經過
  • 標準 data-* 屬性:利用元素節點對象的dataset屬性

:data-後面的屬性名只能包含小寫字母、數字、連詞線(-)、點(.)、冒號(:)和下劃線(_)html

(1)判斷一個節點有無子節點,三種方法java

  • node.hasChildNodes()
  • node.firstChild !== null
  • node.childNodes && node.childNodes.length > 0

:結合firstChild屬性和nextSibling屬性,遍歷當前節點的全部後代節點node

function DOMComb(parent, callback) {
  if (parent.hasChildNodes()) {
    for (var node = parent.firstChild; node; node = node.nextSibling) {
      DOMComb(node, callback);
    }
  }
  callback(parent);
}

// 用法
DOMComb(document.body, console.log)

(2)removeChild  npm

該方法是在當前結點的父節點上調用的。編程

:移除當前結點的全部子節點數組

var element = document.getElementById('xxx');
while (element.firstChild) {
  element.removeChild(element.firstChild);
}

結點的children屬性是一個只讀屬性,隨子節點的變化會實時更新。
在刪除多個節點時,務必注意children屬性時刻都在變化。瀏覽器

(3)compareDocumentPosition()緩存

七個比特位的二進制值,表示參數節點與當前節點的關係

000000	0	兩個節點相同
000001	1	兩個節點不在同一個文檔(即有一個節點不在當前文檔)
000010	2	參數節點在當前節點的前面
000100	4	參數節點在當前節點的後面
001000	8	參數節點包含當前節點
010000	16	當前節點包含參數節點
100000	32	瀏覽器內部使用  

最終結果須要結合比特位運算。  

(4)結點集合 

NodeList 實例是一個類數組對象,可轉化爲真正的數組,支持for和foreach遍歷

var children = document.body.childNodes;
var nodeArr = Array.prototype.slice.call(children);

NodeList實例多是動態集合,也多是靜態集合。

動態集合是一個活的集合,DOM刪除或新增一個相關節點,會馬上反映在NodeList實例上。

:目前只有node.childNodes返回的NodeList是動態集合。 

  • childNodes:全部子結點
  • children:子元素結點

其餘返回NodeList的方法

  • document.getElementsByName
  • Element.querySelectorAll

HTMLCollection 實例是一個類數組對象,只包含元素(Element)結點,只支持for遍歷,動態集合。

  • document.links
  • document.forms
  • document.images
  • document.scripts
  • document.embeds,document.plugins

以及元素定位方法

  • document.getElementsByTagName
  • document.getElementsByClassName

document.styleSheets屬性返回文檔內嵌或引入的樣式表集合,類型StyleSheetList。

(5)HTML表單

經常使用標籤

文本框:<input type="text">,用於輸入文本;
口令框:<input type="password">,用於輸入口令;
單選框:<input type="radio">,用於選擇一項;
複選框:<input type="checkbox">,用於選擇多項;
下拉框:<select>,用於選擇一項;
多行文本框:<textarea>,定義多行的文本輸入控件
隱藏文本:<input type="hidden">,用戶不可見,但表單提交時會把隱藏文本發送到服務器。
文件選擇:<input type="file">:HTML表單中用於上傳文件

當一個表單包含<input type="file">時,表單的enctype必須爲multipart/form-data,method必須爲post,瀏覽器才能正確編碼並以multipart/form-data格式發送表單數據。

(6)根據name屬性獲取標籤結點

document.querySelectorAll('*[name="xxx"]');
document.getElementsByName("xxx");  

注意,沒有name屬性的<input>的數據不會被提交。  

(7)網頁屬性

a. 整張網頁的總高度/寬度

document.documentElement.scrollHeight/scrollWidth
document.body.scrollHeight/scrollWidth

b. 整張網頁的水平的和垂直的滾動距離

document.documentElement.scrollLeft
document.documentElement.scrollTop

注:該屬性均可讀寫,設置該屬性的值,會致使瀏覽器將當前元素自動滾動到相應的位置。

c. 計算元素左上角相對於整張網頁的座標 

function getElementPosition(e) {
  var x = 0;
  var y = 0;
  while (e !== null)  {
    x += e.offsetLeft;
    y += e.offsetTop;
    e = e.offsetParent;
  }
  return {x: x, y: y};
}

document

獲取document對象的方法

  • 正常的網頁,直接使用documentwindow.document
  • iframe框架裏面的網頁,使用iframe節點的contentDocument屬性
  • Ajax 操做返回的文檔,使用XMLHttpRequest對象的responseXML屬性
  • 內部節點的ownerDocument屬性

document對象一般有2個子結點

(1)document.doctype:指向<DOCTYPE>節點,一般爲<!DOCTYPE html>,與document.firstChild等效

(2)document.documentElement:指向當前文檔的根節點,一般爲<html>

document.head和document.body屬性分別直接指向<head>節點和<body>節點。

狀態屬性

document.visibilityState

該屬性返回文檔的可見狀態:

  • visible:頁面可見。頁面多是部分可見,即不是焦點窗口,前面被其餘窗口部分擋住了
  • hidden: 頁面不可見,有可能窗口最小化,或者瀏覽器切換到了另外一個Tab頁面
  • prerender:頁面處於正在渲染狀態,對於用於來講,該頁面不可見
  • unloaded:頁面從內存裏面卸載了

應用場景:

  • 頁面加載時,防止加載某些資源
  • 頁面不可見時,停掉一些頁面功能

document.readyState

該屬性返回當前文檔的狀態:

  • loading:加載HTML代碼階段(還沒有完成解析)
  • interactive:加載外部資源階段
  • complete:加載完成

頁面加載過程:

  • 瀏覽器開始解析HTML文檔,document.readyState屬性等於loading
  • 瀏覽器遇到HTML文檔中的<script>元素,而且沒有asyncdefer屬性,就暫停解析,開始執行腳本,這時document.readyState屬性仍是等於loading
  • HTML文檔解析完成,document.readyState屬性變成interactive
  • 瀏覽器等待圖片、樣式表、字體文件等外部資源加載完成,一旦所有加載完成,document.readyState屬性變成complete

方法

document.createTextNode()

用於生成文本節點(Text實例)。

該方法能夠確保返回的節點,被瀏覽器看成文本渲染,而不是看成HTML代碼渲染。所以,能夠用來展現用戶的輸入,避免 XSS 攻擊。 

var div = document.createElement('div');
div.appendChild(
    document.createTextNode('<span>Foo & bar</span>')
);
console.log(div.innerHTML)
結果:&lt;span&gt;Foo &amp; bar&lt;/span&gt;

會對大於號和小於號進行轉義,保證即便用戶輸入的內容包含惡意代碼,也能正確顯示。

但該方法不對單引號和雙引號轉義,因此不能用來對HTML屬性賦值。

document.createDocumentFragment()

該方法生成一個空的存在於內存中的文檔片斷對象。
新對象不屬於當前文檔,經常使用來生成一段較複雜的DOM結構,而後再插入當前文檔,避免直接修改當前DOM引起網頁的從新渲染。

該方法等同於瀏覽器原生的DocumentFragment構造函數

var docFrag = new DocumentFragment();

注意,DocumentFragment節點自己不能被插入當前文檔,而是其全部子結點插入當前文檔中。插入完成後,該DocumentFragment對象變爲空結點(textContent屬性爲空串),能夠被再次使用。
若想保留其子結點,能夠經過cloneNode()方法

node.appendChild(docFrag.cloneNode(true));

document.createNodeIterator()
該方法返回一個子節點遍歷器對象(NodeFilter實例)

var nodeIterator = document.createNodeIterator(
  document.body, //要遍歷的根節點
  NodeFilter.SHOW_ELEMENT //要遍歷的節點類型
);

:遍歷器返回的第一個節點,老是根節點。

  • nextNode:先返回遍歷器指向的節點A,而後將指針移到下一個節點B
  • previousNode:先將指針移到上一個節點D,而後返回該節點D
var currentNode = nodeIterator.nextNode();
var previousNode = nodeIterator.previousNode();
currentNode === previousNode  //true

document.createTreeWalker()

該方法返回一個DOM的子樹遍歷器對象(TreeWalker實例)
:遍歷器返回的第一個節點,不是根節點。

var treeWalker = document.createTreeWalker(
  document.body, //要遍歷的根節點
  NodeFilter.SHOW_ELEMENT //要遍歷的節點類型
);

相同條件下,treeWalker 比 nodeIterator 少一個根節點。  

Element

屬性

innerHTML VS textContent VS  innerText

  • 讀屬性值時,若文本節點包含 &、<、> ,innerHTML屬性會轉義爲實體形式 &amp;、&lt;、&gt; 。若想獲得原文,建議使用element.textContent屬性。
  • 寫屬性值時,不存在上述轉義問題;
  • 爲了安全考慮,若是插入的是文本,優先textContent屬性;

方法

Element.insertAdjacentHTML()

將一個HTML字符串,解析生成DOM結構(轉義字符),插入相對於當前節點的指定位置。

  • 執行速度比innerHTML屬性快得多
  • 不轉義HTML字符串,致使不能用來插入用戶輸入的內容,不然會有安全風險

Element.closest()

接受一個CSS選擇器做爲參數,返回匹配該選擇器的、最接近當前節點的一個祖先節點(包括當前節點自己)。

若是沒有任何節點匹配 CSS 選擇器,則返回null。

Element.getBoundingClientRect()

返回一個rect對象,提供當前元素節點的大小、位置等信息(CSS盒狀模型的全部信息)

x:元素左上角相對於視口的橫座標
y:元素左上角相對於視口的縱座標
/// 元素自己 + padding + border
height:元素高度
width:元素寬度
/// 隨着頁面滾動變化而變更
left:元素左上角相對於視口的橫座標,與x屬性相等
right:元素右邊界相對於視口的橫座標(等於x + width)
top:元素頂部相對於視口的縱座標,與y屬性相等
bottom:元素底部相對於視口的縱座標(等於y + height)

若要獲得絕對值,能夠將left屬性加上window.scrollXtop屬性加上window.scrollY

rect對象沒有自身屬性,所有繼承於原型屬性,因此:Object.keys(rect) // [] 

另外,Element.getClientRects 方法返回類數組對象,與Element.getBoundingClientRect()相比,該方法:

  • 返回對象有多少個成員,取決於該元素在頁面上佔據多少行
  • 主要用於判斷行內元素是否換行,以及行內元素的每一行的位置偏移
  • 考慮行內元素的換行符

此外,對於頁面元素的焦點問題,考慮如下屬性和方法

Element.focus()
Element.blur()
document.activeElement

/// 讓xxx元素得到焦點,並滾動到可見區域
function getFocus() {
  document.getElementById('xxx').focus({preventScroll:false});
}

DOM事件

事件驅動編程模式(event-driven),經過監聽函數對事件作出反應。 全部DOM的事件操做(監聽和觸發),都定義在EventTarget接口

  • addEventListener:綁定事件的監聽函數
  • removeEventListener:移除事件的監聽函數
  • dispatchEvent:觸發指定事件

若向監聽函數傳遞參數,可用匿名函數包裝監聽函數

btn.addEventListener('click',
    function () {
        alert(this.nodeName); //監聽函數內部的this,指向當前事件所在的那個對象
        fun('Hello');
    }, false);

其中,false標誌冒泡階段,true標誌捕獲階段,默認false。

事件綁定

JS提供三種爲事件綁定監聽函數的方法:

  • HTML的on-屬性:冒泡階段觸發,值爲函數當即執行代碼
el.setAttribute('onclick', 'doSomething()');
// 等同於
<Element onclick="doSomething()">

違反了HTML與JavaScript代碼相分離的原則。

  • 元素節點對象的事件屬性:冒泡階段觸發,值爲函數名
div.onclick = function (event) {
  console.log('觸發事件');
};

缺點是同一個事件只能定義一個監聽函數。

  • EventTarget.addEventListener()

推薦使用

  • 同一個事件能夠添加多個監聽函數
  • 可以指定在哪一個階段(捕獲階段仍是冒泡階段)觸發監聽函數
  • 除了DOM節點,其餘對象(好比windowXMLHttpRequest等)也有這個接口,它等因而整個JavaScript統一的監聽函數接口

事件傳播

propagation,事件傳播的最上層對象是window,接着依次是document,html(document.documentElement)和body(document.body)

  • 第一階段:(始於window,由外向內)從window對象傳到目標節點(上層傳到底層),稱爲「捕獲階段」(capture phase)
  • 第二階段:在目標節點上觸發,稱爲「目標階段」(target phase)
  • 第三階段:(由內向外,終於window)從目標節點傳回window對象(從底層傳回上層),稱爲「冒泡階段」(bubbling phase)

注意,瀏覽器老是假定click事件的目標節點,是點擊位置嵌套最深的那個節點。

對事件傳播的詳細講解過程,參見:JS教程 - 事件模型 的propagation部分。

事件代理

delegation,把監聽函數定義在父節點上,由父節點的監聽函數統一處理多個子元素的事件。 

能夠經過事件對象的stopPropagation方法阻止事件的傳播

// 事件傳播到 node 元素後,就再也不向下傳播了
node.addEventListener('click', function (event) {
  event.stopPropagation();
}, true); ///捕獲階段

// 事件冒泡到 node 元素後,就再也不向上冒泡了
node.addEventListener('click', function (event) {
  event.stopPropagation();
}, false); ///冒泡階段

若同時阻止node節點的其餘click事件的監聽函數,完全阻止這個事件的傳播,請移步:stopImmediatePropagation方法。

事件對象

瀏覽器原生提供一個Event對象,全部的事件都是該對象的實例,或者說繼承了Event.prototype對象。

var event = new Event(
  'look', {
     'bubbles': true,
     'cancelable': false
  });

其中,只讀屬性bubble的true標誌冒泡階段,false標誌捕獲階段,默認false。

由Event構造函數生成的事件,Event.isTrusted屬性返回false,標誌是腳本產生的,而非真正的用戶行爲產生的。 

除Event外,瀏覽器原生提供CustomEvent()構造函數,用來生成自定義的事件實例。

  • 在觸發事件的同時,傳入指定的數據
  • 數據經過其屬性detail帶入 

Event.eventPhase

返回一個整數常量,表示事件目前所處的階段,只讀屬性

  • 0,事件目前沒有發生
  • 1,事件目前處於捕獲階段,即處於從祖先節點向目標節點的傳播過程當中
  • 2,事件到達目標節點,即Event.target屬性指向的那個節點
  • 3,事件處於冒泡階段,即處於從目標節點向祖先節點的反向傳播過程當中

Event.cancelable

返回一個布爾值,表示事件是否能夠取消,只讀屬性,默認false

推薦用法:調用Event.preventDefault()以前,先預判

function preventEvent(event) {
  if (event.cancelable) {
    event.preventDefault();
  } else {
    console.warn('This event can not be canceled.');
  }
}

Event.target VS Event.currentTarget

  • target屬性:返回原始觸發事件的那個節點,即事件最初發生的節點
  • currentTarget屬性:返回事件當前所在的節點,即正在執行的監聽函數所綁定的那個節點

事件傳播過程當中,不一樣節點的監聽函數內部的Event.target與Event.currentTarget屬性的值是不同的,前者老是不變的,後者則是指向監聽函數所在的那個節點對象。

Event.preventDefault()

取消瀏覽器對當前事件的默認行爲,前提是事件對象的cancelable屬性爲true。

該方法只是取消事件對當前元素的默認影響,不會阻止事件的傳播。

Event.composedPath()

返回一個數組,成員是事件的最底層節點和依次冒泡通過的全部上層節點。

事件類型

  1. 鼠標事件:繼承MouseEvent接口

在父節點內部進入子節點,不會觸發mouseenter事件,可是會觸發mouseover事件;

在父節點內部離開子節點,不會觸發mouseleave事件,可是會觸發mouseout事件;

relatedTarget:節點對象,表示事件的相關節點,默認爲null。

mouseenter和mouseover事件時,表示鼠標剛剛離開的那個元素節點;

mouseout和mouseleave事件時,表示鼠標正在進入的那個元素節點;

拓展注意,不一樣事件的target屬性和relatedTarget屬性的不一樣:

事件名稱	target 屬性	   relatedTarget 屬性
focusin	接受焦點的節點	喪失焦點的節點
focusout	喪失焦點的節點	接受焦點的節點
mouseenter	將要進入的節點	將要離開的節點
mouseleave	將要離開的節點	將要進入的節點
mouseout	將要離開的節點	將要進入的節點
mouseover	將要進入的節點	將要離開的節點
dragenter	將要進入的節點	將要離開的節點
dragexit	將要離開的節點	將要進入的節點
  1. 滾輪事件:WheelEvent接口繼承MouseEvent的實例

瀏覽器原生提供WheelEvent()構造函數,用來生成WheelEvent實例。

var wheelEvent = new WheelEvent('wheel', options);  
  1. 鍵盤事件:繼承KeyboardEvent接口、Event接口

瀏覽器原生提供KeyboardEvent構造函數,用來新建鍵盤事件的實例。

屬性key表示當前按下的鍵,默認爲空字符串。

注意,若是一直按鍵不鬆開,會一直觸發事件,直至鬆開

keydown --> keypress --> keydown --> keypress --> …(重複以上過程) --> keyup

經過KeyboardEvent.repeat屬性返回一個布爾值,表明該鍵是否被按着不放,以便判斷是否重複這個鍵。

  1. 進度事件:繼承ProgressEvent接口

描述資源加載/文件上傳的進度,主要由 AJAX請求、<img>、<audio>、<video>、<style>、<link> 等外部資源的加載觸發。

abort:外部資源停止加載時(好比用戶取消)觸發。若是發生錯誤致使停止,不會觸發該事件。
error:因爲錯誤致使外部資源沒法加載時觸發。
load:外部資源加載成功時觸發。
loadstart:外部資源開始加載時觸發。
loadend:外部資源中止加載時觸發,發生順序排在error、abort、load等事件的後面。
progress:外部資源加載過程當中不斷觸發。
timeout:加載超時時觸發。

推薦方法,避免出現圖片在腳本未執行完就加載完畢、監聽函數不會執行的狀況

function loaded() { // ... }

if (image.complete) {
  loaded();
} else {
  image.addEventListener('load', loaded);
}

注意,因爲DOM元素節點沒有提供是否加載錯誤的屬性,因此error事件的監聽函數最好放在<img>元素的HTML代碼中,這樣才能保證發生加載錯誤時百分之百會執行錯誤提示。並且,error事件不會冒泡,子元素的error事件,不會觸發父元素的error事件監聽函數。

  1. 拖拉事件:繼承DragEvent接口,同時繼承MouseEvent接口和Event接口

瀏覽器原生提供一個DragEvent()構造函數,用來生成拖拉事件的實例對象。

關於拖拉事件,有如下幾個注意點

  • 某個元素節點的draggable屬性設爲true,就沒法再用鼠標選中該節點內部的文字或子節點。
  • 拖拉過程只觸發以上這些拖拉事件,儘管鼠標在移動,可是鼠標事件不會觸發。
  • 將文件從操做系統拖拉進瀏覽器,不會觸發dragstartdragend事件。
  • dragenterdragover事件的監聽函數,用來取出拖拉的數據(即容許放下被拖拉的元素)。因爲網頁的大部分區域不適合做爲放下拖拉元素的目標節點,因此這兩個事件的默認設置爲當前節點不容許接受被拖拉的元素。若是想要在目標節點上放下的數據,首先必須阻止這兩個事件的默認行爲。

經過以下例子:將一個節點從當前父節點,拖拉到另外一個父節點中,理解拖拉事件

/* HTML 代碼以下
 <div class="dropzone">
   <div id="draggable" draggable="true">
     該節點可拖拉
   </div>
 </div>
 <div class="dropzone"></div>
 <div class="dropzone"></div>
 <div class="dropzone"></div>
*/

// 被拖拉節點
var dragged;

document.addEventListener('dragstart', function (event) {
  // 保存被拖拉節點
  dragged = event.target;
  // 被拖拉節點的背景色變透明
  event.target.style.opacity = 0.5;
}, false);

document.addEventListener('dragend', function (event) {
  // 被拖拉節點的背景色恢復正常
  event.target.style.opacity = '';
}, false);

document.addEventListener('dragover', function (event) {
  // 阻止事件的默認行爲,防止拖拉效果被重置,容許被拖拉的節點放入目標節點
  event.preventDefault();
}, false);

document.addEventListener('dragenter', function (event) {
  // 目標節點的背景色變紫色
  // 因爲該事件會冒泡,因此要過濾節點
  if (event.target.className === 'dropzone') {
    event.target.style.background = 'purple';
  }
}, false);

document.addEventListener('dragleave', function( event ) {
  // 目標節點的背景色恢復原樣
  if (event.target.className === 'dropzone') {
    event.target.style.background = '';
  }
}, false);

document.addEventListener('drop', function( event ) {
  // 防止事件默認行爲(好比某些元素節點上能夠打開連接),
  event.preventDefault();
  if (event.target.className === 'dropzone') {
    // 恢復目標節點背景色
    event.target.style.background = '';
    // 將被拖拉節點插入目標節點
    dragged.parentNode.removeChild(dragged);
    event.target.appendChild( dragged );
  }
}, false);

注意,drag、dragstart、dragend是針對被拖拉對象,dragenter、dragover、dragleave、drop是針對目標結點對象。  

DataTransfer

全部拖拉事件的實例都有一個DragEvent.dataTransfer屬性,用來讀寫須要拖拉傳遞的數據。該屬性的值是一個DataTransfer接口的實例。 

瀏覽器原生提供一個DataTransfer()構造函數,無參

var dataTrans = new DataTransfer();

拖拉事件開始時,開發者能夠提供數據類型和數據值。拖拉過程當中,開發者經過dragenter和dragover事件的監聽函數,檢查數據類型以肯定是否容許放下(drop)被拖拉的對象。發生drop事件時,監聽函數取出拖拉的數據便可。

屬性

dropEffect VS effectAllowed

  • dropEffect設置接受拖拉結點的區域的效果,effectAllowed設置本次拖拉中被拖拉的節點容許的效果;
  • dropEffect在dragenter和dragover事件的監聽函數中設置,effectAllowed在dragstart事件的監聽函數中設置;

該2個屬性是同一件事的兩個方面,一般配合使用

source.addEventListener('dragstart', function (e) {
  e.dataTransfer.effectAllowed = 'move';
});

target.addEventListener('dragover', function (e) {
  ev.dataTransfer.dropEffect = 'move';
});

types VS items

  • 拖拉的數據格式(一般是 MIME 值),只讀數組
  • 相似數組的只讀對象(DataTransferItemList 實例),每一個成員就是本次拖拉的一個對象(DataTransferItem 實例)

該2個屬性一般在drop事件的監聽函數中獲取。

:若想爲拖拉事件添加數據,只能在dragstart中設置;若想從拖拉事件中獲取數據,只能在drop事件監聽函數中。 

  1. 觸摸事件:觸摸點(Touch)、觸摸點集合(TouchList)、觸摸事件(TouchEvent)

TouchEvent接口繼承Event接口,表示由觸摸引起的事件實例

  • touchesTouchList實例,表明全部的當前處於活躍狀態(觸摸中)的觸摸點,默認值是一個空數組[]
  • targetTouchesTouchList實例,表明全部處在觸摸的目標元素節點內部、且仍然處於活動狀態的觸摸點,默認值是一個空數組[]
  • changedTouchesTouchList實例,表明本次觸摸事件的相關觸摸點,默認值是一個空數組[]

若 ev.touches.length === ev.targetTouches.length,代表全部觸摸點均在目標元素結點內。

:若想在發生觸摸事件的同時阻止鼠標事件,使用:event.preventDefault方法。

  1. 表單事件
// input事件(連續觸發)
 當<input>、<select>、<textarea>的值發生變化,
 單複選框改變選項,
 打開contenteditable屬性的元素結點的值發生變化時觸發
// select事件
 在<input>、<textarea>裏面選中文本時觸發
// Change事件(不會連續觸發)
 當<input>、<select>、<textarea>的值發生變化且只有當所有修改完成時纔會觸發
 [1]. 激活單選框(radio)或複選框(checkbox)時觸發。
 [2]. 用戶提交時觸發。好比,從下列列表(select)完成選擇,在日期或文件輸入框完成選擇。
 [3]. 當文本框或<textarea>元素的值發生改變,而且喪失焦點時觸發。
// invalid 事件
用戶提交表單時,若是表單元素的值不知足校驗條件時觸發
// reset 事件,submit 事件:發生在表單對象<form>上,而不是發生在表單的成員上
reset事件當表單重置(全部表單成員變回默認值)時觸發。
submit事件當表單數據向服務器提交時觸發。 
  1. 其餘事件

a. 資源事件

  • beforeunload事件:資源將要卸載前觸發
  • unload 事件:窗口關閉或者document對象將要卸載時觸發。它的觸發順序排在beforeunloadpagehide事件後面。事件發生時,全部資源依然存在,可是對用戶來講都不可見,UI互動所有無效。緩存存在,則事件無效。
  • load事件:頁面或某個資源加載成功時觸發。緩存存在,則事件無效。

推薦:兼容性好

window.addEventListener('beforeunload', function(e) {
   var confirmationMessage = '確認關閉窗口?';
   e.returnValue = confirmationMessage;
   return confirmationMessage;
});  

b. 焦點事件

在元素節點和document對象上面觸發,與得到/失去焦點相關。

  • focus:元素節點得到焦點後觸發,該事件不會冒泡
  • blur:元素節點失去焦點後觸發,該事件不會冒泡
  • focusin:元素節點將要得到焦點時觸發,發生在focus事件以前,該事件會冒泡
  • focusout:元素節點將要失去焦點時觸發,發生在blur事件以前,該事件會冒泡

focusin --> focus --> focusout --> blur 

這四個事件都繼承FocusEvent接口,提供屬性:

  • FocusEvent.target:事件的目標節點
  • FocusEvent.relatedTarget:對於focusin事件,返回失去焦點的節點;對於focusout事件,返回將要接受焦點的節點;對於focusblur事件,返回null

對於focus和blur事件,一般將addEventListener方法的第三個參數須要設爲true,由於只能在捕獲階段觸發。

form.addEventListener('focus', function (event) {
  event.target.style.background = 'pink';
}, true);

form.addEventListener('blur', function (event) {
  event.target.style.background = '';
}, true);

c. session歷史事件

默認狀況下,瀏覽器會在當前會話(session)緩存頁面,當用戶點擊「前進/後退」按鈕時,瀏覽器就會從緩存中加載頁面。

  • pageshow事件:頁面加載時觸發,包括第一次加載和從緩存加載兩種狀況。第一次加載時,觸發順序在load事件後。從緩存加載時,load事件不會觸發。利用pageshow事件的persisted屬性,能夠判斷頁面是從何處加載而來:false標誌第一次加載,true標誌緩存加載。
  • pagehide事件:經過「前進/後退」按鈕,離開當前頁面時觸發。利用pagehide事件的persisted屬性,設置爲true,表示頁面要保存在緩存中;反之,不保存。
  • hashchange事件:URL的hash 部分(#號後面的部分,包括#號)發生變化時觸發,在window對象上監聽。
  • popstate事件:只在瀏覽器的history對象的當前記錄發生顯式切換時觸發。(好比鼠標點擊「後退/前進」按鈕)

d. 網頁狀態事件

  • DOMContentLoaded事件

網頁下載並解析完成之後,瀏覽器就會在document對象上觸發,遠早於load事件。

:網頁的JavaScript腳本是同步執行的,腳本一旦發生堵塞,將推遲觸發DOMContentLoaded事件。

  • readystatechange事件

當Document對象和XMLHttpRequest對象的readyState屬性發生變化時觸發。readyState有3種狀態:

  1. loading:網頁正在加載
  2. interactive:網頁已經解析完成,可是外部資源仍然處在加載狀態
  3. 和complete:網頁和全部外部資源已經結束加載,load事件即將觸發

e. 窗口事件

主要是scroll事件:在文檔或文檔元素滾動時觸發(用戶拖動滾動條)。 

  • 該事件會連續地大量觸發,監聽函數內不該有耗時操做;(resize事件亦是)
  • 推薦使用requestAnimationFrame或setTimeout控制該事件的觸發頻率,結合customEvent拋出一個新事件;

目前lodash函數庫提供了現成的throttle函數,能夠直接使用:將一個函數的調用頻率限制在必定閾值內

window.addEventListener('scroll', _.throttle(callback, 1000));

關於函數節流(throttle)和函數去抖(debounce)的問題,具體參見:函數節流與函數去抖 - sqh

f. 剪貼板事件

  • cut:將選中的內容從文檔中移除,加入剪貼板時觸發
  • copy:進行復制動做時觸發
  • paste:剪貼板內容粘貼到文檔後觸發

這三個事件都是ClipboardEvent接口的實例。ClipboardEvent的實例屬性clipboardData是一個DataTransfer對象,存放剪貼的數據。

關於事件類型的詳細信息,參見:JS教程 - 事件種類; 

擴展

(1)自定義渲染方法

即自定義jQuery插件,涉及:

  • $.fn:定義方法
  • $.extend(target, obj1, obj2, ...):定義參數 

具體地,編寫一個jQuery插件的原則:

  1. $.fn綁定函數,實現插件的代碼邏輯
  2. 插件函數最後要return this;以支持鏈式調用
  3. 插件函數要有默認值,綁定在$.fn.<pluginName>.defaults
  4. 用戶在調用時可傳入設定值以便覆蓋默認值
$.fn.方法名 = function (options) {
    // 合併默認值和用戶設定值:
    var opts = $.extend({}, $.fn.方法名.defaults, options);
    // 樣式渲染
    this.css('backgroundColor', opts.backgroundColor)
         .css('color', opts.color);
    // 返回this,支持鏈式調用
    return this;
}
// 設定默認值:
$.fn.方法名.defaults = {
    color: '#d85030',
    backgroundColor: '#fff8de'
}

支持用戶自定義默認值

$.fn.方法名.defaults.color = '#fff';
$.fn.方法名.defaults.backgroundColor = '#000';  

也能夠傳參覆蓋默認值。 

(2)underscore庫

完善的函數式編程接口,如同jQuery會綁定到$上,underscore會綁定到_上。

安裝:npm install underscore

具體參見:underscore.js;  

相關文章
相關標籤/搜索