JavaScript DOM編程基礎(DOM屬性&事件[叮:事件代理],Ajax,BOM,form表單)

文檔樹 DOM:Document Object Model

即:用對象的形式表示HTML、CSS。css

DOM包含:html

  • DOM Core
  • DOM HTML
  • DOM Style
  • DOM Event

1.節點遍歷:ヾ(o◕∀◕)ノ

node.parentNode
    .childNodes //獲得node的所有子節點,包括各類類型
    .firstChild
    .lastChild
    .previousSibling
    .nextSibling //下一個兄弟節點

2.元素類型節點遍歷:

p.parentElement  //父元素節點
 .children //返回指定節點的全部element子節點的活HTMLCollection,能夠children[0].nodeName獲取
 .firstElementChild
 .lastElementChild
 .previousElementSibling
 .nextElementSibling

節點操做

圖片描述

1.獲取節點

getElementById

//返回live(實時變化)的動態集合
getElementsByClassName("classA")
//獲取同時有兩個類名的元素節點
getElementsByClassName("classA classB") 

//返回live(實時變化)的動態集合
getElementsByTagName()

//特別注意:querySelectorAll是non-live(非實時變化)的。 ヾ(o◕∀◕)ノ
querySelector("#users") 獲取第一個符合條件的元素
querySelector("input[type='text']") 能夠根據屬性進行選擇,很方便
querySelectorAll(".user") 獲取全部匹配的元素
querySelectorAll("#users .user")

注意:以上選擇器(getElementById除外),除了能夠在整個文檔中尋找,好比: document.getElementsByClassName('className'),還能夠在某個節點下尋找,好比:element.getElementsByClassName('className')node

2.增長節點

建立節點 ヾ(o◕∀◕)ノ

//建立指定標籤名稱的節點
element = document.createElement(tagName)
var li = document.createElement("li");
var a = document.createElement("a");

設置節點內容

//獲取節點及其後代節點的文本內容或爲節點添加內容
element.textContent
element.innerText
element.textContent = "newValue";
element.innerText = "newValue";

插入節點到文檔中 ヾ(o◕∀◕)ノ

//插入節點
//appendChild會添加到parentElement結束標籤以前,也就是變成parentElement元素的最後一個子元素
parentElement.appendChild(childElement); 
//insertBefore會添加newElement到parentElement下referenceElement元素前面
parentElement.insertBefore(newElement, referenceElement)

3.移動&克隆節點 ヾ(o◕∀◕)ノ

若是想把一個節點從原來的位置移動到指定位置。那麼只須要:ajax

const myElementClone = document.getElementById("myElement");
document.getElementById("new-position").appendChild(myElementClone);

但若是不想移動原來節點的位置,而是想克隆一個新的節點出來,那麼須要用到cloneNode(true)spring

const myElementClone = document.getElementById("myElement").cloneNode(true);
document.getElementById("new-position").appendChild(myElementClone);

4.刪除節點 ヾ(o◕∀◕)ノ

parentElement.removeChild(child);
一般不用專門獲取parentElement,直接寫child.parentNode便可

5.可同時用於添加節點,設置節點內容,插入節點,刪除節點

//獲取節點內部的全部HTML結構代碼,或爲節點添加內部的html代碼
element.innerHTML
element.innerHTML = "<a href="#">hahaha</a>"
//可能有內存泄漏和安全問題,所以僅建議用於新建節點,並儘可能不用於用戶填的內容

屬性操做

1.HTML attribute -> DOM property

input元素

  • id - id
  • type - type
  • class - className

label元素

  • for - htmlFor

2.property accessor 屬性訪問器

兩種訪問方式:編程

  1. input.className;
  2. input["id"] = 'cute'

屬性訪問器的通用性拓展性很差。canvas

3.getAttribute/setAttribute

  1. element.getAttribute(attritubeName)

eg: input.getAttribute("class");api

  1. element.setAttribute(name, value)

eg: input.setAttribute("id", "unique") //會將id設置爲unique
特例:disabled屬性
//如下三種都會將disabled設置爲生效
input.setAttribute("disabled", true)
input.setAttribute("disabled", "")
input.setAttribute("disabled", false)
由於setAttribute只是字符串的操做,因此想要移除disabled屬性只能input.removeAttribute("disabled");跨域

缺點:僅僅是字符串的操做。
優勢:通用性好,直接把HTML屬性名傳進去就好了。瀏覽器

4.自定義屬性: dataset

HTMLElement.datasetdataset是HTML元素上的一個屬性,是data-*屬性的一個集合,主要的用途是在元素上保存數據。通常用來作自定義的數據屬性

<div id="users" data-id="123456" data-account-name="darcy">Darcy
</div>
<p id="info"></p>

div.dataset.

  • id: 123456
  • accountName: darcy
//在JS中能夠這樣獲取:
var data = div.dataset;
//而後這樣用
var dataId = data.id;
document.getElementById("info").innerText = data.accountName;

5.修改class列表: classList

element.classList.add("classA"); // 爲元素添加一個class
element.classList.remove("classA"); // 刪除元素上名爲classA的類
element.classList.toggle("classA");

樣式操做(經過JS動態修改樣式)

style, style.cssText, class, styleSheet, window.getComputedStyle

圖片描述

1. element.style.cssProperty

<div id="users" style="color:red;">
Darcy
</div>
var div = document.getElementById("users");
console.log(div.style.color); // red

2.更新樣式

element.style.cssProperty

element.style.borderColor = "red";
element.style.color = "red";

缺點:更新每個屬性都須要單獨的一條語句。

改進:用element.style.cssText = "border-colot: red; color: red;"

缺點:樣式混在邏輯中。

再次改進:更新class(推薦方法)

.invalid {
  border-color: red;
  color: red;
}

element.className += " invalid"

存在的問題:一次更新不少元素的樣式時會很麻煩。

改進(一次更新不少元素的樣式):更換樣式表

//html
<link id="skin" rel="stylesheet" href="skin.spring.css">

//js
document.getElementById("skin").href = "skin.summer.css";

3.獲取樣式

element.style.cssProperty

只能獲取到寫在HTML元素上的樣式,若寫在<style>標籤中,或外聯的css文件中就沒法獲取到了。

window.getComputedStyle("element")(推薦 ヾ(o◕∀◕)ノ)

//html
<div id="users">Darcy</div>
//css
#users{ color: blue; }
//js
var color = window.getComputedStyle("element").color;
color;// rgb(0, 0, 255);

事件

1.事件流

DOM事件流就是DOM事件處理執行的過程。分爲三個過程:

  • capture phase (捕獲過程:從DOM樹最頂端也就是window元素往下捕獲,直到觸發事件的元素的父元素爲止)
  • target phase(事件觸發過程:在觸發事件的節點上進行)
  • bubble phase(冒泡過程:從觸發事件的節點的父節點開始,冒泡到頂層的window對象)

點擊<a>標籤:

圖片描述

如何捕捉一個事件,咱們講DOM事件最終是爲了編程,那麼如何去捕獲一個事件,如何去處理一個事件呢?

2.事件註冊

事件註冊,取消與觸發的主體都是事件對象的DOM元素

1.事件註冊

eventTarget.addEventListener(type, listener[, useCapture])
type: 事件類型
listener:事件處理函數
useCapture:是否在捕獲階段觸發。默認是false,DOM事件處理的是冒泡過程,只有設置這個值爲true,纔會處理捕獲過程。

var elem = document.getElementById("div1");
//定義一個事件處理函數,即當事件被觸發時但願作的事情
var clickHandler = functin(event){
  //TODO
}
//註冊事件
elem.addEventListener('click', clickHandler, false);

2.取消事件註冊

eventTarget.removeEventListener(type, listener[, useCapture]);

3.事件觸發

  • 點擊元素
  • 按下按鍵
  • 用代碼觸發: eventTarget.dispatchEvent(type);
  • eg.用代碼觸發一個click事件: elem.dispatchEvent('click')

4.事件對象

當事件被觸發時,會調用事件處理函數,在調用的時候會傳入一些信息,這些信息表明了當前事件的一些狀態,這就是事件對象。調用事件處理函數的時候,引擎會傳入一個對象給咱們,就是事件對象。咱們在編程的時候,會用到這個事件對象的一些屬性和方法。

var elem = document.getElementById("div1");
var clickHandler = functin(event){ //這個event就是事件對象
  //TODO
}
elem.addEventListener('click', clickHandler, false);

第二行的event就是事件對象。當咱們用鼠標點擊的時候,這個event對象可能包含了鼠標的位置,x,y座標等等。

- 事件對象的屬性:

  • type,事件類型,好比click
  • target,事件觸發的節點,好比點擊一個<a>元素,target就是<a>元素
  • currentTarget,是咱們當前處理事件節點的元素。適用於這樣一種狀況:當咱們須要註冊一個click事件的時候,咱們不必定須要將事件註冊在target上,也能夠註冊在target的父節點上。由於當事件冒泡到target的父節點的時候,仍然能夠處理這個事件。因此,若是咱們把事件註冊在target的父節點上,仍然點擊target元素,event.target任然是target元素,那麼currentTarget就是它的父節點這個元素。只有當事件處於目標階段(target phase)被觸發的時候,currentTarget才與target的值同樣。

- 事件對象的方法:

  • stopPropagation 阻止冒泡,有時候咱們不想事件繼續冒泡上去了。
  • preventDefault 阻止默認行爲
  • stopImmediatePropagation 阻止冒泡

調用方法:

  • event.stopPropagation(); 阻止事件傳遞到父節點。
  • event.stopImmediatePropagation(); 除了阻止事件傳遞到父節點,還阻止了當前節點的後續事件。
  • event.preventDefault()阻止默認行爲

3.事件類型

圖片描述

1.Event

應用:<img>標籤中,當圖片找不到時,顯示默認圖片onerror事件

<img alt="photo" src="http://www.xxx.com/a.jpg" onerror="this.src='http://www.xxx.com/default.jpg'"/>

2.UIEvent

resize 改變頁面或窗體大小時觸發的事件
scroll 滾動事件

3.MouseEvent

事件類型:

圖片描述
注意:
mouseoutmouseleave的區別就是mouseleave不冒泡
mouseovermouseenter的區別也是mouseenter不冒泡

MouseEvent事件屬性:

  • clientX(觸發事件的點到頁面最左端的距離), clientY(觸發事件的點到頁面最上方的距離)
  • screenX(觸發事件的點到屏幕最左端的距離), screenY(觸發事件的點到屏幕最上方的距離)

MouseEvent事件順序:

好比:

1.從元素A上方移過期

mousemove -> mouseover(A) -> mouseenter(A) -> mousemove(A)[不少個] -> mouseout(A) -> mouseleave(A)

2.點擊元素

mousedown -> [mousemove] -> mouseup -> click

例子:拖拽div

需求:按下鼠標並移動時開始拖拽div,鬆開鼠標時中止拖拽div。mousedown -> mousemove -> mouseup

jsfiddle拖拽div栗子

4.FocusEvent

事件類型:

圖片描述

blur 元素失去焦點時
focus 元素得到焦點時
focusin 元素即將得到焦點時
focusout 元素將要失去焦點時

屬性:

relatedTarget 做用:當一個元素失去焦點時,另一個元素就要得到焦點。在blur失去焦點事件中,得到焦點的元素就是這個relatedTarget;在focus得到焦點事件中,失去焦點的元素就是這個relatedTarget

5.InputEvent

圖片描述

6.KeyBoardEvent鍵盤事件

圖片描述

屬性

  • key 按下了什麼鍵
  • code 按下了什麼鍵

jsfiddle中MDN官方例子

4.事件代理

需求:一個列表,點擊哪一行,這一行背景就變灰色,其他全是白色。
問題變爲:想要給一個ul下的多個li註冊同一個click事件(讓背景變灰),若是li個數很少還好,若是li不少,那麼爲每一個li都註冊一遍顯然太浪費了,那麼怎樣解決呢?

回憶咱們的事件流中的事件冒泡,能夠發現觸發事件的元素觸發了事件後,它會往上去冒泡,一直冒泡到window對象。而事件是在冒泡階段被觸發的,因此它的全部父元素也是能夠接收到這個click事件被觸發了的。因此若是咱們把事件註冊到 觸發事件的元素 的父元素上,它也是會執行的。所以,咱們能夠把事件註冊在元素的父節點上來實現,能夠是最近的父節點,也能夠是再上層的父節點。這裏咱們經過在ul上註冊來實現這一功能,而後經過事件處理函數中的event.target能夠拿到當前觸發的li元素。

//html
<ul id="myUl">
  <li></li>
  <li></li>
  <li></li>
  <li></li>
</ul>

//js
var myUl = document.getElementById("myUl");
myUl.addEventListener("click", function(event){
  var target = event.target;//當前點擊的li,就是事件觸發的節點
  //TODO
});

優勢:
1.要管理的handle更少
2.分配的內存更少
3.當增長或刪除子節點時不用處理事件,上例中的li

缺點:
1.註冊到父元素上的事件的回調函數的邏輯更復雜

用的比較多的地方是列表eg. ul>li*4

數據通訊

1.http協議

經常使用http方法

圖片描述

URL構成

圖片描述

常見HTTP狀態碼

圖片描述

2.ajax請求

1.打開瀏覽器

var xhr = new XMLHttpRequest();

2.在地址欄輸入地址

xhr.open('get', '1.txt', true);

2.1[可選]設置請求頭

xhr.setRequestHeader(header, value);
eg:
xhr.setRequestHeader("content-type", "application/x-www-form-urlencoded" );

3.提交,發送請求

xhr.send([data = null]);

data能夠是string類型,也能夠是form-data類型

4.等待服務器返回內容

xhr.onreadystatechange = function(){
  if(xhr.readyState == 4){
    if((xhr.status >= 200 && xhr.status <= 300) || xhr.status == 304){
      console.log(xhr.responseText);
    } else {
      console.log('Request was unsuccessful:' + xhr.status)
    }
  }
}

還能夠監聽xhr.onload事件,這個事件是當xhr.readyState = 4而且xhr.status = 200纔會觸發的。

同源策略

同源策略

不知足同源策略的訪問,就叫跨域資源訪問,遵循W3C定義的CORS標準。

流程圖:

圖片描述

數據存儲

cookie

document.cookie:是一段小型的文本文件。大小在4kb左右。由鍵值對(name-value)構成,鍵值對中間由; 空格隔開。
eg:

"SRCHD=AF=NOFORM; SRCHUSR=DOB=20160521; SRCHUID=V=2&GUID=48081778AFB747C3925DAF775B98D983; MUID=29B9478F16FC621D1C93409312FC61CF; ipv6=hit=1; _FP=hta=on; SRCHHPGUSR=CW=1349&CH=638&DPR=1.25&UTC=480; WLS=TS=63629214318; _SS=SID=18C4028A873563381E5C08FF86946247&HV=1493617535&bIm=475643"

雖然cookie是存儲在瀏覽器端,但大部分時候cookie在服務器端進行設置。服務端經過在HTTP返回的Response Headers裏面經過設置set-cookie這個字段讓瀏覽器知道須要存儲的cookie

圖片描述

屬性:
除了NameValue以外,還有
Domain
Path
瀏覽器會話時間:Expires(時間戳)/Max-Age(最長時間)

cookie進行增刪改查:

document.cookie 屬性看起來像是一個普通的文本字符串,其實它不是。
因此,很神奇的一點是:添加新的cookie只須要document.cookie = "newKey=newValue";就能夠了,不須要document.cookie += ...,以前的cookie不會被覆蓋。
還有一點是:即便在 document.cookie 中寫入一個完整的 cookie 字符串, 當從新讀取該 cookie 信息時,cookie 信息是以名/值對的形式展現的。

去jsfiddle裏看吧

刪除cookie:將它的max-age屬性設置爲0就能夠刪除了。

缺陷:流量代價,安全性問題,大小限制。

storage [localStorage & sessionStorage]

localStorage有效期:永久

sessionStorage有效期:瀏覽器會話期間,不一樣窗口見不共享sessionStorage

大小在5MB左右。

localStorage.name
delete localStorage.name

使用API

//讀取值
localStorage.getItem("name"); //傳入name來訪問對應的值
localStorage.key(i); //傳入索引值來訪問對應的值

//設置值
localStorage.setItem("name", "realValue");

//刪除值
localStorage.removeItem("name");

//清空全部的數據
localStorage.clear();

動畫

三要素:對象,屬性,定時器

setInterval, setTimeout, requestAnimationFrame()

var intervalId = setInterval(func, delay); //delay 爲觸發的間隔
clearInterval(intervalId);

var intervalId2 = setTimeout(func, delay); //delay默認是0,若是不寫就當即觸發,是一個異步的過程
clearTimeout(intervalId2);

區別在於:setTimeout只執行一次,setInterval會重複執行。

eg1:
var intervalId = setInterval(function(){ //關於func的寫法,我是一顆常見的栗子 }, delay);
eg2:
var funcA = function(){//我是第二顆常見栗子 };
var intervalId = setInterval(funcA, delay);

var requestId = requestAnimationFrame(func);
cancelAnimationFrame(requestId);

間隔時間不禁用戶控制,由顯示器的刷新頻率控制,大概1s刷新60次。每次瀏覽器刷新會觸發這個操做,不須要用戶關心間隔時間,且動畫更流暢,不會出現掉幀的狀況。

常見動畫:

形變

位移

旋轉

透明度

複雜動畫也都是由簡單動畫構成的。

音頻與視頻

<audio src=""></audio>
<video src="" width=320 height=240></video>

控制播放的方法和屬性:

圖片描述

查詢媒體狀態:

圖片描述

canvas

不建議用css指定寬高,直接在<canvas>標籤中指定寬和高。

<canvas id="tutorial" width=320 height=240><</canvas>

怎樣獲取canvas的渲染上下文對象?

經過getContext("2d")方法:

var canvas = document.getElementById("tutorial");
var context = canvas.getContext("2d");

基本繪圖步驟:

圖片描述

地球繞着太陽轉實例代碼:

圖片描述

Mozilla官方教程

BOM

BOM是表明瀏覽器窗口對象的一組API
Screen,navigator,location,history對話框,窗體互操做,load,beforeunload,scroll,resize等事件

1.屬性:

圖片描述

navigator

window.navigator.platform // "Win32"
window.navigator.userAgent // 包含瀏覽器內核信息 "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36"

能夠經過userAgent判斷當前運行在什麼設備上。

location

圖片描述

protocol + host(hostname + port) + pathname + search + hash

window.location.href表示當前頁面完整路徑,也能夠經過修改這個屬性讓瀏覽器跳轉。

方法:

window.location.assign(url) 跳轉頁面,記錄歷史。
window.location.replace(url) 跳轉頁面,不記錄歷史。
window.location.reload() 重載當前頁面。

history

屬性:length

方法:

back(n) //傳入正整數,後退n步
forward(n) //傳入負整數,前進n步
go(n) //傳入整數,正數前進,負數倒退

screen

屬性:

availHeight
availWidth

加了avail的是可用的屏幕屬性,沒加的是顯示器的屬性。

2.方法:

圖片描述

3.事件

圖片描述

注意beforeunload事件,詢問了用戶是否決定離開。

表單操做

示例:

服務器接收的信息:

請求的url:https://www.xxx.com/order
格式:application/x-www-form-urlencoded
參數:custname,size,...

<form method="post" action="https://www.xxx.com/order" enctype="application/x-www-form-urlencoded">
<label>姓名:<input name="custname"></label>
<div>披薩大小:
<label>小<input type="radio" name="size" value="small"></label>
<label>中<input type="radio" name="size" value="medium"></label>
<label>大<input type="radio" name="size" value="big"></label>
</div>
...
</form>

注意添加required屬性:<input required>,可讓在submit時就檢測出沒有填寫的表單並給用戶以提示。

1.表單元素

1.1form的屬性

圖片描述

name屬性用處是能夠直接拿到form節點元素:
var pizzaForm = document.forms.pizza;

1.2form的接口

reset()
可重置元素:input,keygen,output,select,textarea
觸發表單reset事件,阻止該事件的默認行爲可取消重置。
能夠用於刪除文件選擇器<input type="file">中已選擇的文件喲 ʅ(´◔౪◔)ʃ

1.3select的屬性和方法

圖片描述

方法:

  • add(element[, before])
  • remove([index])

建立選項:

  • 示例: document.createElement('option'); 等於 new Option();
  • 語法:new Option(text[, value[, defaultSelected[, selected]]])

添加選項:

  • 示例: element.insertAdjacentElement("beforeBegin", option) select.add(option, before)
  • 語法:selectObject.add(optionElement,beforeElement) , element.insertAdjacentElement(position, element);

刪除選項:

  • 示例:opt12.parentNode.removeChild(opt12) 等於 select.remove(2)
  • 語法:select.remove(index)

select級聯下拉選擇器

知識點:

  • onchange
  • remove
  • add

jsfiddle栗子

主要代碼:

//向列表中填充數據
function fillSelect(select, list){
  //先倒序遍歷清空列表
  for(var i=select.length-1; i>0; i--){
    select.remove(i);
  }
  //而後把傳入的數據列表list經過循環添加到option上去
  list.forEach(function(data){
    var option = new Option(data.text, data.value)
    select.add(option);
  })
}
fillSelect(demoForm.chapter, chapters);

demoForm.chapter.addEventListener("click", function(event){
  var value = event.target.value;
  //另外一種獲取value的方式:demoForm.chapter.value
  var list = sections[value] || [];
  fillSelect(demoForm.section, list);
})

2.表單驗證

可驗證元素:button input select textarea

element的屬性和方法:

  • willValidite 可用於判斷元素是否會被驗證
  • checkValidity() 驗證某個元素
  • validity 存儲驗證結果,錯誤信息等
  • validationMessage 驗證信息
  • setCustomValidity(message) 設置自定義的異常顯示信息

自定義異常:

圖片描述

若是不須要驗證,就在<form>上添加一個 novalidate 屬性,就禁止了該表單下全部的驗證。

3.表單提交

submit()方法能夠手動提交
onsubmit事件綁定的方法中,能夠經過阻止默認事件觸發來阻止表單提交刷新頁面

4.表單應用

驗證手機號能夠在標籤中寫pattern:

<input name="telephone" type="tel" pattern="^0?(1[34578])[0-9]{9}$">

驗證表單應該在表單的submit事件被觸發時進行,而不是按鈕被點擊時進行。由於還有其餘的觸發表單提交的方式。

列表操做

列表的顯示、添加、刪除、更新、選擇

數據結構:

圖片描述

事件代理:
若是須要在<ul>的每項<li>上都添加點擊事件,那麼就添加到<ul>上,在事件處理函數中經過event.target去獲取當前的點擊的<li>元素。

編程方式 : 面向視圖-> 面向數據

面向視圖編程

view與controller直接關聯在一塊兒。
由於視圖層變化會很頻繁,這直接致使控制層的變化。
並且從自動化測試的角度來講,由於視圖層沒辦法徹底自動化,而視圖層與控制層的耦合性如此高,致使控制層也沒辦法作徹底的自動化測試。

面向數據

將視圖(View)抽象成數據模型(ViewModel),後續全部的操做都針對數據模型來進行。只須要關注數據模型,不關注視圖上怎樣展現。

圖片描述

具體視圖上怎樣展現,交給Binder(專門的數據綁定相關的庫)去完成:

圖片描述

相關文章
相關標籤/搜索