本文最初發表於 "博客園" ,併在 "GitHub" 上持續更新 前端的系列文章 。歡迎在GitHub上關註我,一起入門和進階前端。 以下是正文。 前言 JavaScript的組成 JavaScript基礎分為三個部分: ECMAScript:JavaScript的語法標準。包括變數、表達式、運算符 ...
以下是正文。
前言
JavaScript的組成
JavaScript基礎分為三個部分:
ECMAScript:JavaScript的語法標準。包括變數、表達式、運算符、函數、if語句、for語句等。
DOM:文檔對象模型,操作網頁上的元素的API。比如讓盒子移動、變色、輪播圖等。
BOM:瀏覽器對象模型,操作瀏覽器部分功能的API。比如讓瀏覽器自動滾動。
事件
JS是以事件驅動為核心的一門語言。
事件的三要素
事件的三要素:事件源、事件、事件驅動程式。
比如,我用手去按開關,燈亮了。這件事情里,事件源是:手。事件是:按開關。事件驅動程式是:燈的開和關。
再比如,網頁上彈出一個廣告,我點擊右上角的X
,廣告就關閉了。這件事情里,事件源是:X
。事件是:onclick。事件驅動程式是:廣告關閉了。
於是我們可以總結出:誰引發的後續事件,誰就是事件源。
總結如下:
事件源:引發後續事件的html標簽。
事件:js已經定義好了(見下圖)。
事件驅動程式:對樣式和html的操作。也就是DOM。
代碼書寫步驟如下:(重要)
(1)獲取事件源:document.getElementById(“box”); // 類似於Android裡面的findViewById
(2)綁定事件: 事件源box.事件onclick = function(){ 事件驅動程式 };
(3)書寫事件驅動程式:關於DOM的操作。
最簡單的代碼舉例:(點擊box1,然後彈框)
<body>
<div id="box1"></div>
<script type="text/javascript">
// 1、獲取事件源
var div = document.getElementById("box1");
// 2、綁定事件
div.onclick = function () {
// 3、書寫事件驅動程式
alert("我是彈出的內容");
}
</script>
</body>
常見的事件如下:
下麵針對這事件的三要素,進行分別介紹。
1、獲取事件源的方式(DOM節點的獲取)
獲取事件源的常見方式如下:
var div1 = document.getElementById("box1"); //方式一:通過id獲取單個標簽
var arr1 = document.getElementsByTagName("div1"); //方式二:通過 標簽名 獲得 標簽數組,所以有s
var arr2 = document.getElementsByClassName("hehe"); //方式三:通過 類名 獲得 標簽數組,所以有s
2、綁定事件的方式
方式一:直接綁定匿名函數
<div id="box1" ></div>
<script type="text/javascript">
var div1 = document.getElementById("box1");
//綁定事件的第一種方式
div1.onclick = function () {
alert("我是彈出的內容");
}
</script>
方式二:先單獨定義函數,再綁定
<div id="box1" ></div>
<script type="text/javascript">
var div1 = document.getElementById("box1");
//綁定事件的第二種方式
div1.onclick = fn; //註意,這裡是fn,不是fn()。fn()指的是返回值。
//單獨定義函數
function fn() {
alert("我是彈出的內容");
}
</script>
註意上方代碼的註釋。綁定的時候,是寫fn,不是寫fn()。fn代表的是整個函數,而fn()代表的是返回值。
方式三:行內綁定
<!--行內綁定-->
<div id="box1" onclick="fn()"></div>
<script type="text/javascript">
function fn() {
alert("我是彈出的內容");
}
</script>
註意第一行代碼,綁定時,是寫的"fn()"
,不是寫的"fn"
。因為綁定的這段代碼不是寫在js代碼里的,而是被識別成了字元串。
3、事件驅動程式
我們在上面是拿alert舉例,不僅如此,我們還可以操作標簽的屬性和樣式。舉例如下:
點擊滑鼠時,原本粉色的div變大了,背景變紅:
<style>
#box1 {
width: 100px;
height: 100px;
background-color: pink;
cursor: pointer;
}
</style>
</head>
<body>
<div id="box1" ></div>
<script type="text/javascript">
var div1 = document.getElementById("box1");
//點擊滑鼠時,原本粉色的div變大了,背景變紅了
div1.onclick = function () {
div1.style.width = "200px"; //屬性值要寫引號
div1.style.height = "200px";
div1.style.backgroundColor = "red"; //屬性名是backgroundColor,不是background-Color
}
</script>
上方代碼的註意事項:
- 在js里寫屬性值時,要用引號
- 在js里寫屬性名時,是
backgroundColor
,不是CSS裡面的background-Color
。
實現效果如下:
onload事件
onload事件比較特殊,這裡單獨講一下。
當頁面載入(文本和圖片)完畢的時候,觸發onload事件。
舉例:
<script type="text/javascript">
window.onload = function () {
console.log("smyhvae"); //等頁面載入完畢時,列印字元串
}
</script>
有一點我們要知道:js的載入是和html同步載入的。因此,如果使用元素在定義元素之前,容易報錯。這個時候,onload事件就能派上用場了,我們可以把使用元素的代碼放在onload里,就能保證這段代碼是最後執行。
建議是:整個頁面上所有元素載入完畢在執行js內容。所以,window.onload可以預防使用標簽在定義標簽之前。
事件舉例:京東頂部廣告欄
比如上面這張圖,當滑鼠點擊右上角的X
時,關掉整個廣告欄,這就要用到事件。
代碼實現如下:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
* {
padding: 0;
margin: 0;
}
.top-banner {
background-color: pink;
height: 80px;
}
.w {
width: 1210px;
margin: 10px auto;
position: relative;
}
img {
width: 1210px;
height: 80px;
background-color: blue;
}
a {
position: absolute;
top: 5px;
right: 5px;
color: #fff;
background-color: #000;
text-decoration: none;
width: 20px;
height: 20px;
font: 700 14px/20px "simsum";
text-align: center;
}
.hide {
display: none!important;
}
</style>
</head>
<body>
<div class="top-banner" id="topBanner">
<div class="w">
<img src="" alt=""/>
<a href="#" id="closeBanner">×</a>
</div>
</div>
<script>
//需求:點擊案例,隱藏盒子。
//思路:點擊a鏈接,讓top-banner這個盒子隱藏起來(加隱藏類名)。
//1.獲取事件源和相關元素
var closeBanner = document.getElementById("closeBanner");
var topBanner = document.getElementById("topBanner");
//2.綁定事件
closeBanner.onclick = function () {
//3.書寫事件驅動程式
//類控制
// topBanner.className += " hide"; //保留原類名,添加新類名
topBanner.className = "hide";//替換舊類名
// topBanner.style.display = "none";
}
</script>
</body>
</html>
註意最後一行代碼,這種方式會替換舊類名,意思是,不管之前的類名叫什麼,都會被修改。
事件舉例:
要求實現效果:當滑鼠懸停在img上時,更換為另外一張圖片;滑鼠離開時,還原為本來的圖片。
代碼實現:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<script>
//window.onload頁面載入完畢以後再執行此代碼
window.onload = function () {
//需求:滑鼠放到img上,更換為另一張圖片,也就是修改路徑(src的值)。
//步驟:
//1.獲取事件源
//2.綁定事件
//3.書寫事件驅動程式
//1.獲取事件源
var img = document.getElementById("box");
//2.綁定事件(懸停事件:滑鼠進入到事件源中立即出發事件)
img.onmouseover = function () {
//3.書寫事件驅動程式(修改src)
img.src = "image/jd2.png";
// this.src = "image/jd2.png";
}
//1.獲取事件源
var img = document.getElementById("box");
//2.綁定事件(懸停事件:滑鼠進入到事件源中立即出發事件)
img.onmouseout = function () {
//3.書寫事件驅動程式(修改src)
img.src = "image/jd1.png";
}
}
</script>
</head>
<body>
<img id="box" src="image/jd1.png" style="cursor: pointer;border: 1px solid #ccc;"/>
</body>
</html>
DOM的介紹
什麼是DOM
DOM:文檔對象模型。DOM 為文檔提供了結構化表示,並定義瞭如何通過腳本來訪問文檔結構。目的其實就是為了能讓js操作html元素而制定的一個規範。
DOM就是由節點組成的。
解析過程
HTML載入完畢,渲染引擎會在記憶體中把HTML文檔,生成一個DOM樹,getElementById是獲取內中DOM上的元素節點。然後操作的時候修改的是該元素的屬性。
DOM樹(一切都是節點)
DOM的數據結構如下:
上圖可知,在HTML當中,一切都是節點:(非常重要)
元素節點:HMTL標簽。
文本節點:標簽中的文字(比如標簽之間的空格、換行)
屬性節點::標簽的屬性。
整個html文檔就是一個文檔節點。所有的節點都是Object。
DOM可以做什麼
找對象(元素節點)
設置元素的屬性值
設置元素的樣式
動態創建和刪除元素
事件的觸發響應:事件源、事件、事件的驅動程式
DOM節點的獲取
DOM節點的獲取方式其實就是獲取事件源的方式,在上一段已經講到。這裡再重覆一下。
操作元素節點,必須首先找到該節點。有三種方式可以獲取DOM節點:
var div1 = document.getElementById("box1"); //方式一:通過id獲取單個標簽
var arr1 = document.getElementsByTagName("div1"); //方式二:通過 標簽名 獲得 標簽數組,所以有s
var arr2 = document.getElementsByClassName("hehe"); //方式三:通過 類名 獲得 標簽數組,所以有s
既然方式二、方式三獲取的是標簽數組,那麼習慣性是先遍歷之後再使用。
特殊情況:數組中的值只有1個。即便如此,這一個值也是包在數組裡的。這個值的獲取方式如下:
document.getElementsByTagName("div1")[0]; //取數組中的第一個元素
document.getElementsByClassName("hehe")[0]; //取數組中的第一個元素
DOM訪問關係的獲取
DOM的節點並不是孤立的,因此可以通過DOM節點之間的相對關係對它們進行訪問。如下:
節點的訪問關係,是以屬性的方式存在的。
JS中的父子兄訪問關係:
這裡我們要重點知道parentNode和children這兩個屬性的用法。下麵分別介紹。
獲取父節點
調用者就是節點。一個節點只有一個父節點,調用方式就是
節點.parentNode
獲取兄弟節點
1、下一個節點 | 下一個元素節點:
Sibling的中文是兄弟。
(1)nextSibling:
火狐、谷歌、IE9+版本:都指的是下一個節點(包括標簽、空文檔和換行節點)。
IE678版本:指下一個元素節點(標簽)。
(2)nextElementSibling:
- 火狐、谷歌、IE9+版本:都指的是下一個元素節點(標簽)。
總結:為了獲取下一個元素節點,我們可以這樣做:在IE678中用nextSibling,在火狐谷歌IE9+以後用nextElementSibling,於是,綜合這兩個屬性,可以這樣寫:
下一個兄弟節點 = 節點.nextElementSibling || 節點.nextSibling
2、前一個節點 | 前一個元素節點:
previous的中文是:前一個。
(1)previousSibling:
火狐、谷歌、IE9+版本:都指的是前一個節點(包括標簽、空文檔和換行節點)。
IE678版本:指前一個元素節點(標簽)。
(2)previousElementSibling:
- 火狐、谷歌、IE9+版本:都指的是前一個元素節點(標簽)。
總結:為了獲取前一個元素節點,我們可以這樣做:在IE678中用previousSibling,在火狐谷歌IE9+以後用previousElementSibling,於是,綜合這兩個屬性,可以這樣寫:
前一個兄弟節點 = 節點.previousElementSibling || 節點.previousSibling
3、補充:獲得任意一個兄弟節點:
節點自己.parentNode.children[index]; //隨意得到兄弟節點
獲取單個的子節點
1、第一個子節點 | 第一個子元素節點:
(1)firstChild:
火狐、谷歌、IE9+版本:都指的是第一個子節點(包括標簽、空文檔和換行節點)。
IE678版本:指第一個子元素節點(標簽)。
(2)firstElementChild:
- 火狐、谷歌、IE9+版本:都指的是第一個子元素節點(標簽)。
總結:為了獲取第一個子元素節點,我們可以這樣做:在IE678中用firstChild,在火狐谷歌IE9+以後用firstElementChild,於是,綜合這兩個屬性,可以這樣寫:
第一個子元素節點 = 節點.firstElementChild || 節點.firstChild
2、最後一個子節點 | 最後一個子元素節點:
(1)lastChild:
火狐、谷歌、IE9+版本:都指的是最後一個子節點(包括標簽、空文檔和換行節點)。
IE678版本:指最後一個子元素節點(標簽)。
(2)lastElementChild:
- 火狐、谷歌、IE9+版本:都指的是最後一個子元素節點(標簽)。
總結:為了獲取最後一個子元素節點,我們可以這樣做:在IE678中用lastChild,在火狐谷歌IE9+以後用lastElementChild,於是,綜合這兩個屬性,可以這樣寫:
最後一個子元素節點 = 節點.lastElementChild || 節點.lastChild
獲取所有的子節點
(1)childNodes:標準屬性。返回的是指定元素的子節點的集合(包括元素節點、所有屬性、文本節點)。是W3C的親兒子。
- 火狐 谷歌等高本版會把換行也看做是子節點。
用法:
子節點數組 = 父節點.childNodes; //獲取所有節點。
(2)children:非標準屬性。返回的是指定元素的子元素節點的集合。【重要】
- 它只返回HTML節點,甚至不返迴文本節點。
- 在IE6/7/8中包含註釋節點(在IE678中,註釋節點不要寫在裡面)。
雖然不是標準的DOM屬性,但它和innerHTML方法一樣,得到了幾乎所有瀏覽器的支持。
用法:(用的最多)
子節點數組 = 父節點.children; //獲取所有節點。用的最多。
nodeType
這裡講一下nodeType。
nodeType == 1 表示的是元素節點(標簽) 。記住:元素就是標簽。
nodeType == 2 表示是屬性節點 瞭解
nodeType == 3 是文本節點 瞭解
DOM節點操作(重要)
上一段的內容:節點的訪問關係都是屬性。
本段的內容:節點的操作都是函數(方法)。
創建節點
格式如下:
新的標簽(元素節點) = document.createElement("標簽名");
比如,如果我們想創建一個li標簽,或者是創建一個不存在的adbc標簽,可以這樣做:
<script type="text/javascript">
var a1 = document.createElement("li"); //創建一個li標簽
var a2 = document.createElement("adbc"); //創建一個不存在的標簽
console.log(a1);
console.log(a2);
console.log(typeof a1);
console.log(typeof a2);
</script>
列印結果:
插入節點
插入節點有兩種方式,它們的含義是不同的。
方式1:
父節點.appendChild(新的子節點);
解釋:父節點的最後插入一個新的子節點。
方式2:
父節點.insertBefore(新的子節點,作為參考的子節點)
解釋:
- 在參考節點前插入一個新的節點。
- 如果參考節點為null,那麼他將在父節點最後插入一個子節點。
我們可以看到,li標簽確實被插入到了box1標簽的裡面,和box2併列了。
方式2的舉例:
我們可以看到,b1標簽被插入到了box1標簽的裡面,和a1標簽併列,在a1標簽的前面。
刪除節點
格式如下:
父節點.removeChild(子節點);
解釋:用父節點刪除子節點。必須要指定是刪除哪個子節點。
如果我想刪除自己這個節點,可以這麼做:
node1.parentNode.removeChild(node1);
複製節點(克隆節點)
格式如下:
要複製的節點.cloneNode(); //括弧里不帶參數和帶參數false,效果是一樣的。
要複製的節點.cloneNode(true);
括弧裡帶不帶參數,效果是不同的。解釋如下:
不帶參數/帶參數false:只複製節點本身,不複製子節點。
帶參數true:既複製節點本身,也複製其所有的子節點。
設置節點的屬性
我們可以獲取節點的屬性值、設置節點的屬性值、刪除節點的屬性。
我們就統一拿下麵這個標簽來舉例:
<img src="images/1.jpg" class="image-box" title="美女圖片" alt="地鐵一瞥" id="a1">
下麵分別介紹。
1、獲取節點的屬性值
方式1:
元素節點.屬性;
元素節點[屬性];
舉例:(獲取節點的屬性值)
<body>
<img src="images/1.jpg" class="image-box" title="美女圖片" alt="地鐵一瞥" id="a1">
<script type="text/javascript">
var myNode = document.getElementsByTagName("img")[0];
console.log(myNode.src);
console.log(myNode.className); //註意,是className,不是class
console.log(myNode.title);
console.log("------------");
console.log(myNode["src"]);
console.log(myNode["className"]); //註意,是className,不是class
console.log(myNode["title"]);
</script>
</body>
上方代碼中的img標簽,有各種屬性,我們可以逐一獲取,列印結果如下:
方式2:(推薦)
元素節點.getAttribute("屬性名稱");
舉例:
console.log(myNode.getAttribute("src"));
console.log(myNode.getAttribute("class")); //註意是class,不是className
console.log(myNode.getAttribute("title"));
列印結果:
方式1和方式2的區別在於:前者是直接操作標簽,後者是把標簽作為DOM節點。推薦方式2。
2、設置節點的屬性值
方式1舉例:(設置節點的屬性值)
myNode.src = "images/2.jpg" //修改src的屬性值
myNode.className = "image2-box"; //修改class的name
方式2:(推薦)
元素節點.setAttribute(屬性名, 新的屬性值);
方式2舉例:(設置節點的屬性值)
myNode.setAttribute("src","images/3.jpg");
myNode.setAttribute("class","image3-box");
myNode.setAttribute("id","你好");
3、刪除節點的屬性
格式:
元素節點.removeAttribute(屬性名);
舉例:(刪除節點的屬性)
myNode.removeAttribute("class");
myNode.removeAttribute("id");
我的公眾號
想學習代碼之外的軟技能?不妨關註我的微信公眾號:生命團隊(id:vitateam
)。
掃一掃,你將發現另一個全新的世界,而這將是一場美麗的意外: