JavaScript中Dom
1.基本概念
1.1 什么是window?
- window:是一個全局對象, 代表瀏覽器中一個打開的窗口, 每個窗口都是一個window對象(整個窗口哦)
1.2 什么是document?
- document是window的一個屬性, 這個屬性是一個對象
- document: 代表當前窗口中的整個網頁
- document對象保存了網頁上所有的內容, 通過document對象就可以操作網頁上的內容
1.3 什么是DOM?
- DOM 定義了訪問和操作 HTML文檔(網頁)的標準方法,所以學習DOM就是學習如何通過document對象操作網頁上的內容
2.獲取dom元素==(注意理解節(jié)點的概念)==
在JavaScript中HTML標簽也稱之為DOM元素,使用document的時候前面不用加window
2.1通過id獲取
- document.getElementById("box");
- 由于id不可以重復, 所以找到了就會將找到的標簽包裝成一個對象返回給我們, 找不到就返回Null
- 注意點: DOM操作返回的是一個對象, 這個對象是宿主類型對象(瀏覽器提供的對象)
2.2 通過class名稱獲取
- document.getElementsByClassName("father");
- 由于class可以重復, 所以找到了就返回一個存儲了標簽對象的數(shù)組, 找不到就返回一個空數(shù)組
2.3 通過name名稱獲取
<form> <input type="text" name="test"> <input type="password" name="test"> </form> let oDivs = document.getElementsByName("test"); console.log(oDivs);由于name可以重復, 所以找到了就返回一個存儲了標簽對象的數(shù)組, 找不到就返回一個空數(shù)組
getElementsByName 在不同的瀏覽器其中工作方式不同。在IE和Opera中, getElementsByName() 方法還會返回那些 id 為指定值的元素
2.4 通過標簽名稱獲取
- document.getElementsByTagName("div");
- 由于標簽名稱可以重復, 所以找到了就返回一個存儲了標簽對象的數(shù)組, 找不到就返回一個空數(shù)組
2.5 通過選擇器獲取(重點)
- let oDiv = document.querySelector(".box");
- querySelector只會返回根據(jù)指定選擇器找到的第一個元素
2.6 通過選擇器獲取2(重點)
- let oDivs = document.querySelectorAll(".father");
- querySelectorAll會返回指定選擇器找到的所有元素
2.7 獲取元素中所有子元素或子節(jié)點
-
首先了解一下什么是節(jié)點
- DOM對象(document), 這個對象以樹的形式保存了界面上所有的內容,HTML頁面每一部分都是由節(jié)點(標簽(元素),文本,屬性)
- 節(jié)點樹.png
let oDiv = document.querySelector("div"); // children屬性獲取到的是指定元素中所有的子元素 console.log(oDiv.children); // childNodes屬性獲取到的是指定元素中所有的節(jié)點 console.log(oDiv.childNodes); for(let node of oDiv.childNodes){ console.log(node.nodeType); if(node.nodeType === Node.ELEMENT_NODE){ //判斷節(jié)點類型 console.log(node); } }
2.8獲取指定節(jié)點第一個或最后一個子節(jié)點或子元素
let oDiv = document.querySelector("div"); //第一個子節(jié)點 console.log(oDiv.firstChild); //獲取指定元素中的第一個子元素 console.log(oDiv.firstElementChild); //獲取指定節(jié)點中最后一個子節(jié)點 console.log(oDiv.lastChild); // 獲取指定元素中最后一個子元素 console.log(oDiv.lastElementChild);
2.9 獲取子元素獲取父節(jié)點或度元素
let item = document.querySelector(".item"); //其實獲取的一樣,只不過由于火狐瀏覽器以前不支持parentNode,所以才有了兩個 console.log(item.parentElement); console.log(item.parentNode); let parentEle = item.parentElement || item.parentNode;//兼容性寫法 console.log(parentEle);
2.10 獲取相鄰上一個節(jié)點或元素/下一個節(jié)點或元素
//獲取相鄰上一個節(jié)點 console.log(item.previousSibling); //獲取相鄰上一個元素 console.log(item.previousElementSibling); //獲取相鄰下一個節(jié)點 console.log(item.nextSibling); //獲取相鄰下一個元素 console.log(item.nextElementSibling);
3.節(jié)點增刪改查
首先我們有這樣一個結構
<div> <h1>我是標題</h1> <p>我是段落</p> </div>
然后我們創(chuàng)建一個節(jié)點
let oSpan = document.createElement("span"); // console.log(oSpan); // console.log(typeof oSpan); 是一個對象類型
然后將這個節(jié)點添加進去
// 注意點: appendChild方法會將指定的元素添加到最后 let oDiv = document.querySelector("div"); oDiv.appendChild(oSpan)
那么如果我想添加在指定的地方怎么辦
let oDiv = document.querySelector("div"); let oH1 = document.querySelector("h1"); let oP = document.querySelector("p"); oDiv.insertBefore(oSpan, oH1); //我就把oSpan插到了oH1前面 oDiv.insertBefore(oSpan, oP);
該怎么刪除呢
// 注意點: 在js中如果想要刪除某一個元素, 只能通過對應的父元素來刪除,元素是不能夠自殺的 console.log(oSpan.parentNode); oSpan.parentNode.removeChild(oSpan); oDiv.parentNode.removeChild(oDiv);
再看一下如何克隆一個節(jié)點
// 注意點: cloneNode方法默認不會克隆子元素, 如果想克隆子元素需要傳遞一個true let oDiv = document.querySelector("div"); let newDiv = oDiv.cloneNode();//只克隆自己,不可隆子元素 let newDiv = oDiv.cloneNode(true); console.log(newDiv);
4.元素屬性的增刪改查
4.1 基本概念
- 無論是通過document創(chuàng)建還是查詢出來的標簽,系統(tǒng)都會將元素包裝成一個對象返回給我們,系統(tǒng)在包裝這個對象的時候會自動將元素的屬性都包裝到這個對象中,所以只要拿到這個對象就可以拿到標簽屬性,操作標簽屬性.
4.2 如何獲取元素屬性
<img src="images/1.jpg" alt="我是alt222" title="我是title" nj="666"> let oImg = document.querySelector("img"); console.log(oImg.alt); console.log(oImg.getAttribute("alt")); //注意點: 通過對象.屬性名稱的方式無法獲取到自定義屬性的取值 //通過getAttribute方法可以獲取到自定義屬性的取值 console.log(oImg.nj);//獲取不到 console.log(oImg.getAttribute("nj"))
4.3 如何修改元素屬性
oImg.title = "新的title"; oImg.setAttribute("title", "新的title222"); //給屬性名為title的內容設為新的title222 //注意點和獲取元素屬性一樣 oImg.nj = "123"; oImg.setAttribute("nj", "123");
4.4 如何新增元素屬性
// 注意點: setAttribute方法如果屬性不存在就是新增, 如果屬性存在就是修改 oImg.setAttribute("it666", "itzb");
4.5 如何刪除元素屬性
oImg.removeAttribute("alt"); // 注意點和獲取元素屬性一樣 oImg.nj = ""; oImg.removeAttribute("nj");
5.元素內容操作
5.1 獲取元素內容
/* 1.innerHTML獲取的內容包含標簽, innerText/textContent獲取的內容不包含標簽 2.innerHTML/textContent獲取的內容不會去除兩端的空格, innerText獲取的內容會去除兩端的空格 */ let oDiv = document.querySelector("div"); console.log(oDiv.innerHTML); console.log(oDiv.innerText); console.log(oDiv.textContent);
5.2 設置元素內容
/* 特點: 無論通過innerHTML/innerText/textContent設置內容, 新的內容都會覆蓋原有的內容 區(qū)別: 如果通過innerHTML設置數(shù)據(jù), 數(shù)據(jù)中包含標簽, 會轉換成標簽之后再添加 如果通過innerText/textContent設置數(shù)據(jù), 數(shù)據(jù)中包含標簽, 不會轉換成標簽, 會當做一個字符串直接設置 */ let oDiv = document.querySelector("div"); // oDiv.innerHTML = "123"; // oDiv.innerText = "456"; // oDiv.textContent = "789"; // oDiv.innerHTML = "<span>我是span</span>"; // oDiv.innerText = "<span>我是span</span>"; // oDiv.textContent = "<span>我是span</span>"; setText(oDiv, "www.it666.com"); //為了解決兼容性問題,企業(yè)開發(fā)中textContent和innerText是結合起來使用的 function setText(obj, text) { if("textContent" in obj){ //如果有這個屬性 obj.textContent = text; }else{ obj.innerText = text; } }
6.元素樣式操作
6.1 設置元素樣式
<style> .box{ width: 200px; height: 200px; background-color: red; } </style> let oDiv = document.querySelector("div"); // 第一種方式 // 注意點: 由于class在JS中是一個關鍵字, 所以叫做className oDiv.className = "box"; // 第二種方式 // 注意點: 過去CSS中通過-連接的樣式, 在JS中都是駝峰命名 // 注意點: 通過JS添加的樣式都是行內樣式, 會覆蓋掉同名的CSS樣式 oDiv.style.width = "300px"; oDiv.style.height = "300px"; oDiv.style.backgroundColor = "blue";
6.2 獲取元素樣式
let oDiv = document.querySelector("div"); oDiv.style.width = "300px"; // 注意點: 通過style屬性只能過去到行內樣式的屬性值, 獲取不到CSS設置的屬性值 console.log(oDiv.style.width); // 注意點: 如果想獲取到CSS設置的屬性值, 必須通過getComputedStyle方法來獲取 // getComputedStyle方法接收一個參數(shù), 這個參數(shù)就是要獲取的元素對象 // getComputedStyle方法返回一個對象, 這個對象中就保存了CSS設置的樣式和屬性值 let style = window.getComputedStyle(oDiv); console.log(style.width);
7. 點擊事件
如何給元素綁定事件?
在JavaScript中所有的HTML標簽都可以添加事件,元素.事件名稱 = function(){},當對應事件被觸發(fā)時候就會自動執(zhí)行function中的代碼.
<button>我是按鈕</button> <a >我是a標簽</a> let oBtn = document.querySelector("button"); oBtn.onclick = function () { alert("按鈕被點擊了"); } // 注意點: 如果給元素添加了和系統(tǒng)同名的事件, 我們添加的事件不會覆蓋系統(tǒng)添加的事件,只不過會先執(zhí)行我們添加的,在執(zhí)行系統(tǒng)的.想要覆蓋就寫一句return false let oA = document.querySelector("a"); oA.onclick = function () { alert("a標簽被點擊了"); // 以下代碼的含義: 用我們添加的事件覆蓋掉系統(tǒng)同名的事件 return false; }
8. 定時器
8.1重復執(zhí)行的定時器
setInterval
//有兩個按鈕 <button id="start">開始</button> <button id="close">結束</button> //定時器會返回一個唯一的標識,我們用id來接收,方便關閉 let startBtn = document.querySelector("#start"); let id = null; startBtn.onclick = function () { id = setInterval(function () { console.log("隨便寫點"); }, 1000); } let closeBtn = document.querySelector("#close"); closeBtn.onclick = function () { clearInterval(id); }
8.2 只執(zhí)行一次的
setTimeout
let startBtn = document.querySelector("#start"); let closeBtn = document.querySelector("#close"); let id = null; startBtn.onclick = function () { id = window.setTimeout(function () { console.log("隨便寫點"); }, 5000); } closeBtn.onclick = function () { clearTimeout(id); }
9.做兩個小游戲
9.1 消除鬼魂
9.2貪吃蛇
10.移入移出事件
// 1.移入事件 oDiv.onmouseover = function () { console.log("移入事件"); } // 注意點: 對于初學者來說, 為了避免未知的一些BUG, 建議使用onmouseenter oDiv.onmouseenter = function () { console.log("移入事件"); } // 2.移出事件 oDiv.onmouseout = function () { console.log("移出事件"); } // 注意點: 對于初學者來說, 為了避免未知的一些BUG, 建議使用onmouseleave oDiv.onmouseleave = function () { console.log("移出事件"); } // 3.移動事件 oDiv.onmousemove = function () { console.log("移動事件"); }移入移出表單 商品展示
11 表單事件(注意實時獲取修改后的數(shù)據(jù))
let oInput = document.querySelector("input"); // 1.監(jiān)聽input獲取焦點 oInput.onfocus = function () { console.log("獲取到了焦點"); } // 2.監(jiān)聽input失去焦點 oInput.onblur = function () { console.log("失去了焦點"); } // 3.監(jiān)聽input內容改變 // 注意點: onchange事件只有表單失去焦點的時候, 才能拿到修改之后的數(shù)據(jù) oInput.onchange = function () { console.log(this.value); } // oninput事件可以時時獲取到用戶修改之后的數(shù)據(jù), 只要用戶修改了數(shù)據(jù)就會調用(執(zhí)行) // 注意點: oninput事件只有在IE9以及IE9以上的瀏覽器才能使用 // 在IE9以下, 如果想時時的獲取到用戶修改之后的數(shù)據(jù), 可以通過onpropertychange事件來實現(xiàn) // 通過代碼修改value不會觸發(fā)input事件 oInput.oninput = function () { console.log(this.value); }
* 表單校驗 以及輸入框有內容才能點擊按鈕
* 讓當前提交按鈕不能點擊用disabled ,當不能點擊時,disabled為true
#### 12 tab選項卡
* ```JavaScript
<body>
<div class="box">
<ul class="top">
<li class="current">新聞</li>
<li>視頻</li>
<li>音樂</li>
<li>軍事</li>
<li>財經</li>
</ul>
<div class="bottom">
<div class="content">新聞的內容</div>
<div class="content">視頻的內容</div>
<div class="content">音樂的內容</div>
<div class="content">軍事的內容</div>
<div class="content">財經的內容</div>
</div>
</div>
<script>
// 1.拿到需要操作的元素
let oItems = document.querySelectorAll("li");
let oDivs = document.querySelectorAll(".content");
// 定義變量保存上一次設置的索引
let previousIndex = 0;
// 2.給所有的選項卡添加點擊事件
for(let i = 0; i < oItems.length; i++){
let item = oItems[i];
// item.setAttribute("index", i);
item.onclick = function() {
// 清空上一次對應的元素對應的樣式
let preItem = oItems[previousIndex];
preItem.className = "";
let preDiv = oDivs[previousIndex];
preDiv.style.display = "none";
// 設置當前這一次的元素對應的樣式
// let index = this.getAttribute("index");
this.className = "current";
let oDiv = oDivs[i];
oDiv.style.display = "block";
// 保存當前這一次的索引
previousIndex = i;
};
}
</script>
</body>
在上面的代碼中,為什么i直接就能用,為什么用let定義的for循環(huán)就行,var就不行,我們先引出閉包的概念
-
12.1 閉包
/* 1.什么是閉包(closure)? 閉包是一種特殊的函數(shù)。 2.如何生成一個閉包? 當一個內部函數(shù)引用了外部函數(shù)的數(shù)據(jù)(變量/函數(shù))時, 那么內部的函數(shù)就是閉包 所以只要滿足"是函數(shù)嵌套"、"內部函數(shù)引用外部函數(shù)數(shù)據(jù)" 3.閉包特點: 只要閉包還在使用外部函數(shù)的數(shù)據(jù), 那么外部的數(shù)據(jù)就一直不會被釋放 也就是說可以延長外部函數(shù)數(shù)據(jù)的生命周期 4.閉包注意點: 當后續(xù)不需要使用閉包時候, 一定要手動將閉包設置為null, 否則會出現(xiàn)內存泄漏 */ function test() { var i = 666; // 局部變量 } // 只要代碼執(zhí)行到了大括號結束, i這個變量就會自動釋放 console.log(i); // i is not defined //下面開啟閉包 function test() { var i = 666; // 由于demo函數(shù)滿足閉包的兩個條件, 所以demo函數(shù)就是閉包 return function demo() { console.log(i); } } let fn = test(); fn(); // 666
12.2 循環(huán)索引同步(var的情況)
/* 默認情況下是順序結構, 代碼會從上之下的執(zhí)行, 前面的沒執(zhí)行完后面的不能執(zhí)行 默認情況下通過var定義的變量, 只要不是定義在函數(shù)中都是全局變量 */ for(var i = 0; i < 3; i++){ // 0 1 2 3 function test() { console.log(i); // 3 } } // console.log(i); // 3 test(); //想要輸出當前索引,有如下方式 for(var i = 0; i < 3; i++){ // 0 1 2 3 function test() { console.log(i); // 0 1 2 } test(); } for(var i = 0; i < 3; i++){ // 0 1 2 3 (function test() { console.log(i); // 0 1 2 })(); } for(var i = 0; i < 3; i++){ // 0 1 2 3 // function test(index) { // var index = i; // console.log(index); // 0 1 2 // } // test(i); 可以簡寫為如下 (function test(index) { console.log(index); // 0 1 2 })(i); }-
做一個練習,定義三個按鈕,點擊每一個輸出對應的索引
//不能同步,因為等循環(huán)執(zhí)行完才執(zhí)行函數(shù) let oBtns = document.querySelectorAll("button"); for(var i = 0; i < oBtns.length; i++){ let btn = oBtns[i]; btn.onclick = function () { console.log(i); // 3 } }//能同步 let oBtns = document.querySelectorAll("button"); for(var i = 0; i < oBtns.length; i++) { let btn = oBtns[i]; (function test(index) { // var index = i; // console.log(index); // 0 1 2 // 注意點: onclick對應的方法由于滿足了閉包的條件, 所以onclick對應的方法也是一個閉包 //所以index不會被立即釋放,我們就能訪問了 btn.onclick = function () { console.log(index); } })(i); }看一下上面那個函數(shù)執(zhí)行完在內存里面的情況
- 循環(huán)索引同步.png
12.2 循環(huán)索引同步(let的情況)
/*let list = []; // 這里的i是局部變量 // 注意點: 由于i是局部變量, 所以每次執(zhí)行完循環(huán)體都會重新定義一個i變量 for(let i = 0; i < 3; i++){ // 0 1 2 3 let fn = function test() { console.log(i); // 3 } list.push(fn); } // console.log(i); // i is not defined // 以下會依次輸出1,2,3 list[0](); list[1](); list[2](); */ for(let i = 0; i < 3; i++){ // 0 1 2 3 // 注意點: 在ES6中由于{}是塊級作用域, 所以只要在塊級作用域中定義了一個函數(shù) // 并且這個函數(shù)中用到了塊級作用域中的數(shù)據(jù), 那么這個函數(shù)就是閉包 function test() { console.log(i); } } test(); // 2上面的代碼內存中情況如下
- 循環(huán)索引同步let.png
? 這就是為什么通過let定義在for循環(huán)中后通過點擊事件可以取得當前的i值,因為是閉包
12.3 排他思想
/* 1.什么是排它思想? 清除其它非選中元素的樣式, 只設置當前選中元素樣式 */ let oItems = document.querySelectorAll("li"); let previousIndex = 0; // es6之后 for(let i = 0; i < oItems.length; i++){ let item = oItems[i]; item.onclick = function () { // 排它 // for(let j = 0; j < oItems.length; j++){ // let li = oItems[j]; // li.className = ""; // } // 通過一個索引實現(xiàn)排他 let preItem = oItems[previousIndex]; preItem.className = ""; this.className = "current"; previousIndex = i; } } //es6之前 for(var i = 0; i < oItems.length; i++) { var item = oItems[i]; (function (index) { item.onclick = function () { // 排它 var preItem = oItems[previousIndex]; preItem.className = ""; this.className = "current"; previousIndex = index; } })(i); }
13 時鐘對象
// 1.獲取當前時間 let date = new Date(); console.log(date); // 2.獲取當前時間距離1970年1月1日(世界標準時間)起的毫秒 console.log(Date.now()); let date = new Date(); console.log(date.valueOf()); // 3.創(chuàng)建指定時間 let date1 = new Date("2019-11-11 09:08:07"); console.log(date1); // 注意點: 在創(chuàng)建指定時間的時候, 如果月份是單獨傳入的, 那么會多一個月 let date2 = new Date(2019, 10, 11, 9, 8, 7); console.log(date2); // 4.獲取指定時間年月日時分秒 let date = new Date(); console.log(date); console.log(date.getFullYear()); // 注意點; 通過getMonth方法獲取到的月份會少一個月 console.log(date.getMonth() + 1); console.log(date.getDate()); console.log(date.getHours()); console.log(date.getMinutes()); console.log(date.getSeconds()); // 5.時間格式化 let date = new Date(); let res = formartDate(date); console.log(res); // console.log(date); // 2019-4-19 18:17:06 function formartDate(date) { return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`; }-
獲取時間差
// 1000毫秒 = 1秒 60秒 = 1分鐘 60分鐘 = 1小時 24小時 = 1天 // 以下兩個時間相差值 10天1小時29分40秒 let curDate = new Date("2020-4-19 22:30:20"); let remDate = new Date("2020-4-30 00:00:00"); // 1.得到兩個時間之間的差值(毫秒) let differTime = remDate - curDate; // let differTime = remDate.valueOf() - curDate.valueOf(); // 2.得到兩個時間之間的差值(秒) let differSecond = differTime / 1000; // 3.利用相差的總秒數(shù) / 每一天的秒數(shù) = 相差的天數(shù) let day = Math.floor(differSecond / (60 * 60 * 24)); console.log(day); // 4.利用相差的總秒數(shù) / 小時 % 24; let hour = Math.floor(differSecond / (60 * 60) % 24); console.log(hour); // 5.利用相差的總秒數(shù) / 分鐘 % 60; let minute = Math.floor(differSecond / 60 % 60); console.log(minute); // 6.利用相差的總秒數(shù) % 秒數(shù) let second = differSecond % 60; console.log(second);秒殺效果 時鐘效果
14 勻速動畫和緩動動畫
14.1 勻速動畫
function linearAnimation(ele, target) { //關掉定時器,防止定時器的疊加 clearInterval(timerId); timerId = setInterval(function () { // 1.拿到元素當前的位置 let begin = parseInt(ele.style.marginLeft) || 0; // 2.定義變量記錄步長 // 0 - 500 = -500 13 // 500 - 200 = 300 -13 let step = (begin - target) > 0 ? -13 : 13; // 3.計算新的位置 begin += step; console.log(Math.abs(target - begin), Math.abs(step)); //當由小往大走時,不夠一個步長說明就快到終點了,往小同理 if(Math.abs(target - begin) <= Math.abs(step)){ clearInterval(timerId); begin = target; } // 4.重新設置元素的位置 ele.style.marginLeft = begin + "px"; }, 100); }
14.2 緩動動畫
-
function easeAnimation(ele, target) { clearInterval(timerId); timerId = setInterval(function () { // 1.拿到元素當前的位置 let begin = parseInt(ele.style.marginLeft) || 0; // 2.定義變量記錄步長 // 公式: (結束位置 - 開始位置) * 緩動系數(shù)(0 ~1) let step = (target - begin) * 0.3; console.log(step); // 3.計算新的位置 begin += step; //結束條件 if(Math.abs(Math.floor(step)) <= 1){ clearInterval(timerId); begin = target; } // 4.重新設置元素的位置 ele.style.marginLeft = begin + "px"; }, 100); }無限自動輪播
14.3 勻速動畫的封裝
對前面代碼的優(yōu)化,可以實現(xiàn)多個動畫一起執(zhí)行
linearAnimation(oDiv, {"marginTop":500, "marginLeft": 300}, function () { alert("動畫執(zhí)行完畢之后執(zhí)行的其它的操作"); }); function linearAnimation(ele, obj, fn) { clearInterval(timerId); timerId = setInterval(function () { // flag變量用于標記是否所有的屬性都執(zhí)行完了動畫 let flag = true; for(let key in obj){ let attr = key; let target = obj[key]; // 1.拿到元素當前的位置 // let begin = parseInt(ele.style.width) || 0; let style = getComputedStyle(ele); // let begin = parseInt(style.width) || 0; let begin = parseInt(style[attr]) || 0; // 2.定義變量記錄步長 let step = (begin - target) > 0 ? -13 : 13; // 3.計算新的位置 begin += step; if(Math.abs(target - begin) > Math.abs(step)){ flag = false; }else{ begin = target; } // 4.重新設置元素的位置 // ele.style.width = begin + "px"; ele.style[attr] = begin + "px"; } if(flag){ clearInterval(timerId); // if(fn){ // fn(); // } fn && fn(); } }, 100);
15 事件
15.1 添加事件的三種方式
/* 方式一: 1.通過onxxx的方式來添加 注意點: 由于是給屬性賦值, 所以后賦值的會覆蓋先賦值 */ oBtn.onclick = function () { alert("666"); } oBtn.onclick = function () { alert("777"); } let obj = {}; obj.say = function () { console.log("123"); } obj.say = function () { console.log("456"); } obj.say();/* 方式二: 2.通過addEventListener方法添加 注意點: 1.事件名稱不需要添加on 2.后添加的不會覆蓋先添加的 下面會輸出兩次 3.只支持最新的瀏覽器IE9 */ oBtn.addEventListener("click", function () { alert("666"); }); oBtn.addEventListener("click", function () { alert("777"); });/* 方式三 3.通過attachEvent方法添加 注意點: 1.事件名稱必須加上on 2.后添加的不會覆蓋先添加的 3.只支持低版本的瀏覽器 */ oBtn.attachEvent("onclick", function () { alert("666"); }); oBtn.attachEvent("onclick", function () { alert("777"); });-
以下為兼容寫法
function addEvent(ele, name, fn) { if(ele.attachEvent){ ele.attachEvent("on"+name, fn); }else{ ele.addEventListener(name, fn); } }
15.2 事件對象以及阻止默認行為
/* 1.什么是事件對象? 事件對象就是一個系統(tǒng)自動創(chuàng)建的一個對象 當注冊的事件被觸發(fā)的時候, 系統(tǒng)就會自動創(chuàng)建事件對象 */ /* 2.事件對象的注意點: 在高級版本的瀏覽器中, 會自動將事件對象傳遞給回到函數(shù) 在低級版本的瀏覽器中, 不會自動將事件對象傳遞給回調函數(shù) 在低級版本的瀏覽器中, 需要通過window.event來獲取事件對象 */ let oA = document.querySelector("a"); oA.onclick = function (event) { // 兼容性的寫法 event = event || window.event; alert("666"); // 阻止默認行為 return false; // 企業(yè)開發(fā)推薦 // 注意點: preventDefault方法只支持高級版本的瀏覽器 // event.preventDefault(); // event.returnValue = false; // IE9以下的瀏覽器 }-
事件的三個階段
<body> <div class="father"> <div class="son"></div> </div> <script> /* 1.事件的三個階段 1.1.捕獲階段(從外向內的傳遞事件) 1.2.當前目標階段 1.3.冒泡的階段(從內向外的傳遞事件) 2.注意點: 三個階段只有兩個會被同時執(zhí)行 要么捕獲和當前, 要么當前和冒泡 3.為什么要么只能是捕獲和當前, 要么只能是當前和冒泡? 這是JS處理事件的歷史問題 早期各大瀏覽器廠商為占領市場, 以及對事件的理解不同 后續(xù)W3C為了兼容, 將兩種方式都納入標準 */ /* 1.如何設置事件到底是捕獲還是冒泡? 通過addEventListener方法, 這個方法接收三個參數(shù) 第一個參數(shù): 事件的名稱 第二個參數(shù): 回調函數(shù) 第三個參數(shù): false冒泡 / true 捕獲 注意點: onXxx的屬性, 不接收任何參數(shù), 所以默認就是冒泡 attachEvent方法, 只能接收兩個參數(shù), 所以默認就是冒泡 */ let oFDiv = document.querySelector(".father"); let oSDiv = document.querySelector(".son"); /* 以下會先輸出son,然后father oFDiv.addEventListener("click", function () { console.log("father"); }, false); oSDiv.addEventListener("click", function () { console.log("son"); }, false); */ oFDiv.onclick = function () { console.log("father"); } oSDiv.onclick = function () { console.log("son"); } /* IE 6.0: div -> body -> html -> document 其他瀏覽器: div -> body -> html -> document -> window 注意: 不是所有的事件都能冒泡,以下事件不冒泡:blur、focus、load、unload */ </script> </body>下圖可以很好地理解冒泡和捕獲

15.3 阻止事件冒泡
由上面我們知道,當事件發(fā)生后,事件冒泡就是一個事件開始傳播(從里到外或者從外向里)。為什么要傳播呢?因為事件源本身(可能)并沒有處理事件的能力,即處理事件的函數(shù)(方法)并未綁定在該事件源上。例如我們點擊一個按鈕時,就會產生一個click事件,但這個按鈕本身可能不能處理這個事件,事件必須從這個按鈕傳播出去,從而到達能夠處理這個事件的代碼中(例如我們給按鈕的onclick屬性賦一個函數(shù)的名字,就是讓這個函數(shù)去處理該按鈕的click事件),或者按鈕的父級綁定有事件函數(shù),當該點擊事件發(fā)生在按鈕上,按鈕本身并無處理事件函數(shù),則傳播到父級去處理。
-
如何阻止
// 1.拿到需要操作的元素 var oFDiv = document.getElementById("father"); var oSDiv = document.getElementById("son"); // 2.注冊事件監(jiān)聽 oFDiv.onclick = function () { console.log("father"); } oSDiv.onclick = function (event) { event = event || window.event; // 注意點: stopPropagation方法只支持高級瀏覽器 // event.stopPropagation(); // event.cancelBubble = true; // 低級瀏覽器 if(event.cancelBubble){ event.cancelBubble = true; }else{ event.stopPropagation(); } console.log("son"); }
15.4 移入移出事件區(qū)別
15.5 事件位置獲取
/* offsetX/offsetY: 事件觸發(fā)相對于當前元素自身的位置 clientX/clientY: 事件觸發(fā)相對于瀏覽器可視區(qū)域的位置 注意點: 可視區(qū)域是不包括滾動出去的范圍的 pageX/pageY: 事件觸發(fā)相對于整個網頁的位置 主要點: 整個網頁包括滾動出去的范圍的 screenX/screenY: 事件觸發(fā)相對于屏幕的位置(電腦屏幕) */
16 正則表達式
/* 1.什么是正則表達式? 正則表達式就是對字符串操作的一種邏輯公式 2.正則表達式的作用? 1.在字符串"查找"是否包含指定子串 2.從字符串中"提取"指定子串 3.對字符串中指定的內容進行"替換" */ // 1.字符串查找 /* let str = "123abc456"; let index = str.indexOf("abc"); let index = str.lastIndexOf("abc"); let flag = str.includes("abc"); */ // 2.字符串提取 /* let str = "123abc456"; let startIndex = str.indexOf("a"); console.log(str.substr(startIndex, "abc".length)); */ // 3.字符串替換 /* let str = "123abc456"; str.replace("abc", "it666"); */ // 1.利用正則表達式匹配(查找) let str = "123abc456"; // 1.創(chuàng)建一個正則表達式對象 // 2.指定匹配的規(guī)則 // 注意點: 默認情況下在正則表達式中是區(qū)分大小寫的,當給構造函數(shù)中傳遞一個i時,代表不區(qū)分大小寫. let reg = new RegExp("A", "i"); let res = reg.test(str); console.log(res); let str = "abc2020-1-11def"; // 通過構造函數(shù)創(chuàng)建正則表達式對象,注意轉義字符 // let reg = new RegExp("\\d{4}-\\d{1,2}-\\d{1,2}"); // 通過字面量來創(chuàng)建正則表達式對象 let reg = /\d{4}-\d{1,2}-\d{1,2}/; let res = reg.test(str); console.log(res); // 2.通過正則表達式提取符合規(guī)則的字符串 let str = "abc2020-1-11def2019-11-11fdjsklf"; // 注意點: 默認情況下在正則表達式中一旦匹配就會停止查找,后面寫個g代表全局查找 let reg = /\d{4}-\d{1,2}-\d{1,2}/g; let res = str.match(reg); console.log(res); console.log(res[0]); console.log(res[1]); // 3.通過正則表達式替換符合規(guī)則的字符串 let str = "abc2020-1-11def2019-11-11fdjsklf"; let reg = /\d{4}-\d{1,2}-\d{1,2}/g; let newStr = str.replace(reg, "it666"); console.log(str); console.log(newStr); </script> /* 常用正則表達式合集: 驗證數(shù)字:^[0-9]*$ 驗證n位的數(shù)字:^\d{n}$ 驗證至少n位數(shù)字:^\d{n,}$ 驗證m-n位的數(shù)字:^\d{m,n}$ 驗證零和非零開頭的數(shù)字:^(0|[1-9][0-9]*)$ 驗證有兩位小數(shù)的正實數(shù):^[0-9]+(.[0-9]{2})?$ 驗證有1-3位小數(shù)的正實數(shù):^[0-9]+(.[0-9]{1,3})?$ 驗證非零的正整數(shù):^\+?[1-9][0-9]*$ 驗證非零的負整數(shù):^\-[1-9][0-9]*$ 驗證非負整數(shù)(正整數(shù) + 0) ^\d+$ 驗證非正整數(shù)(負整數(shù) + 0) ^((-\d+)|(0+))$ 驗證長度為3的字符:^.{3}$ 驗證由26個英文字母組成的字符串:^[A-Za-z]+$ 驗證由26個大寫英文字母組成的字符串:^[A-Z]+$ 驗證由26個小寫英文字母組成的字符串:^[a-z]+$ 驗證由數(shù)字和26個英文字母組成的字符串:^[A-Za-z0-9]+$ 驗證由數(shù)字、26個英文字母或者下劃線組成的字符串:^\w+$ 驗證用戶密碼:^[a-zA-Z]\w{5,17}$ 正確格式為:以字母開頭,長度在6-18之間,只能包含字符、數(shù)字和下劃線。 驗證是否含有 ^%&',;=?$\" 等字符:[^%&',;=?$\x22]+ 驗證漢字:^[\u4e00-\u9fa5],{0,}$ 驗證Email地址:^\w+[-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$ 驗證InternetURL:^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$ ;^[a-zA-z]+://(w+(-w+)*)(.(w+(-w+)*))*(?S*)?$ 驗證電話號碼:^(\d3,4|\d{3,4}-)?\d{7,8}$:--正確格式為:XXXX-XXXXXXX,XXXX-XXXXXXXX,XXX-XXXXXXX,XXX-XXXXXXXX,XXXXXXX,XXXXXXXX。 驗證身份證號(15位或18位數(shù)字):^\d{15}|\d{}18$ 驗證一年的12個月:^(0?[1-9]|1[0-2])$ 正確格式為:“01”-“09”和“1”“12” 驗證一個月的31天:^((0?[1-9])|((1|2)[0-9])|30|31)$ 正確格式為:01、09和1、31。 整數(shù):^-?\d+$ 非負浮點數(shù)(正浮點數(shù) + 0):^\d+(\.\d+)?$ 正浮點數(shù) ^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$ 非正浮點數(shù)(負浮點數(shù) + 0) ^((-\d+(\.\d+)?)|(0+(\.0+)?))$ 負浮點數(shù) ^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$ 浮點數(shù) ^(-?\d+)(\.\d+)?$ */


