一召耘、Web API介紹
1.1 API的概念
API(Application Programming Interface,應(yīng)用程序編程接口)是一些預(yù)先定義的函數(shù)罪针,目的是提供應(yīng)用程序與開發(fā)人員基于某軟件或硬件得以訪問一組例程的能力员舵,而又無需訪問源碼棒仍,無需理解其內(nèi)部工作機(jī)制細(xì)節(jié),只需直接調(diào)用使用即可抡蛙。
舉例解釋什么是API护昧。
例如,? C語言中有一個(gè)函數(shù) fopen()可以打開硬盤上的文件粗截,這個(gè)函數(shù)對(duì)于我們來說惋耙,就是一個(gè)C語言提供的打開文件的工具。
? javascript中有一個(gè)函數(shù)alert()可以在頁面彈一個(gè)提示框慈格,這個(gè)函數(shù)就是js提供的一個(gè)彈框工具怠晴。
這些工具(函數(shù))由編程語言提供,內(nèi)部的實(shí)現(xiàn)已經(jīng)封裝好了浴捆,我們只要學(xué)會(huì)靈活的使用這些工具即可蒜田。
1.2 Web API的概念
? Web API 是瀏覽器提供的一套操作瀏覽器功能和頁面元素的 API ( BOM 和 DOM )。
? 現(xiàn)階段我們主要針對(duì)于瀏覽器講解常用的 API , 主要針對(duì)瀏覽器做交互效果选泻。比如我們想要瀏覽器彈出一個(gè)警示框冲粤, 直接使用 alert(‘彈出’)
? MDN 詳細(xì) API : https://developer.mozilla.org/zh-CN/docs/Web/API
? 因?yàn)?Web API 很多,所以我們將這個(gè)階段稱為 Web APIs页眯。
? 此處的 Web API 特指瀏覽器提供的一系列API(很多函數(shù)或?qū)ο蠓椒?梯捕,即操作網(wǎng)頁的一系列工具。例如:操作html標(biāo)簽窝撵、操作頁面地址的方法傀顾。
1.3 API 和 Web API 總結(jié)
API 是為我們程序員提供的一個(gè)接口,幫助我們實(shí)現(xiàn)某種功能碌奉,我們會(huì)使用就可以了短曾,不必糾結(jié)內(nèi)部如何實(shí)現(xiàn)
Web API 主要是針對(duì)于瀏覽器提供的接口,主要針對(duì)于瀏覽器做交互效果赐劣。
Web API 一般都有輸入和輸出(函數(shù)的傳參和返回值)嫉拐,Web API 很多都是方法(函數(shù))
學(xué)習(xí) Web API 可以結(jié)合前面學(xué)習(xí)內(nèi)置對(duì)象方法的思路學(xué)習(xí)
二、DOM 介紹
2.1 什么是DOM
? 文檔對(duì)象模型(Document Object Model魁兼,簡稱DOM)秉馏,是 W3C 組織推薦的處理可擴(kuò)展標(biāo)記語言(html或者xhtml)的標(biāo)準(zhǔn)編程接口换吧。
? W3C 已經(jīng)定義了一系列的 DOM 接口钉汗,通過這些 DOM 接口可以改變網(wǎng)頁的內(nèi)容笼吟、結(jié)構(gòu)和樣式。
DOM是W3C組織制定的一套處理 html和xml文檔的規(guī)范,所有的瀏覽器都遵循了這套標(biāo)準(zhǔn)。
2.2 DOM樹
DOM樹 又稱為文檔樹模型,把文檔映射成樹形結(jié)構(gòu)挺身,通過節(jié)點(diǎn)對(duì)象對(duì)其處理,處理的結(jié)果可以加入到當(dāng)前的頁面锌仅。
- 文檔:一個(gè)頁面就是一個(gè)文檔章钾,DOM中使用document表示
- 節(jié)點(diǎn):網(wǎng)頁中的所有內(nèi)容,在文檔樹中都是節(jié)點(diǎn)(標(biāo)簽热芹、屬性贱傀、文本、注釋等)伊脓,使用node表示
- 標(biāo)簽節(jié)點(diǎn):網(wǎng)頁中的所有標(biāo)簽府寒,通常稱為元素節(jié)點(diǎn),又簡稱為“元素”报腔,使用element表示
DOM把以上內(nèi)容都看作是對(duì)象
三株搔、獲取元素
為什么要獲取頁面元素?
例如:我們想要操作頁面上的某部分(顯示/隱藏纯蛾,動(dòng)畫)纤房,需要先獲取到該部分對(duì)應(yīng)的元素,再對(duì)其進(jìn)行操作翻诉。
3.1 根據(jù)ID獲取
語法:document.getElementById(id)
作用:根據(jù)ID獲取元素對(duì)象
參數(shù):id值炮姨,區(qū)分大小寫的字符串
返回值:元素對(duì)象 或 null
案例代碼
<body>
<div id="time">2019-9-9</div>
<script>
// 因?yàn)槲覀兾臋n頁面從上往下加載,所以先得有標(biāo)簽 所以我們script寫到標(biāo)簽的下面
var timer = document.getElementById('time');
console.log(timer);//<div id="time">2019-9-9</div>
console.log(typeof timer);//object
// console.dir 打印我們返回的元素對(duì)象 更好的查看里面的屬性和方法
console.dir(timer);//div#time
</script>
</body>
3.2 根據(jù)標(biāo)簽名獲取元素
語法:document.getElementsByTagName('標(biāo)簽名')
或者 element.getElementsByTagName('標(biāo)簽名')
作用:根據(jù)標(biāo)簽名獲取元素對(duì)象
參數(shù):標(biāo)簽名
返回值:元素對(duì)象集合(偽數(shù)組碰煌,數(shù)組元素是元素對(duì)象)
案例代碼
<body>
<ul>
<li>知否知否舒岸,應(yīng)是等你好久11</li>
<li>知否知否,應(yīng)是等你好久22</li>
<li>知否知否芦圾,應(yīng)是等你好久33</li>
<li>知否知否蛾派,應(yīng)是等你好久44</li>
<li>知否知否,應(yīng)是等你好久55</li>
</ul>
<ul id="nav">
<li>生僻字</li>
<li>生僻字</li>
<li>生僻字</li>
<li>生僻字</li>
<li>生僻字</li>
</ul>
<script>
// 1.返回的是 獲取過來元素對(duì)象的集合 以偽數(shù)組的形式存儲(chǔ)的
var lis = document.getElementsByTagName('li');
console.log(lis);
console.log(lis[0]);//<li>知否知否个少,應(yīng)是等你好久11</li>
// 2. 我們想要依次打印里面的元素對(duì)象我們可以采取遍歷的方式
for (var i = 0; i < lis.length; i++) {
console.log(lis[i]);
}
// 3. element.getElementsByTagName() 可以得到這個(gè)元素里面的某些標(biāo)簽
var nav = document.getElementById('nav'); // 這個(gè)獲得nav 元素
var navLis = nav.getElementsByTagName('li');
console.log(navLis);
</script>
</body>
注意:1.因?yàn)榈玫降氖且粋€(gè)對(duì)象的集合碍脏,我們想要操作里面的元素就需要遍歷;2.得到的元素是動(dòng)態(tài)的稍算。
注意:getElementsByTagName()獲取到是動(dòng)態(tài)集合,即:當(dāng)頁面增加了標(biāo)簽役拴,這個(gè)集合中也就增加了元素糊探。
3.3 H5新增獲取元素方式
-
document.getElementsByClassName('類名')
根據(jù)類名返回元素對(duì)象集合 -
document.querySelector('選擇器')
根據(jù)指定選擇器返回第一個(gè)元素對(duì)象 -
document.querySelectorAll('選擇器')
根據(jù)指定選擇器返回元素對(duì)象集合
案例代碼
<body>
<div class="box">盒子1</div>
<div class="box">盒子2</div>
<div id="nav">
<ul>
<li>首頁</li>
<li>產(chǎn)品</li>
</ul>
</div>
<script>
// 1. getElementsByClassName 根據(jù)類名獲得某些元素集合
var boxs = document.getElementsByClassName('box');
console.log(boxs);
// 2. querySelector 返回指定選擇器的第一個(gè)元素對(duì)象 切記 里面的選擇器需要加符號(hào) .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()返回指定選擇器的所有元素對(duì)象集合
var allBox = document.querySelectorAll('.box');
console.log(allBox);
var lis = document.querySelectorAll('li');
console.log(lis);
</script>
</body>
3.4 獲取特殊元素(body,html)
document.body
返回body元素對(duì)象
document.documentElement
返回html元素對(duì)象
四、事件基礎(chǔ)
4.1 事件概述
JavaScript 使我們有能力創(chuàng)建動(dòng)態(tài)頁面科平,而事件是可以被 JavaScript 偵測(cè)到的行為褥紫。
簡單理解: 觸發(fā)--- 響應(yīng)機(jī)制。
網(wǎng)頁中的每個(gè)元素都可以產(chǎn)生某些可以觸發(fā) JavaScript 的事件瞪慧,例如髓考,我們可以在用戶點(diǎn)擊某按鈕時(shí)產(chǎn)生一個(gè)事件,然后去執(zhí)行某些操作弃酌。
4.2 事件三要素
- 事件源(誰):觸發(fā)事件的元素
- 事件類型(什么事件): 例如 click 點(diǎn)擊事件
- 事件處理程序(做啥):事件觸發(fā)后要執(zhí)行的代碼(函數(shù)形式)氨菇,事件處理函數(shù)
案例代碼
<body>
<button id="btn">唐伯虎</button>
<script>
// 點(diǎn)擊一個(gè)按鈕,彈出對(duì)話框
// 1. 事件是有三部分組成 事件源 事件類型 事件處理程序 我們也稱為事件三要素
//(1) 事件源 事件被觸發(fā)的對(duì)象 誰 按鈕
var btn = document.getElementById('btn');
//(2) 事件類型 如何觸發(fā) 什么事件 比如鼠標(biāo)點(diǎn)擊(onclick) 還是鼠標(biāo)經(jīng)過 還是鍵盤按下
//(3) 事件處理程序 通過一個(gè)函數(shù)賦值的方式 完成
btn.onclick = function() {
alert('點(diǎn)秋香');
}
</script>
</body>
4.3 執(zhí)行事件的步驟
- 獲取事件源
- 注冊(cè)事件(綁定事件)
- 添加事件處理程序(采取函數(shù)賦值形式)
案例代碼
<body>
<div>123</div>
<script>
// 執(zhí)行事件步驟
// 點(diǎn)擊div 控制臺(tái)輸出 我被選中了
// 1. 獲取事件源
var div = document.querySelector('div');
// 2.綁定事件 注冊(cè)事件
// div.onclick
// 3.添加事件處理程序
div.onclick = function() {
console.log('我被選中了');
}
</script>
</body>
4.4 常見的鼠標(biāo)事件
五妓湘、操作元素
? JavaScript的 DOM 操作可以改變網(wǎng)頁內(nèi)容查蓉、結(jié)構(gòu)和樣式,我們可以利用 DOM 操作元素來改變?cè)乩锩娴膬?nèi)容榜贴、屬性等豌研。(注意:這些操作都是通過元素對(duì)象的屬性實(shí)現(xiàn)的)
5.1 改變?cè)貎?nèi)容(獲取或設(shè)置)
element.innerText
從起始位置到終止位置的內(nèi)容,它去除html標(biāo)簽唬党,同時(shí)空格和換行也會(huì)去掉
element.innerHTML
起始位置到終止位置的全部內(nèi)容鹃共,包括html標(biāo)簽,同時(shí)保留空格和換行
innerText改變?cè)貎?nèi)容
<body>
<button>顯示當(dāng)前系統(tǒng)時(shí)間</button>
<div>某個(gè)時(shí)間</div>
<p>1123</p>
<script>
// 當(dāng)我們點(diǎn)擊了按鈕驶拱, div里面的文字會(huì)發(fā)生變化
// 1. 獲取元素
var btn = document.querySelector('button');
var div = document.querySelector('div');
// 2.注冊(cè)事件
btn.onclick = function() {
// div.innerText = '2019-6-6';
div.innerHTML = getDate();
}
function getDate() {
var date = new Date();
// 我們寫一個(gè) 2019年 5月 1日 星期三
var year = date.getFullYear();
var month = date.getMonth() + 1;
var dates = date.getDate();
var arr = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
var day = date.getDay();
return '今天是:' + year + '年' + month + '月' + dates + '日 ' + arr[day];
}
</script>
</body>
innerText和innerHTML的區(qū)別
- 獲取內(nèi)容時(shí)的區(qū)別:
? innerText只接收文本霜浴,但原本的格式會(huì)去除(空格和換行),而innerHTML會(huì)保留空格和換行
- 設(shè)置內(nèi)容時(shí)的區(qū)別:
? innerText不會(huì)識(shí)別html屯烦,元素里面的標(biāo)簽都不接收都會(huì)被忽略坷随;而innerHTML會(huì)識(shí)別,一般innerHTML使用較多
案例代碼
<body>
<div></div>
<p>
我是文字
<span>123</span>
</p>
<script>
// innerText 和 innerHTML的區(qū)別
// 1. innerText 不識(shí)別html標(biāo)簽 非標(biāo)準(zhǔn) 去除空格和換行
var div = document.querySelector('div');
// div.innerText = '<strong>今天是:</strong> 2019';
// 2. innerHTML 識(shí)別html標(biāo)簽 W3C標(biāo)準(zhǔn) 保留空格和換行的
div.innerHTML = '<strong>今天是:</strong> 2019';
// 這兩個(gè)屬性是可讀寫的 可以獲取元素里面的內(nèi)容
var p = document.querySelector('p');
console.log(p.innerText);
console.log(p.innerHTML);
</script>
</body>
5.2 常用元素的屬性操作
-
innerText innerHTML
改變?cè)貎?nèi)容 src href
id alt title
獲取屬性的值
元素對(duì)象.屬性名
設(shè)置屬性的值
元素對(duì)象.屬性名 = 值
案例代碼
<body>
<button id="ldh">劉德華</button>
<button id="zxy">張學(xué)友</button> <br>
<img src="images/ldh.jpg" alt="" title="劉德華">
<script>
// 修改元素屬性 src
// 1. 獲取元素
var ldh = document.getElementById('ldh');
var zxy = document.getElementById('zxy');
var img = document.querySelector('img');
// 2. 注冊(cè)事件 處理程序
zxy.onclick = function() {
img.src = 'images/zxy.jpg';
img.title = '張學(xué)友思密達(dá)';
}
ldh.onclick = function() {
img.src = 'images/ldh.jpg';
img.title = '劉德華';
}
</script>
</body>
5.3 表單元素的屬性操作
利用DOM可以操作如下表單元素的屬性
type value checked selected disabled
獲取屬性的值
元素對(duì)象.屬性名
設(shè)置屬性的值
元素對(duì)象.屬性名 = 值
表單元素中有一些屬性如:disabled驻龟、checked温眉、selected,元素對(duì)象的這些屬性的值是布爾型翁狐。
案例代碼
<body>
<button>按鈕</button>
<input type="text" value="輸入內(nèi)容">
<script>
// 1. 獲取元素
var btn = document.querySelector('button');
var input = document.querySelector('input');
// 2. 注冊(cè)事件 處理程序
btn.onclick = function() {
// 表單里面的值 文字內(nèi)容是通過 value 來修改的
input.value = '被點(diǎn)擊了';
// 如果想要某個(gè)表單被禁用 不能再點(diǎn)擊 disabled 我們想要這個(gè)按鈕 button禁用
// btn.disabled = true;
this.disabled = true;
// this 指向的是事件函數(shù)的調(diào)用者 btn
}
</script>
</body>
5.4 案例:仿京東顯示密碼
5.5 樣式屬性操作
我們可以通過 JS 修改元素的大小类溢、顏色、位置等樣式露懒。
常用方式
-
element.style
行內(nèi)樣式操作 -
element.className
類名樣式操作
方式1:通過操作style屬性
元素對(duì)象的style屬性也是一個(gè)對(duì)象
元素對(duì)象.style.樣式屬性 = 值;
style.樣式采取駝峰命名法闯冷,如fontSize
<body>
<div></div>
<script>
// 1. 獲取元素
var div = document.querySelector('div');
// 2. 注冊(cè)事件 處理程序
div.onclick = function() {
// div.style里面的屬性 采取駝峰命名法
this.style.backgroundColor = 'purple';
this.style.width = '250px';
}
</script>
</body>
案例:循環(huán)精靈圖背景
案例:顯示隱藏文本框內(nèi)容
方式2:通過操作className屬性
元素對(duì)象.className = 值;
因?yàn)閏lass是關(guān)鍵字,所有使用className懈词。
會(huì)直接更改元素的類名蛇耀,覆蓋原先的類名,要保留原先的坎弯,可以
el.className='原來類名 新類名'
案例代碼
<body>
<div class="first">文本</div>
<script>
// 1. 使用 element.style 獲得修改元素樣式 如果樣式比較少 或者 功能簡單的情況下使用
var test = document.querySelector('div');
test.onclick = function() {
// this.style.backgroundColor = 'purple';
// this.style.color = '#fff';
// this.style.fontSize = '25px';
// this.style.marginTop = '100px';
// 2. 我們可以通過 修改元素的className更改元素的樣式 適合于樣式較多或者功能復(fù)雜的情況
// 3. 如果想要保留原先的類名纺涤,我們可以這么做 多類名選擇器
// this.className = 'change';
this.className = 'first change';
}
</script>
</body>
案例:密碼框格式提示錯(cuò)誤信息
六译暂、今日總結(jié)
七、排他操作
7.1 排他思想
如果有同一組元素撩炊,我們想要某一個(gè)元素實(shí)現(xiàn)某種樣式外永, 需要用到循環(huán)的排他思想算法:
所有元素全部清除樣式(干掉其他人)
給當(dāng)前元素設(shè)置樣式 (留下我自己)
注意順序不能顛倒,首先干掉其他人拧咳,再設(shè)置自己
<button>按鈕1</button>
<button>按鈕2</button>
<button>按鈕3</button>
<button>按鈕4</button>
<button>按鈕5</button>
<script>
// 1. 獲取所有按鈕元素
var btns = document.getElementsByTagName('button');
// btns得到的是偽數(shù)組 里面的每一個(gè)元素 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) 然后才讓當(dāng)前的元素背景顏色為pink 留下我自己
this.style.backgroundColor = 'pink';
}
}
</script>
7.2 案例:百度換膚
<ul class="baidu">
<li><img src="images/1.jpg"></li>
<li><img src="images/2.jpg"></li>
<li><img src="images/3.jpg"></li>
<li><img src="images/4.jpg"></li>
</ul>
<script>
// 1. 獲取元素
var imgs = document.querySelector('.baidu').querySelectorAll('img');
// console.log(imgs);
// 2. 循環(huán)注冊(cè)事件
for (var i = 0; i < imgs.length; i++) {
imgs[i].onclick = function() {
// this.src 就是我們點(diǎn)擊圖片的路徑 images/2.jpg
// console.log(this.src);
// 把這個(gè)路徑 this.src 給body 就可以了
document.body.style.backgroundImage = 'url(' + this.src + ')';
}
}
</script>
7.3 案例:表格隔行變色
// 1.獲取元素 獲取的是 tbody 里面所有的行
var trs = document.querySelector('tbody').querySelectorAll('tr');
// 2. 利用循環(huán)綁定注冊(cè)事件
for (var i = 0; i < trs.length; i++) {
// 3. 鼠標(biāo)經(jīng)過事件 onmouseover
trs[i].onmouseover = function() {
// console.log(11);
this.className = 'bg';
}
// 4. 鼠標(biāo)離開事件 onmouseout
trs[i].onmouseout = function() {
this.className = '';
}
}
7.4 案例:全選和取消全選
// 1. 全選和取消全選做法: 讓下面所有復(fù)選框的checked屬性(選中狀態(tài)) 跟隨 全選按鈕即可
// 獲取元素
var j_cbAll = document.getElementById('j_cbAll');
var j_tbs = document.getElementById('j_tb').getElementsByTagName('input');
// 全選按鈕注冊(cè)事件
j_cbAll.onclick = function() {
// this.checked 當(dāng)前復(fù)選框的選中狀態(tài)
console.log(this.checked);
for (var i = 0; i < j_tbs.length; i++) {
j_tbs[i].checked = this.checked;
}
}
// 給所有的子復(fù)選框注冊(cè)單擊事件
for (var i = 0; i < j_tbs.length; i++) {
j_tbs[i].onclick = function() {
// flag 控制全選按鈕是否選中
var flag = true;
// 每次點(diǎn)擊下面的復(fù)選框都要循環(huán)檢查者4個(gè)小按鈕是否全被選中
for (var i = 0; i < j_tbs.length; i++) {
if (!j_tbs[i].checked) {
flag = false;
break;
}
}
// 設(shè)置全選按鈕的狀態(tài)
j_cbAll.checked = flag;
}
}
八伯顶、自定義屬性操作
8.1 獲取屬性值
element.屬性
獲取內(nèi)置屬性值(元素本身自帶的屬性)
element.getAttribute('屬性')
主要獲取自定義屬性(標(biāo)準(zhǔn))和我們程序員自定義的屬性
<div id="demo" index="1" class="nav"></div>
<script>
var div = document.querySelector('div');
// 1. 獲取元素的屬性值
// (1) element.屬性
console.log(div.id);
// (2) element.getAttribute('屬性') get得到獲取 attribute 屬性的意思 我們程序員自己添加的屬性我們稱為自定義屬性 index
console.log(div.getAttribute('id'));
console.log(div.getAttribute('index'));
</script>
8.2 設(shè)置屬性值
element.屬性='值'
設(shè)置內(nèi)置屬性
element.setAttribute('屬性','值')
主要設(shè)置自定義的屬性(標(biāo)準(zhǔn))
// 2. 設(shè)置元素屬性值
// (1) element.屬性= '值'
div.id = 'test';
div.className = 'navs';
// (2) element.setAttribute('屬性', '值'); 主要針對(duì)于自定義屬性
div.setAttribute('index', 2);
div.setAttribute('class', 'footer'); // class 特殊 這里面寫的就是
8.3 移出屬性
element.removeAttribute('屬性')
// class 不是className
// 3 移除屬性 removeAttribute(屬性)
div.removeAttribute('index');
8.4 案例:tab欄
// 獲取元素
var tab_list = document.querySelector('.tab_list');
var lis = tab_list.querySelectorAll('li');
var items = document.querySelectorAll('.item');
// for循環(huán),給選項(xiàng)卡綁定點(diǎn)擊事件
for (var i = 0; i < lis.length; i++) {
// 開始給5個(gè)小li 設(shè)置索引號(hào)
lis[i].setAttribute('index', i);
lis[i].onclick = function() {
// 1. 上的模塊選項(xiàng)卡骆膝,當(dāng)前這一個(gè)底色會(huì)是紅色祭衩,其余不變(排他思想)
// 干掉所有人 其余的li清除 class 這個(gè)類
for (var i = 0; i < lis.length; i++) {
lis[i].className = '';
}
// 留下我自己
this.className = 'current';
// 2. 下面的顯示內(nèi)容模塊
var index = this.getAttribute('index');
console.log(index);
// 干掉所有人 讓其余的item 這些div 隱藏
for (var i = 0; i < items.length; i++) {
items[i].style.display = 'none';
}
// 留下我自己 讓對(duì)應(yīng)的item 顯示出來
items[index].style.display = 'block';
}
}
8.5 H5自定義屬性
自定義屬性目的:是為了保存并使用數(shù)據(jù)。有些數(shù)據(jù)可以保存到頁面中而不用保存到數(shù)據(jù)庫中谭网。
自定義屬性獲取是通過getAttribute(‘屬性’) 獲取汪厨。
但是有些自定義屬性很容易引起歧義,不容易判斷是元素的內(nèi)置屬性還是自定義屬性愉择。
H5給我們新增了自定義屬性:
.H5規(guī)定自定義屬性data-開頭劫乱,可以直接在元素內(nèi)設(shè)置:<div data-index="1"></div>
或element.setAttribute('data-index',2)
;
兼容性獲茸短椤:element.getAttribute('data-index')
以及H5新增elemet.dataset.index
element.dataset['index']
ie11才開始支持
<div getTime="20" data-index="2" data-list-name="andy"></div>
<script>
var div = document.querySelector('div');
// console.log(div.getTime);
console.log(div.getAttribute('getTime'));
div.setAttribute('data-time', 20);
console.log(div.getAttribute('data-index'));
console.log(div.getAttribute('data-list-name'));
// h5新增的獲取自定義屬性的方法 它只能獲取data-開頭的
// dataset 是一個(gè)集合里面存放了所有以data開頭的自定義屬性
console.log(div.dataset);
console.log(div.dataset.index);
console.log(div.dataset['index']);
// 如果自定義屬性里面有多個(gè)-鏈接的單詞衷戈,我們獲取的時(shí)候采取 駝峰命名法
console.log(div.dataset.listName);
console.log(div.dataset['listName']);
</script>
九、節(jié)點(diǎn)操作
9.1 節(jié)點(diǎn)概述
網(wǎng)頁中的所有內(nèi)容都是節(jié)點(diǎn)(標(biāo)簽层坠、屬性殖妇、文本、注釋等)破花,在DOM 中谦趣,節(jié)點(diǎn)使用 node 來表示。
?HTML DOM 樹中的所有節(jié)點(diǎn)均可通過 JavaScript 進(jìn)行訪問座每,所有 HTML 元素(節(jié)點(diǎn))均可被修改前鹅,也可以創(chuàng)建或刪除。
一般地峭梳,節(jié)點(diǎn)至少擁有nodeType(節(jié)點(diǎn)類型)舰绘、nodeName(節(jié)點(diǎn)名稱)和nodeValue(節(jié)點(diǎn)值)這三個(gè)基本屬性。
- 元素節(jié)點(diǎn) nodeType為1
- 屬性節(jié)點(diǎn) nodeType為2
- 文本節(jié)點(diǎn) nodeType為3(文本節(jié)點(diǎn)包含文字 空格和換行等)
9.2 節(jié)點(diǎn)層級(jí)
? 利用 DOM 樹可以把節(jié)點(diǎn)劃分為不同的層級(jí)關(guān)系葱椭,常見的是父子兄層級(jí)關(guān)系捂寿。
9.3 父級(jí)節(jié)點(diǎn)
node.parentNode
可以返回某節(jié)點(diǎn)的父節(jié)點(diǎn),是離它最近的一個(gè)父節(jié)點(diǎn)(親爸爸)孵运,如果沒有父節(jié)點(diǎn)則返回null
<div class="demo">
<div class="box">
<span class="erweima">×</span>
</div>
</div>
<script>
// 1. 父節(jié)點(diǎn) parentNode
var erweima = document.querySelector('.erweima');
// var box = document.querySelector('.box');
// 得到的是離元素最近的父級(jí)節(jié)點(diǎn)(親爸爸) 如果找不到父節(jié)點(diǎn)就返回為 null
console.log(erweima.parentNode);
</script>
9.4 子節(jié)點(diǎn)
所有子節(jié)點(diǎn)
parentNode.childNodes
(標(biāo)準(zhǔn))秦陋,返回包含指定節(jié)點(diǎn)的子節(jié)點(diǎn)的集合(即時(shí)更新),包含元素節(jié)點(diǎn)和文本節(jié)點(diǎn)治笨。一般不提倡使用踱侣。
子元素節(jié)點(diǎn)
parentNode.children
(非標(biāo)準(zhǔn))粪小,是一個(gè)只讀屬性,返回所有的元素子節(jié)點(diǎn)(重點(diǎn)掌握)
<ul>
<li>我是li</li>
<li>我是li</li>
<li>我是li</li>
<li>我是li</li>
</ul>
<script>
// DOM 提供的方法(API)獲取
var ul = document.querySelector('ul');
var lis = ul.querySelectorAll('li');
// 1. 子節(jié)點(diǎn) childNodes 所有的子節(jié)點(diǎn) 包含 元素節(jié)點(diǎn) 文本節(jié)點(diǎn)等等
console.log(ul.childNodes);
console.log(ul.childNodes[0].nodeType);
console.log(ul.childNodes[1].nodeType);
// 2. children 獲取所有的子元素節(jié)點(diǎn) 也是我們實(shí)際開發(fā)常用的
console.log(ul.children);
</script>
第1個(gè)子節(jié)點(diǎn)
parentNode.firstChild
最后1個(gè)子節(jié)點(diǎn)
parentNode.lastChild
第1個(gè)子元素節(jié)點(diǎn)
parentNode.firstElementChild
返回第一個(gè)子元素節(jié)點(diǎn)
最后1個(gè)子元素節(jié)點(diǎn)
parentNode.lastElementChild
返回最后一個(gè)子元素節(jié)點(diǎn)
后兩個(gè)方法ie9以上才支持
實(shí)際開發(fā)中抡句,firstChild 和 lastChild 包含其他節(jié)點(diǎn),操作不方便杠愧,而 firstElementChild 和 lastElementChild 又有兼容性問題待榔,那么我們?nèi)绾潍@取第一個(gè)子元素節(jié)點(diǎn)或最后一個(gè)子元素節(jié)點(diǎn)呢?
如果想要第一個(gè)子元素節(jié)點(diǎn)流济,可以使用parentNode.children[0]
如果想要最后一個(gè)子元素節(jié)點(diǎn)锐锣,可以使用parentNode.children[parentNode.children.length-1]
<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 第一個(gè)子節(jié)點(diǎn) 不管是文本節(jié)點(diǎn)還是元素節(jié)點(diǎn)
console.log(ol.firstChild);
console.log(ol.lastChild);
// 2. firstElementChild 返回第一個(gè)子元素節(jié)點(diǎn) ie9才支持
console.log(ol.firstElementChild);
console.log(ol.lastElementChild);
// 3. 實(shí)際開發(fā)的寫法 既沒有兼容性問題又返回第一個(gè)子元素
console.log(ol.children[0]);
console.log(ol.children[ol.children.length - 1]);
</script>
9.5 案例:新浪下拉菜單
// 1. 獲取元素
var nav = document.querySelector('.nav');
var lis = nav.children; // 得到4個(gè)小li
// 2.循環(huán)注冊(cè)事件
for (var i = 0; i < lis.length; i++) {
lis[i].onmouseover = function() {
this.children[1].style.display = 'block';
}
lis[i].onmouseout = function() {
this.children[1].style.display = 'none';
}
}
9.6 兄弟節(jié)點(diǎn)
下一個(gè)兄弟節(jié)點(diǎn)
node.nextSibling
返回當(dāng)前元素的下一個(gè)兄弟節(jié)點(diǎn),找不到返回null
上一個(gè)兄弟節(jié)點(diǎn)
node.nextSibling
返回當(dāng)前元素的上一個(gè)兄弟節(jié)點(diǎn)绳瘟,找不到返回null
<div>我是div</div>
<span>我是span</span>
<script>
var div = document.querySelector('div');
// 1.nextSibling 下一個(gè)兄弟節(jié)點(diǎn) 包含元素節(jié)點(diǎn)或者 文本節(jié)點(diǎn)等等
console.log(div.nextSibling);
console.log(div.previousSibling);
// 2. nextElementSibling 得到下一個(gè)兄弟元素節(jié)點(diǎn)
console.log(div.nextElementSibling);
console.log(div.previousElementSibling);
</script>
下一個(gè)兄弟元素節(jié)點(diǎn)(有兼容性問題)
node.nextElementSibling
返回當(dāng)前元素的下一個(gè)兄弟元素節(jié)點(diǎn)雕憔,找不到則返回null
上一個(gè)兄弟元素節(jié)點(diǎn)(有兼容性問題)
node.previousElementSibling
返回當(dāng)前元素的上一個(gè)兄弟元素節(jié)點(diǎn),找不到則返回null
nextElementSibling和previousElementSibling糖声,ie9以上才支持斤彼,解決方法:自己封裝一個(gè)兼容性函數(shù)
function getNextElementSibling(element) {
var el = element;
while (el = el.nextSibling) {
if (el.nodeType === 1) {
return el;
}
}
return null;
}
9.7 創(chuàng)建節(jié)點(diǎn)
document.createElement('tagName')
創(chuàng)建由tagName指定的HTML元素。因?yàn)檫@些元素原先不存在蘸泻,是根據(jù)需求動(dòng)態(tài)生成的琉苇,我們也稱為動(dòng)態(tài)創(chuàng)建元素節(jié)點(diǎn)。
9.8 添加節(jié)點(diǎn)
1.node.appendChild(child)
將一個(gè)節(jié)點(diǎn)添加到指定父節(jié)點(diǎn)的子節(jié)點(diǎn)列表末尾悦施,類似于css里面的after偽元素
2.node.insertBefore(child,指定元素)
將一個(gè)節(jié)點(diǎn)添加到父節(jié)點(diǎn)的指定子節(jié)點(diǎn)前面并扇,類似于css里面的before偽元素
<ul>
<li>123</li>
</ul>
<script>
// 1. 創(chuàng)建節(jié)點(diǎn)元素節(jié)點(diǎn)
var li = document.createElement('li');
// 2. 添加節(jié)點(diǎn) node.appendChild(child) node 父級(jí) child 是子級(jí) 后面追加元素
var ul = document.querySelector('ul');
ul.appendChild(li);
// 3. 添加節(jié)點(diǎn) node.insertBefore(child, 指定元素);
var lili = document.createElement('li');
ul.insertBefore(lili, ul.children[0]);
// 4. 我們想要頁面添加一個(gè)新的元素 : 1. 創(chuàng)建元素 2. 添加元素
</script>
9.9 案例:簡單版發(fā)布留言
<body>
<textarea name="" id=""></textarea>
<button>發(fā)布</button>
<ul>
</ul>
<script>
// 1. 獲取元素
var btn = document.querySelector('button');
var text = document.querySelector('textarea');
var ul = document.querySelector('ul');
// 2. 注冊(cè)事件
btn.onclick = function() {
if (text.value == '') {
alert('您沒有輸入內(nèi)容');
return false;
} else {
// console.log(text.value);
// (1) 創(chuàng)建元素
var li = document.createElement('li');
// 先有l(wèi)i 才能賦值
li.innerHTML = text.value;
// (2) 添加元素
// ul.appendChild(li);
ul.insertBefore(li, ul.children[0]);
}
}
</script>
</body>
9.10 刪除節(jié)點(diǎn)
node.removeChild(chil)
node.removeChild() 方法從 node節(jié)點(diǎn)中刪除一個(gè)子節(jié)點(diǎn),返回刪除的節(jié)點(diǎn)抡诞。
<button>刪除</button>
<ul>
<li>熊大</li>
<li>熊二</li>
<li>光頭強(qiáng)</li>
</ul>
<script>
// 1.獲取元素
var ul = document.querySelector('ul');
var btn = document.querySelector('button');
// 2. 刪除元素 node.removeChild(child)
// ul.removeChild(ul.children[0]);
// 3. 點(diǎn)擊按鈕依次刪除里面的孩子
btn.onclick = function() {
if (ul.children.length == 0) {
this.disabled = true;
} else {
ul.removeChild(ul.children[0]);
}
}
</script>
9.11 案例:刪除留言
<textarea name="" id=""></textarea>
<button>發(fā)布</button>
<ul>
</ul>
<script>
// 1. 獲取元素
var btn = document.querySelector('button');
var text = document.querySelector('textarea');
var ul = document.querySelector('ul');
// 2. 注冊(cè)事件
btn.onclick = function() {
if (text.value == '') {
alert('您沒有輸入內(nèi)容');
return false;
} else {
// console.log(text.value);
// (1) 創(chuàng)建元素
var li = document.createElement('li');
// 先有l(wèi)i 才能賦值
li.innerHTML = text.value + "<a href='javascript:;'>刪除</a>";
// (2) 添加元素
// ul.appendChild(li);
ul.insertBefore(li, ul.children[0]);
// (3) 刪除元素 刪除的是當(dāng)前鏈接的li 它的父親
var as = document.querySelectorAll('a');
for (var i = 0; i < as.length; i++) {
as[i].onclick = function() {
// 刪除的是 li 當(dāng)前a所在的li this.parentNode;
ul.removeChild(this.parentNode);
}
}
}
}
</script>
9.12 復(fù)制(克卵 )節(jié)點(diǎn)
node.cloneNode()
返回調(diào)用該方法的節(jié)點(diǎn)的一個(gè)副本,也稱為克隆節(jié)點(diǎn)/拷貝節(jié)點(diǎn)
括號(hào)為空或者里面是false是淺拷貝光坝,只復(fù)制標(biāo)簽不復(fù)制里面的內(nèi)容
括號(hào)為true是深拷貝取视,復(fù)制標(biāo)簽復(fù)制里面的內(nèi)容
<ul>
<li>1111</li>
<li>2</li>
<li>3</li>
</ul>
<script>
var ul = document.querySelector('ul');
// 1. node.cloneNode(); 括號(hào)為空或者里面是false 淺拷貝 只復(fù)制標(biāo)簽不復(fù)制里面的內(nèi)容
// 2. node.cloneNode(true); 括號(hào)為true 深拷貝 復(fù)制標(biāo)簽復(fù)制里面的內(nèi)容
var lili = ul.children[0].cloneNode(true);
ul.appendChild(lili);
</script>
9.13 案例:動(dòng)態(tài)生成表格
// 1.先去準(zhǔn)備好學(xué)生的數(shù)據(jù)
var datas = [{
name: '魏瓔珞',
subject: 'JavaScript',
score: 100
}, {
name: '弘歷',
subject: 'JavaScript',
score: 98
}, {
name: '傅恒',
subject: 'JavaScript',
score: 99
}, {
name: '明玉',
subject: 'JavaScript',
score: 88
}, {
name: '大豬蹄子',
subject: 'JavaScript',
score: 0
}];
// 2. 往tbody 里面創(chuàng)建行: 有幾個(gè)人(通過數(shù)組的長度)我們就創(chuàng)建幾行
var tbody = document.querySelector('tbody');
// 遍歷數(shù)組
for (var i = 0; i < datas.length; i++) {
// 1. 創(chuàng)建 tr行
var tr = document.createElement('tr');
tbody.appendChild(tr);
// 2. 行里面創(chuàng)建單元格td 單元格的數(shù)量取決于每個(gè)對(duì)象里面的屬性個(gè)數(shù)
// 使用for in遍歷學(xué)生對(duì)象
for (var k in datas[i]) {
// 創(chuàng)建單元格
var td = document.createElement('td');
// 把對(duì)象里面的屬性值 datas[i][k] 給 td
td.innerHTML = datas[i][k];
tr.appendChild(td);
}
// 3. 創(chuàng)建有刪除2個(gè)字的單元格
var td = document.createElement('td');
td.innerHTML = '<a href="javascript:;">刪除 </a>';
tr.appendChild(td);
}
// 4. 刪除操作 開始
var as = document.querySelectorAll('a');
for (var i = 0; i < as.length; i++) {
as[i].onclick = function() {
// 點(diǎn)擊a 刪除 當(dāng)前a 所在的行(鏈接的爸爸的爸爸) node.removeChild(child)
tbody.removeChild(this.parentNode.parentNode)
}
}
9.14 創(chuàng)建元素的三種方式
-
document.write()
直接將內(nèi)容寫入頁面的內(nèi)容流,但文檔流執(zhí)行完畢(整個(gè)頁面加載完)乔遮,再去使用它會(huì)導(dǎo)致頁面全部重繪扮超。它的功能是創(chuàng)建一個(gè)全新的頁面,原本寫在頁面上的元素全部不見蹋肮。 -
element.innerHTML
將內(nèi)容寫入某個(gè)DOM節(jié)點(diǎn)出刷,不會(huì)導(dǎo)致頁面重繪。創(chuàng)建多個(gè)元素時(shí)效率更高(不要大量拼接字符串坯辩,采取數(shù)組形式拼接)馁龟,缺點(diǎn)是結(jié)構(gòu)稍微復(fù)雜 -
document.createElement()
創(chuàng)建多個(gè)元素時(shí)效率稍低一點(diǎn),優(yōu)點(diǎn)是結(jié)構(gòu)更清晰
不同瀏覽器下漆魔,innerHTML效率要比createElement高
// 三種創(chuàng)建元素方式區(qū)別
// 1. document.write() 創(chuàng)建元素 如果頁面文檔流加載完畢坷檩,再調(diào)用這句話會(huì)導(dǎo)致頁面重繪
window.onload = function(){
document.write('<div>123</div>');
}
var btn = document.querySelector('button');
btn.onclick = function() {
document.write('<div>123</div>');
}
// 2. innerHTML 創(chuàng)建元素
var inner = document.querySelector('.inner');
for (var i = 0; i <= 100; i++) {
inner.innerHTML += '<a href="#">百度</a>'
}
var arr = [];
for (var i = 0; i <= 100; i++) {
arr.push('<a href="#">百度</a>');
}
inner.innerHTML = arr.join('');
// 3. document.createElement() 創(chuàng)建元素
var create = document.querySelector('.create');
for (var i = 0; i <= 100; i++) {
var a = document.createElement('a');
create.appendChild(a);
}
9.15 innerTHML和createElement效率對(duì)比
innerHTML字符串拼接方式(效率低)
<script>
function fn() {
var d1 = +new Date();
var str = '';
for (var i = 0; i < 1000; i++) {
document.body.innerHTML += '<div style="width:100px; height:2px; border:1px solid blue;"></div>';
}
var d2 = +new Date();
console.log(d2 - d1);
}
fn();
</script>
createElement方式(效率一般)
<script>
function fn() {
var d1 = +new Date();
for (var i = 0; i < 1000; i++) {
var div = document.createElement('div');
div.style.width = '100px';
div.style.height = '2px';
div.style.border = '1px solid red';
document.body.appendChild(div);
}
var d2 = +new Date();
console.log(d2 - d1);
}
fn();
</script>
innerHTML數(shù)組方式(效率高)
<script>
function fn() {
var d1 = +new Date();
var array = [];
for (var i = 0; i < 1000; i++) {
array.push('<div style="width:100px; height:2px; border:1px solid blue;"></div>');
}
document.body.innerHTML = array.join('');
var d2 = +new Date();
console.log(d2 - d1);
}
fn();
</script>
十却音、DOM的核心總結(jié)
關(guān)于dom操作,我們主要針對(duì)于元素的操作矢炼。主要有創(chuàng)建系瓢、增、刪句灌、改夷陋、查、屬性操作胰锌、事件操作骗绕。
10.1 創(chuàng)建
documen.write
innerHTML
createElement
10.2 增加
appendChild
insertBefore
10.3 刪
removeChild
10.4 改
主要修改dom的元素屬性,dom元素的內(nèi)容资昧、屬性酬土、表單的值等
- 元素屬性
src href title
- 普通元素內(nèi)容
innerHTML innerText
- 表單元素
value type disabled等
- 元素樣式
style className
10.5 查
主要獲取查詢dom的元素
- DOM提供的API方法
getElementById getElementByTagName
古老用法,不推薦 - H5提供的新方法
querySelector querySelectorAll
提倡 - 利用節(jié)點(diǎn)操作獲取元素
父parentNode 子children 兄previousElementSibling格带、nextElementSibling
提倡
10.6 屬性操作
主要針對(duì)于自定義屬性
-
setAttribute
設(shè)置dom的屬性值 -
getAttribute
得到dom的屬性值 -
removeAttribute
移除屬性
十一撤缴、事件高級(jí)
11.1 注冊(cè)事件(2種方式)
傳統(tǒng)注冊(cè)方式:
- 利用on開頭,如onclick
<button onclick="alert(1)"></button>
btn.onclick = function(){}
- 特點(diǎn):注冊(cè)事件的唯一性践惑,即同一個(gè)元素同一個(gè)事件只能設(shè)置一個(gè)處理函數(shù)腹泌,最后注冊(cè)的處理函數(shù)會(huì)覆蓋前面注冊(cè)的
監(jiān)聽注冊(cè)方式:
- w3c標(biāo)準(zhǔn) 推薦方式
- addEventListener()
- ie9前不支持,可以使用attachEvent()代替
- 特點(diǎn):即同一個(gè)元素同一個(gè)事件可以注冊(cè)多個(gè)監(jiān)聽器(處理函數(shù))
11.2 事件監(jiān)聽
addEventListener()事件監(jiān)聽(IE9以后支持)
eventTarget.addEventListener(type,listener[, useCapture])
eventTarget.addEventListener()方法將指定的監(jiān)聽器注冊(cè)到 eventTarget(目標(biāo)對(duì)象)上尔觉,當(dāng)該對(duì)象觸發(fā)指定的事件時(shí)凉袱,就會(huì)執(zhí)行事件處理函數(shù)。
該方法接收三個(gè)參數(shù):
-
type
:事件類型字符串侦铜,如click专甩、mouseover,這里不要帶on -
listener
:事件處理函數(shù)钉稍,事件發(fā)生時(shí)涤躲,會(huì)調(diào)用監(jiān)聽該函數(shù) -
useCapture
:可選參數(shù),是一個(gè)布爾值贡未,默認(rèn)false种樱。
attacheEvent()事件監(jiān)聽(僅IE678支持,其他瀏覽器均無效)
eventTarget.attachEvent(eventNameWithOn,callback)
? eventTarget.attachEvent()方法將指定的監(jiān)聽器注冊(cè)到 eventTarget(目標(biāo)對(duì)象) 上俊卤,當(dāng)該對(duì)象觸發(fā)指定的事件時(shí)嫩挤,指定的回調(diào)函數(shù)就會(huì)被執(zhí)行。
該方法接收兩個(gè)參數(shù):
-
eventNameWithOn
:事件類型字符串消恍,如click岂昭、mouseover,這里要帶on -
callback
:事件處理函數(shù)狠怨,當(dāng)目標(biāo)觸發(fā)事件時(shí)回調(diào)函數(shù)被調(diào)用 -
useCapture
:可選參數(shù)约啊,是一個(gè)布爾值邑遏,默認(rèn)false。
<button>傳統(tǒng)注冊(cè)事件</button>
<button>方法監(jiān)聽注冊(cè)事件</button>
<button>ie9 attachEvent</button>
<script>
var btns = document.querySelectorAll('button');
// 1. 傳統(tǒng)方式注冊(cè)事件
btns[0].onclick = function() {
alert('hi');
}
btns[0].onclick = function() {
alert('hao a u');
}
// 2. 事件偵聽注冊(cè)事件 addEventListener
// (1) 里面的事件類型是字符串 必定加引號(hào) 而且不帶on
// (2) 同一個(gè)元素 同一個(gè)事件可以添加多個(gè)偵聽器(事件處理程序)
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>
事件監(jiān)聽兼容性解決方案
封裝一個(gè)函數(shù)恰矩,函數(shù)中判斷瀏覽器的類型:
function addEventListener(element,eventName,fn){
//判斷當(dāng)前瀏覽器是否支持addEventListener方法
if(element.addEventListener){
element.addEventListener(eventName,fn);
}else if(element.attachEvent){
element.attachEvent('on'+eventName,fn);
}else{//相當(dāng)于element.onclick = fn
element['on'+eventName] = fn
}
}
11.3 刪除事件(解綁事件)
- 傳統(tǒng)注冊(cè)方式:
eventTarget.onclick = null
- 方法注冊(cè)監(jiān)聽注冊(cè)方式
eventTarget.removeEventLister(type,listener[,useCapture])
eventTarget.detachEvent(eventNameWithOn,callback)
<div>1</div>
<div>2</div>
<div>3</div>
<script>
var divs = document.querySelectorAll('div');
divs[0].onclick = function() {
alert(11);
// 1. 傳統(tǒng)方式刪除事件
divs[0].onclick = null;
}
// 2. removeEventListener 刪除事件
divs[1].addEventListener('click', fn) // 里面的fn 不需要調(diào)用加小括號(hào)
function fn() {
alert(22);
divs[1].removeEventListener('click', fn);
}
// 3. detachEvent
divs[2].attachEvent('onclick', fn1);
function fn1() {
alert(33);
divs[2].detachEvent('onclick', fn1);
}
</script>
**刪除事件兼容性解決方案 **
function removeEventListener(element,eventName,fn){
if(element.removeEventListener){
element.removeEventListener(eventName,fn);
}else if(element.detachEvent){
elment.detachEvent('on'+eventName,fn);
}else{
element['on'+eventName] = fn;
}
}
11.4 DOM事件流
html中的標(biāo)簽都是相互嵌套的记盒,我們可以將元素想象成一個(gè)盒子裝一個(gè)盒子,document是最外面的大盒子外傅。
當(dāng)你單擊一個(gè)div時(shí)孽鸡,同時(shí)你也單擊了div的父元素,甚至整個(gè)頁面栏豺。那么是先執(zhí)行父元素的單擊事件,還是先執(zhí)行div的單擊事件 豆胸?奥洼??
事件流描述的是從頁面中接收事件的順序
事件發(fā)生時(shí)會(huì)在元素節(jié)點(diǎn)之間按照特定的順序傳播晚胡,這個(gè)傳播過程即DOM事件流
比如:我們給頁面中的一個(gè)div注冊(cè)了單擊事件灵奖,當(dāng)你單擊了div時(shí),也就單擊了body估盘,單擊了html瓷患,單擊了document。
- 事件冒泡:IE最早提出遣妥,事件開始時(shí)由最具體的元素接收擅编,然后逐級(jí)向上傳播到DOM最頂層節(jié)點(diǎn)的過程
-
事件捕獲:網(wǎng)景最早提出,由DOM最頂層節(jié)點(diǎn)開始箫踩,然后逐級(jí)向下傳播到最具體的元素接收的過程爱态。
當(dāng)時(shí)的2大瀏覽器霸主誰也不服誰!
IE 提出從目標(biāo)元素開始境钟,然后一層一層向外接收事件并響應(yīng)锦担,也就是冒泡型事件流。
Netscape(網(wǎng)景公司)提出從最外層開始慨削,然后一層一層向內(nèi)接收事件并響應(yīng)洞渔,也就是捕獲型事件流。江湖紛爭缚态,武林盟主也腦殼疼4沤贰!猿规!
最終衷快,w3c 采用折中的方式,平息了戰(zhàn)火姨俩,制定了統(tǒng)一的標(biāo)準(zhǔn) —--— 先捕獲再冒泡蘸拔。
現(xiàn)代瀏覽器都遵循了此標(biāo)準(zhǔn)师郑,所以當(dāng)事件發(fā)生時(shí),會(huì)經(jīng)歷3個(gè)階段调窍。
DOM 事件流會(huì)經(jīng)歷3個(gè)階段:
捕獲階段
當(dāng)前目標(biāo)階段
冒泡階段
? 我們向水里面扔一塊石頭宝冕,首先它會(huì)有一個(gè)下降的過程,這個(gè)過程就可以理解為從最頂層向事件發(fā)生的最具體元素(目標(biāo)點(diǎn))的捕獲過程邓萨;之后會(huì)產(chǎn)生泡泡地梨,會(huì)在最低點(diǎn)( 最具體元素)之后漂浮到水面上,這個(gè)過程相當(dāng)于事件冒泡缔恳。
- JS代碼中只能執(zhí)行捕獲或者冒泡其中一個(gè)階段(二選一)
onclick
和attach
只能得到冒泡階段addEventListener(type,listener[,useCapture])
useCapture參數(shù)如果是true宝剖,表示在事件捕獲階段調(diào)用事件處理程序;如果是false(默認(rèn))歉甚,即表示在事件冒泡階段調(diào)用處理程序万细。- 實(shí)際開發(fā)中很少使用事件捕獲,更關(guān)注事件冒泡
- 有些事件沒有冒泡纸泄,比如
onblur赖钞、onfocus、onmouseenter聘裁、onmouseleave
事件冒泡
<div class="father">
<div class="son">son盒子</div>
</div>
<script>
// onclick 和 attachEvent(ie) 在冒泡階段觸發(fā)
// 冒泡階段 如果addEventListener 第三個(gè)參數(shù)是 false 或者 省略
// son -> father ->body -> html -> document
var son = document.querySelector('.son');
// 給son注冊(cè)單擊事件
son.addEventListener('click', function() {
alert('son');
}, false);
// 給father注冊(cè)單擊事件
var father = document.querySelector('.father');
father.addEventListener('click', function() {
alert('father');
}, false);
// 給document注冊(cè)單擊事件雪营,省略第3個(gè)參數(shù)
document.addEventListener('click', function() {
alert('document');
})
</script>
事件捕獲
<div class="father">
<div class="son">son盒子</div>
</div>
<script>
// 如果addEventListener() 第三個(gè)參數(shù)是 true 那么在捕獲階段觸發(fā)
// document -> html -> body -> father -> son
var son = document.querySelector('.son');
// 給son注冊(cè)單擊事件,第3個(gè)參數(shù)為true
son.addEventListener('click', function() {
alert('son');
}, true);
var father = document.querySelector('.father');
// 給father注冊(cè)單擊事件衡便,第3個(gè)參數(shù)為true
father.addEventListener('click', function() {
alert('father');
}, true);
// 給document注冊(cè)單擊事件献起,第3個(gè)參數(shù)為true
document.addEventListener('click', function() {
alert('document');
}, true)
</script>
11.5 事件對(duì)象
事件發(fā)生后,跟事件相關(guān)的一系列信息數(shù)據(jù)的集合都放到這個(gè)對(duì)象里面砰诵,這個(gè)對(duì)象就是事件對(duì)象征唬。代表事件的狀態(tài),比如鍵盤按鍵的狀態(tài)茁彭,鼠標(biāo)的位置总寒、誰綁定了這個(gè)事件等。它有很多屬性和方法理肺。
事件對(duì)象的使用
事件觸發(fā)發(fā)生時(shí)就會(huì)產(chǎn)生事件對(duì)象摄闸,并且系統(tǒng)會(huì)以實(shí)參的形式傳給事件處理函數(shù)。
所以妹萨,在事件處理函數(shù)中聲明1個(gè)形參用來接收事件對(duì)象年枕。
eventTarget.onclick = function(event) {
//這個(gè)event是事件對(duì)象,常寫成e或者evt
}
eventTarget.addEventListener('click',function(event) {
})
eventTarget.addEventListener('click',fn)
function fn(event) {}
事件對(duì)象的兼容性處理
事件對(duì)象本身的獲取存在兼容問題:
標(biāo)準(zhǔn)瀏覽器中是瀏覽器給方法傳遞的參數(shù)乎完,只需要定義形參 e 就可以獲取到熏兄。
在 IE6~8 中,瀏覽器不會(huì)給方法傳遞參數(shù),如果需要的話摩桶,需要到 window.event 中獲取查找桥状。
解決:e = e || window.event;
<div>123</div>
<script>
var div = document.querySelector('div');
div.onclick = function(e) {
// 事件對(duì)象
e = e || window.event;
console.log(e);
}
</script>
事件對(duì)象的屬性和方法
e.target 和 this 的區(qū)別
this 是事件綁定的元素(綁定這個(gè)事件處理函數(shù)的元素)。e.currentTarget非常相似硝清,但是有兼容問題辅斟,所以我們用this
e.target 是事件觸發(fā)的元素(返回的是我們點(diǎn)擊了哪個(gè)元素)。
通常情況下terget 和 this是一致的芦拿,
但有一種情況不同士飒,那就是在事件冒泡時(shí)(父子元素有相同事件,單擊子元素蔗崎,父元素的事件處理函數(shù)也會(huì)被觸發(fā)執(zhí)行)酵幕,
這時(shí)候this指向的是父元素,因?yàn)樗墙壎ㄊ录脑貙?duì)象缓苛,
而target指向的是子元素裙盾,因?yàn)樗怯|發(fā)事件的那個(gè)具體元素對(duì)象。
<div>123</div>
<script>
var div = document.querySelector('div');
div.addEventListener('click', function(e) {
// e.target 和 this指向的都是div
console.log(e.target);
console.log(this);
});
</script>
事件冒泡下的e.target和this
<ul>
<li>abc</li>
<li>abc</li>
<li>abc</li>
</ul>
<script>
var ul = document.querySelector('ul');
ul.addEventListener('click', function(e) {
// 我們給ul 綁定了事件 那么this 就指向ul
console.log(this); // ul
// e.target 觸發(fā)了事件的對(duì)象 我們點(diǎn)擊的是li e.target 指向的就是li
console.log(e.target); // li
});
</script>
11.6 阻止默認(rèn)行為
html中一些標(biāo)簽有默認(rèn)行為他嫡,例如a標(biāo)簽被單擊后,默認(rèn)會(huì)進(jìn)行頁面跳轉(zhuǎn)庐完。
<a >百度</a>
<script>
// 2. 阻止默認(rèn)行為 讓鏈接不跳轉(zhuǎn)
var a = document.querySelector('a');
a.addEventListener('click', function(e) {
e.preventDefault(); // dom 標(biāo)準(zhǔn)寫法
});
// 3. 傳統(tǒng)的注冊(cè)方式
a.onclick = function(e) {
// 普通瀏覽器 e.preventDefault(); 方法
e.preventDefault();
// 低版本瀏覽器 ie678 returnValue 屬性
e.returnValue = false;
// 我們可以利用return false 也能阻止默認(rèn)行為 沒有兼容性問題
return false;
}
</script>
11.7 阻止事件冒泡
事件冒泡本身的特性钢属,會(huì)帶來的壞處,也會(huì)帶來的好處门躯。
- 標(biāo)準(zhǔn)寫法:利用事件對(duì)象里面的stopPropagation()方法
e.stopPropagation()
- 非標(biāo)準(zhǔn)寫法:IE6-8 利用事件對(duì)象cancelBubble屬性
e.cancelBubble = true
<div class="father">
<div class="son">son兒子</div>
</div>
<script>
var son = document.querySelector('.son');
// 給son注冊(cè)單擊事件
son.addEventListener('click', function(e) {
alert('son');
e.stopPropagation(); // stop 停止 Propagation 傳播
window.event.cancelBubble = true; // 非標(biāo)準(zhǔn) cancel 取消 bubble 泡泡
}, false);
var father = document.querySelector('.father');
// 給father注冊(cè)單擊事件
father.addEventListener('click', function() {
alert('father');
}, false);
// 給document注冊(cè)單擊事件
document.addEventListener('click', function() {
alert('document');
})
</script>
阻止事件冒泡的兼容性處理
if(e && e.stopPropagation) {
e.stopPropagation();
}else {
window.event.cancelBubble = true;
}
11.8 事件委托
事件冒泡本身的特性淆党,會(huì)帶來的壞處,也會(huì)帶來的好處讶凉。
把事情委托給別人染乌,代為處理。事件委托也稱為事件代理懂讯,在 jQuery 里面稱為事件委派荷憋。
不給子元素注冊(cè)事件,給父元素注冊(cè)事件褐望,把處理代碼在父元素的事件中執(zhí)行勒庄。
生活中的代理:
js事件中的代理:
事件委托的原理
不給子元素單獨(dú)設(shè)置事件偵聽器,而是給父元素注冊(cè)事件(設(shè)置事件偵聽器)瘫里,利用事件冒泡实蔽,當(dāng)子元素的事件觸發(fā),會(huì)冒泡到父元素谨读,即也觸發(fā)了父元素的點(diǎn)擊事件局装。然后用父元素偵聽函數(shù)的內(nèi)容去控制相應(yīng)的子元素。
事件委托的作用
我們只操作了一次 DOM ,提高了程序的性能铐尚。
動(dòng)態(tài)新創(chuàng)建的子元素拨脉,也擁有事件。
// 事件委托的核心原理:給父節(jié)點(diǎn)添加偵聽器塑径, 利用事件冒泡影響每一個(gè)子節(jié)點(diǎn)
var ul = document.querySelector('ul');
ul.addEventListener('click', function(e) {
// e.target 這個(gè)可以得到我們點(diǎn)擊的對(duì)象
e.target.style.backgroundColor = 'pink';
})
十二女坑、常用鼠標(biāo)事件
12.1 案例:禁止選中文字和禁止右鍵菜單
- 禁止鼠標(biāo)右鍵菜單
contextmenu主要控制應(yīng)該何時(shí)顯示上下文菜單,主要用于取消默認(rèn)的上下文菜單
document.addEventListener('contextmenu',function(e) {
e.preventDefault();
})
- 精致鼠標(biāo)選中(selectstart 開始選中)
document.addEventListener('selectstart',function(e) {
e.preventDefault();
})
<body>
我是一段不愿意分享的文字
<script>
// 1. contextmenu 我們可以禁用右鍵菜單
document.addEventListener('contextmenu', function(e) {
e.preventDefault();
})
// 2. 禁止選中文字 selectstart
document.addEventListener('selectstart', function(e) {
e.preventDefault();
})
</script>
</body>
12.2 鼠標(biāo)事件對(duì)象
12.3 獲取鼠標(biāo)在頁面的坐標(biāo)
// 鼠標(biāo)事件對(duì)象 MouseEvent
document.addEventListener('click', function(e) {
// 1. client 鼠標(biāo)在可視區(qū)的x和y坐標(biāo)(和頁面高度和是否滾動(dòng)無關(guān))
console.log(e.clientX);
console.log(e.clientY);
console.log('---------------------');
// 2. page 鼠標(biāo)在頁面文檔的x和y坐標(biāo)(起始為文檔頁面頂端)
console.log(e.pageX);
console.log(e.pageY);
console.log('---------------------');
// 3. screen 鼠標(biāo)在電腦屏幕的x和y坐標(biāo)
console.log(e.screenX);
console.log(e.screenY);
})
12.4 案例:跟隨鼠標(biāo)的天使
<img src="images/angel.gif" alt="">
<script>
var pic = document.querySelector('img');
document.addEventListener('mousemove', function(e) {
// 1. mousemove只要我們鼠標(biāo)移動(dòng)1px 就會(huì)觸發(fā)這個(gè)事件
// 2.核心原理: 每次鼠標(biāo)移動(dòng)统舀,我們都會(huì)獲得最新的鼠標(biāo)坐標(biāo)匆骗,
// 把這個(gè)x和y坐標(biāo)做為圖片的top和left 值就可以移動(dòng)圖片
var x = e.pageX;
var y = e.pageY;
console.log('x坐標(biāo)是' + x, 'y坐標(biāo)是' + y);
//3 . 千萬不要忘記給left 和top 添加px 單位
pic.style.left = x - 50 + 'px';
pic.style.top = y - 40 + 'px';
});
</script>
十三、常用的鍵盤事件
13.1 鍵盤事件
- 使用addEventListener時(shí)不需要加on
- onkeypress和前面2個(gè)的區(qū)別是誉简,它不識(shí)別功能鍵碉就,比如左右鍵盤和shift等,按下這些鍵時(shí)不能觸發(fā)這個(gè)事件
- 三個(gè)事件的執(zhí)行順序是keydown -keypress -keyup
// 常用的鍵盤事件
//1. keyup 按鍵彈起的時(shí)候觸發(fā)
document.addEventListener('keyup', function() {
console.log('我彈起了');
})
//3. keypress 按鍵按下的時(shí)候觸發(fā) 不能識(shí)別功能鍵 比如 ctrl shift 左右箭頭啊
document.addEventListener('keypress', function() {
console.log('我按下了press');
})
//2. keydown 按鍵按下的時(shí)候觸發(fā) 能識(shí)別功能鍵 比如 ctrl shift 左右箭頭啊
document.addEventListener('keydown', function() {
console.log('我按下了down');
})
// 4. 三個(gè)事件的執(zhí)行順序 keydown -- keypress -- keyup
13.2 鍵盤事件對(duì)象
- onkeydown和onkeyuo不區(qū)分字母大小寫(返回都是大寫字母的ASCII碼值)闷串,onkeypress區(qū)分
- keypress不能識(shí)別功能鍵床玻,但keyCode屬性能區(qū)分大小寫闷沥,返回不同的ASCII值
使用keyCode屬性判斷用戶按下哪個(gè)鍵
// 鍵盤事件對(duì)象中的keyCode屬性可以得到相應(yīng)鍵的ASCII碼值
document.addEventListener('keyup', function(e) {
console.log('up:' + e.keyCode);
// 我們可以利用keycode返回的ASCII碼值來判斷用戶按下了那個(gè)鍵
if (e.keyCode === 65) {
alert('您按下的a鍵');
} else {
alert('您沒有按下a鍵')
}
})
document.addEventListener('keypress', function(e) {
// console.log(e);
console.log('press:' + e.keyCode);
})
13.3 案例:模擬京東按鍵輸入內(nèi)容
當(dāng)我們按下 s 鍵, 光標(biāo)就定位到搜索框(文本框獲得焦點(diǎn))。
注意:觸發(fā)獲得焦點(diǎn)事件偎行,可以使用 元素對(duì)象.focus()
<input type="text">
<script>
// 獲取輸入框
var search = document.querySelector('input');
// 給document注冊(cè)keyup事件
document.addEventListener('keyup', function(e) {
// 判斷keyCode的值
if (e.keyCode === 83) {
// 觸發(fā)輸入框的獲得焦點(diǎn)事件
search.focus();
}
})
</script>
13.4 案例:模擬京東快遞單號(hào)查詢
要求:當(dāng)我們?cè)谖谋究蛑休斎雰?nèi)容時(shí),文本框上面自動(dòng)顯示大字號(hào)的內(nèi)容氛魁。
<div class="search">
<div class="con">123</div>
<input type="text" placeholder="請(qǐng)輸入您的快遞單號(hào)" class="jd">
</div>
<script>
// 獲取要操作的元素
var con = document.querySelector('.con');
var jd_input = document.querySelector('.jd');
// 給輸入框注冊(cè)keyup事件
jd_input.addEventListener('keyup', function() {
// 判斷輸入框內(nèi)容是否為空
if (this.value == '') {
// 為空藏姐,隱藏放大提示盒子
con.style.display = 'none';
} else {
// 不為空,顯示放大提示盒子凉蜂,設(shè)置盒子的內(nèi)容
con.style.display = 'block';
con.innerText = this.value;
}
})
// 給輸入框注冊(cè)失去焦點(diǎn)事件琼梆,隱藏放大提示盒子
jd_input.addEventListener('blur', function() {
con.style.display = 'none';
})
// 給輸入框注冊(cè)獲得焦點(diǎn)事件
jd_input.addEventListener('focus', function() {
// 判斷輸入框內(nèi)容是否為空
if (this.value !== '') {
// 不為空則顯示提示盒子
con.style.display = 'block';
}
})
</script>