即:用對象的形式表示HTML、CSS。css
DOM包含:html
node.parentNode .childNodes //獲得node的所有子節點,包括各類類型 .firstChild .lastChild .previousSibling .nextSibling //下一個兄弟節點
元素類型節點
遍歷:p.parentElement //父元素節點 .children //返回指定節點的全部element子節點的活HTMLCollection,能夠children[0].nodeName獲取 .firstElementChild .lastElementChild .previousElementSibling .nextElementSibling
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
//建立指定標籤名稱的節點 element = document.createElement(tagName) var li = document.createElement("li"); var a = document.createElement("a");
//獲取節點及其後代節點的文本內容或爲節點添加內容 element.textContent element.innerText element.textContent = "newValue"; element.innerText = "newValue";
//插入節點 //appendChild會添加到parentElement結束標籤以前,也就是變成parentElement元素的最後一個子元素 parentElement.appendChild(childElement); //insertBefore會添加newElement到parentElement下referenceElement元素前面 parentElement.insertBefore(newElement, referenceElement)
若是想把一個節點從原來的位置移動到指定位置。那麼只須要: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);
parentElement.removeChild(child); 一般不用專門獲取parentElement,直接寫child.parentNode便可
//獲取節點內部的全部HTML結構代碼,或爲節點添加內部的html代碼 element.innerHTML element.innerHTML = "<a href="#">hahaha</a>" //可能有內存泄漏和安全問題,所以僅建議用於新建節點,並儘可能不用於用戶填的內容
兩種訪問方式:編程
input.className;
input["id"] = 'cute'
屬性訪問器的通用性
和拓展性
很差。canvas
getAttribute/setAttribute
element.getAttribute(attritubeName)
eg: input.getAttribute("class");
api
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屬性名傳進去就好了。瀏覽器
dataset
HTMLElement.dataset
:dataset
是HTML元素上的一個屬性,是data-*
屬性的一個集合,主要的用途是在元素上保存數據。通常用來作自定義的數據屬性。
<div id="users" data-id="123456" data-account-name="darcy">Darcy </div> <p id="info"></p>
//在JS中能夠這樣獲取: var data = div.dataset; //而後這樣用 var dataId = data.id; document.getElementById("info").innerText = data.accountName;
classList
element.classList.add("classA"); // 爲元素添加一個class element.classList.remove("classA"); // 刪除元素上名爲classA的類 element.classList.toggle("classA");
style, style.cssText, class, styleSheet, window.getComputedStyle
element.style.cssProperty
<div id="users" style="color:red;"> Darcy </div>
var div = document.getElementById("users"); console.log(div.style.color); // red
element.style.cssProperty
element.style.borderColor = "red"; element.style.color = "red";
缺點:更新每個屬性都須要單獨的一條語句。
element.style.cssText = "border-colot: red; color: red;"
缺點:樣式混在邏輯中。
.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";
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);
DOM事件流就是DOM事件處理執行的過程。分爲三個過程:
點擊<a>
標籤:
如何捕捉一個事件,咱們講DOM事件最終是爲了編程,那麼如何去捕獲一個事件,如何去處理一個事件呢?
事件註冊,取消與觸發的主體
都是事件對象的DOM元素
。
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);
eventTarget.removeEventListener(type, listener[, useCapture]);
eventTarget.dispatchEvent(type);
elem.dispatchEvent('click')
當事件被觸發時,會調用事件處理函數
,在調用的時候會傳入一些信息,這些信息表明了當前事件的一些狀態,這就是事件對象
。調用事件處理函數
的時候,引擎會傳入一個對象給咱們,就是事件對象
。咱們在編程的時候,會用到這個事件對象的一些屬性和方法。
var elem = document.getElementById("div1"); var clickHandler = functin(event){ //這個event就是事件對象 //TODO } elem.addEventListener('click', clickHandler, false);
第二行的event
就是事件對象。當咱們用鼠標點擊的時候,這個event對象可能包含了鼠標的位置,x,y座標等等。
type
,事件類型,好比clicktarget
,事件觸發的節點,好比點擊一個<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()
阻止默認行爲
應用:<img>
標籤中,當圖片找不到時,顯示默認圖片onerror
事件
<img alt="photo" src="http://www.xxx.com/a.jpg" onerror="this.src='http://www.xxx.com/default.jpg'"/>
resize
改變頁面或窗體大小時觸發的事件scroll
滾動事件
注意:mouseout
與mouseleave
的區別就是mouseleave
不冒泡mouseover
與mouseenter
的區別也是mouseenter
不冒泡
MouseEvent
事件屬性:MouseEvent
事件順序:好比:
1.從元素A上方移過期
mousemove -> mouseover(A) -> mouseenter(A) -> mousemove(A)[不少個] -> mouseout(A) -> mouseleave(A)
2.點擊元素
mousedown -> [mousemove] -> mouseup -> click
需求:按下鼠標並移動時開始拖拽div,鬆開鼠標時中止拖拽div。mousedown -> mousemove -> mouseup
FocusEvent
blur
元素失去焦點時focus
元素得到焦點時focusin
元素即將得到焦點時focusout
元素將要失去焦點時
屬性:
relatedTarget
做用:當一個元素失去焦點時,另一個元素就要得到焦點。在blur
失去焦點事件中,得到焦點的元素就是這個relatedTarget
;在focus
得到焦點事件中,失去焦點的元素就是這個relatedTarget
。
InputEvent
KeyBoardEvent
鍵盤事件
key
按下了什麼鍵code
按下了什麼鍵需求:一個列表,點擊哪一行,這一行背景就變灰色,其他全是白色。
問題變爲:想要給一個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
var xhr = new XMLHttpRequest();
xhr.open('get', '1.txt', true);
xhr.setRequestHeader(header, value);
eg:xhr.setRequestHeader("content-type", "application/x-www-form-urlencoded" );
xhr.send([data = null]);
data
能夠是string
類型,也能夠是form-data
類型
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
。
屬性:
除了Name
和Value
以外,還有Domain
Path
瀏覽器會話時間:Expires
(時間戳)/Max-Age
(最長時間)
對cookie
進行增刪改查:
document.cookie
屬性看起來像是一個普通的文本字符串,其實它不是。
因此,很神奇的一點是:添加新的cookie只須要document.cookie = "newKey=newValue";
就能夠了,不須要document.cookie += ...
,以前的cookie
不會被覆蓋。
還有一點是:即便在 document.cookie
中寫入一個完整的 cookie
字符串, 當從新讀取該 cookie
信息時,cookie
信息是以名/值對的形式展現的。
刪除cookie
:將它的max-age
屬性設置爲0
就能夠刪除了。
缺陷:流量代價,安全性問題,大小限制。
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>
控制播放的方法和屬性:
查詢媒體狀態:
不建議用css指定寬高,直接在<canvas>
標籤中指定寬和高。
<canvas id="tutorial" width=320 height=240><</canvas>
怎樣獲取canvas的渲染上下文對象?
經過getContext("2d")
方法:
var canvas = document.getElementById("tutorial"); var context = canvas.getContext("2d");
基本繪圖步驟:
地球繞着太陽轉實例代碼:
BOM是表明瀏覽器窗口對象的一組API
Screen,navigator,location,history對話框,窗體互操做,load,beforeunload,scroll,resize等事件
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
判斷當前運行在什麼設備上。
protocol + host(hostname + port) + pathname + search + hash
window.location.href
表示當前頁面完整路徑,也能夠經過修改這個屬性讓瀏覽器跳轉。
方法:
window.location.assign(url)
跳轉頁面,記錄歷史。window.location.replace(url)
跳轉頁面,不記錄歷史。window.location.reload()
重載當前頁面。
屬性:length
方法:
back(n)
//傳入正整數,後退n步forward(n)
//傳入負整數,前進n步go(n)
//傳入整數,正數前進,負數倒退
屬性:
availHeight
availWidth
加了avail的是可用的屏幕屬性,沒加的是顯示器的屬性。
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
時就檢測出沒有填寫的表單並給用戶以提示。
form
的屬性
name
屬性用處是能夠直接拿到form節點元素:var pizzaForm = document.forms.pizza;
form
的接口reset()
可重置元素:input
,keygen
,output
,select
,textarea
觸發表單reset事件,阻止該事件的默認行爲可取消重置。
能夠用於刪除文件選擇器<input type="file">
中已選擇的文件喲 ʅ(´◔౪◔)ʃ
select
的屬性和方法
方法:
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
級聯下拉選擇器知識點:
主要代碼:
//向列表中填充數據 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); })
可驗證元素:button input select textarea
willValidite
可用於判斷元素是否會被驗證checkValidity()
驗證某個元素validity
存儲驗證結果,錯誤信息等validationMessage
驗證信息setCustomValidity(message)
設置自定義的異常顯示信息自定義異常:
若是不須要驗證,就在<form>
上添加一個 novalidate
屬性,就禁止了該表單下全部的驗證。
submit()
方法能夠手動提交onsubmit
事件綁定的方法中,能夠經過阻止默認事件觸發來阻止表單提交刷新頁面
驗證手機號能夠在標籤中寫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(專門的數據綁定相關的庫)去完成: