前端點滴(JS基礎)(六)----傾盡所有
HTML DOM 操作
1. 屬性節點的操作
(1)查詢元素的屬性
屬性不能單獨存在,一定屬於一個標籤。所有,操作屬性,前提必須找到標籤。
語法 | 描述 | 特點 | 支持 |
---|---|---|---|
元素節點.attributes | 獲取元素的所有屬性 | - | 所有瀏覽器 |
元素節點.getAttribute(屬性名) | 獲取指定屬性的值 | 標準的獲取已經存在的屬性值的方法 | 所有瀏覽器 |
元素節點.屬性名 | 獲取指定屬性的值 | 獲取不存在的屬性值時比較好用,能夠獲取類似於readOnly、checked等屬性 | 所有瀏覽器 |
實例:
<script>
var input = document.getElementById('input');
/* 元素節點.attributes */
console.log(input.attributes);
// NamedNodeMap {0: type, 1: id, 2: readonly, type: type, id: id, readonly: readonly, length: 3}
console.log(input.attributes.length); // 3
/* 元素節點.getAttribute(屬性名) */
console.log(input.getAttribute('type')); //=> text
console.log(input.getAttribute('readOnly')); //=> null
/* 元素節點.屬性名 */
console.log(input.type); //=> text
console.log(input.readOnly); //=> true
</script>
(2)添加/修改元素的屬性
語法 | 描述 | 特點 | 支持 |
---|---|---|---|
元素節點.setAttribute(屬性名,屬性值) | 設置(添加/修改)元素的所有屬性 | 屬性不存在表示添加,屬性存在表示修改 | 所有瀏覽器 |
元素節點.屬性名 = 值 | 設置(添加/修改)元素的所有屬性 | 屬性不存在表示添加,屬性存在表示修改 | 所有瀏覽器 |
實例:
/* 設置元素屬性 */
input.setAttribute("value","yaodao");
input.value = "yaodao"
/* 修改元素屬性 */
input.setAttribute("name","text2");
input.name = "text2"
效果:
(設置前):
(設置後):
(3)刪除元素的屬性
/* 刪除元素屬性 */
input.removeAttribute("value")
(4)判斷元素是否有哪個屬性
語法:標籤節點.hasAttribute("屬性名")
注意: 返回Boolean類型的值。
/* 判斷是否存在元素屬性 */
console.log(input.hasAttribute("value")); //=> false
console.log(input.hasAttribute("name")); //=> true
總結
元素節點的增刪改查:
- 增:document.creatElement(“標籤名”); document.creatTextNode(“文本”); 父節點.appendChild(子節點); 父節點.insertBefore(新節點,參照節點)
- 刪:父節點.removeChild(子節點);
- 改:父節點.replaceChild(新節點,參照節點)
- 查:document.getElementById(“元素id”); document.getElementsByTagName(“標籤名”); document.getElementsByClassName(“類名”);document.getElementsByName(“元素的name屬性”);document.querySelector(“css選擇器”);document.querySelectorAll(“css選擇器”)
屬性節點的增刪改查:
- 增:元素節點.setAttribute(“屬性名”,“屬性值”); 元素節點.屬性名 = “屬性值”;
- 刪:元素節點.removeAttribute(“屬性名”);
- 改:元素節點.setAttribute(“屬性名”,“屬性值”); 元素節點.屬性名 = “屬性值”;
- 查:元素節點.attributes; 元素節點.getAttribute(“屬性名”); 元素節點.屬性名;
2. DOM 對象的通用屬性
innerHTML
- 獲取/設置元素裏的html內容
innerText
- 獲取/設置元素裏面的文本內容
nodeName
- nodeName 是隻讀的
元素節點的 nodeName 與標籤名相同
屬性節點的 nodeName 與屬性名相同
文本節點的 nodeName 始終是 #text
文檔節點的 nodeName 始終是 #document
nodeValue
- 元素節點的 nodeValue 是 undefined 或 null
- 文本節點的 nodeValue 是文本本身
- 屬性節點的 nodeValue 是屬性值
nodeType
調用nodeType屬性會得到一個數字,這個數字表示節點的類型
- 元素 1
- 屬性 2
- 文本 3
- 註釋 8
- 文檔 9
實例:
<script type="text/javascript">
var p = document.getElementById('p');
//innerHTML,innerText
/* 獲取元素裏的html內容 */
console.log(p.innerHTML); //=> 123<span>456</span>
/* 獲取元素裏的文本內容 */
console.log(p.innerText); //=> 123456
/* 設置元素中的html內容 */
p.innerHTML = '<a href="#">按鈕</a>';
/* 設置元素裏的文本內容 */
p.innerText = '這是innerText後的文本';
// nodeName
/* 獲取元素節點的nodeName */
console.log(p.nodeName); //=> p
/* 獲取屬性節點的nodeName */
console.log(p.getAttributeNode("id").nodeName); //=> id
// nodeValue
/* 獲取元素節點的nodeValue */
console.log(p.nodeValue); //=> undefined
console.log(p.getAttributeNode("id").nodeValue); //=> p
// nodeType
/* 獲取元素節點的nodeType */
console.log(p.nodeType); //=> 1
/* 獲取屬性節點的nodeType */
console.log(p.getAttributeNode("id").nodeType); //=> 2
/* 獲取文本節點的nodeType */
console.log(p.childNodes[0].nodeType); //=> 3
/* 獲取文檔的nodeType */
console.log(document.nodeType); //=> 9
</script>
3. 設置/獲取元素的css樣式
(1)設置樣式
語法: elementNode.style.css樣式 = 值
css樣式的寫法:
①、一個單詞的直接寫即可。比如color height …
②、樣式名稱帶中橫線的,去掉中橫線,後面單詞首字母大寫。比如fontSize lineHeight backgroundColor
實例:
(2)獲取樣式
使用 " elementNode.style.樣式名稱
" 的方式只能獲取行內樣式和js已經設置過的樣式。
要想獲取全部的樣式,則必須使用下面的方法:
- 在IE中支持
elementNode.currentStyle.樣式名稱
- 火狐支持
getComputedStyle(elementNode).樣式
爲了兼容各個瀏覽器,所以需要自己封裝一個函數,用於獲取完整的css樣式:
function getStyle(el,style){
// IE 支持類型
if(el.currentStyle){
return el.currentStyle[style]
}else{
// 火狐支持類型
return getComputedStyle(el)[style]
}
}
console.log(getStyle(p,'fontSize'))
調用 getStyle() 獲取完整的樣式。
注意: 樣式名有需要地使用駝峯命名法,並且以字符串的方式參入參數。
4. DOM獲取元素的位置
靜態元素位置屬性:
- offsetLeft 元素在網頁中水平座標值
- offsetTop 元素在網頁中垂直座標值
- offsetWidth 元素在頁面中佔據的寬度
- offsetHeight 元素在頁面中佔據的高度
注意: 當前offsetWidth = width+padding+border。
注意: 當前offsetLeft = margin-left。
注意: 當前offsetTop = margin-top。
動態元素位置屬性:
- scrollLeft 滾動條在容器中水平滾動的距離,多用於瀏覽器的滾動條
- scrollTop 滾動條在容器中垂直滾動的距離,多用於瀏覽器的滾動條
間歇滾動實現案例:
// <ul id="Dong"> 關鍵是css中設置 overflow:hidden;
var Dong = document.getElementById("Dong");
Dong.innerHTML += Dong.innerHTML;
var iLiHeight = 45; //設置滾動行高
Dong.scrollTop = 0; //初始化
var tim;
function moving() {
Dong.scrollTop++;
tim = setInterval(scrollUp, 30);
}
function scrollUp() {
if (Dong.scrollTop % iLiHeight ==0) {
clearInterval(tim);
setTimeout(moving, 3000)
}
else {
Dong.scrollTop++;
if (Dong.scrollTop >= Dong.scrollHeight/2) {
Dong.scrollTop =0;
}
}
}
setTimeout(moving,3000);
})
5. 事件和事件對象
(1)什麼是事件
瀏覽網頁時,當我們做出點擊鼠標、按鍵盤、移動鼠標等行爲時,這些行爲會被瀏覽器內置的JavaScript引擎所捕獲,並執行對應的某些操作(函數)。那麼你的行爲(動作)+ JavaScript引擎捕獲 + 執行對應的操作 = 事件
。
所以,一個完整的事件應該包括:
- 用戶行爲;
- 瀏覽器捕獲你的行爲;
- 執行對應的操作(函數)
常見行爲有:鼠標點擊、鼠標的移動、鼠標的移入和移出、鍵盤控制等等。
事件的作用是:通過事件,我們(瀏覽網頁的人)就可以和瀏覽器進行一些交互了。
(2)事件綁定的多種方式
聲明: 如果同時存在標籤事件,DOM方法綁定的事件。優先執行DOM方式綁定的事件。
1、on() 綁定事件
語法:elementNode.on('不帶on的常用事件名',function(){})
實例:
document.getElementById('btn').on('click', function () {
alert(123);
});
2、事件名綁定事件
語法:elementNode.帶有on的常用事件名 = function(){}
實例:
document.getElementById('btn').onclick = function () {
alert(123);
};
3、事件監聽綁定事件
事件監聽的方法有兩種:
- addEventListener——兼容:firefox、chrome、IE、safari、opera;不兼容IE7、IE8
- attachEvent——兼容:IE7、IE8;不兼容firefox、chrome、IE9、IE10、IE11、safari、opera
addEventListener() 語法: elementNode.addEventListener(event, function, useCapture)
注意: useCapture (可選)布爾值,指定事件是否在捕獲或冒泡階段執行。【true:事件句柄在捕獲階段執行; false:默認,事件句柄在冒泡階段執行】,需要了解事件發生過程:事件捕獲----處於目標----事件冒泡
attachEvent() 語法: elementNode.attachEvent(event, function)
共性與區別:
相同點:
都是dom對象的方法,可以實現一種事件綁定多個事件處理函數。
不同點:
-
attachEvent是IE有的方法,它不遵循W3C標準,而其他的主流瀏覽器如FF等遵循W3C標準的瀏覽器都使用addEventListener,所以實際開發中需分開處理。
-
多次綁定後執行的順序是不一樣的,attachEvent是後綁定先執行(覆蓋),addEventListener是先綁定先執行(不會覆蓋)。
-
存在兼容問題,綁定事件名方法不同,addEventListener() 方法的event參數不用帶on ,attachEvent() 方法中的event 參數需要帶on。
同樣爲了兼容各個瀏覽器,所以需要自己封裝一個函數,用於監聽事件:
var btn = document.getElementById('btn');
function listenFn(el,type,fn){
if(window.addEventListener){
return el.addEventListener(type,fn);
}else{
return el.attachEvent('on'+type,fn)
}
};
function fn(){
alert(123);
};
function fn2(){
alert(456);
};
// ...
listenFn(btn,'click',fn);
listenFn(btn,'click',fn2);
// ... 還可以綁定多個事件
效果:
事件監聽的第三個參數說明:
addEventListener第三個參數涉及到的事件捕獲與冒泡。
<style>
#div1{
width: 200px;
height: 200px;
background-color: red;
}
#div2{
width: 100px;
height: 100px;
background-color: green;
}
</style>
<div id="div1" >
<div id="div2">
<button id="btn">按鈕</button>
</div>
</div>
<script type="text/javascript">
window.onload=function(){
document.getElementById("btn").addEventListener("click",function () {
// body...
alert("hello");
});
document.getElementById("div2").addEventListener("click",function(){
alert("div2");
},true);
document.getElementById("div1").addEventListener("click",function(){
alert("div1");
});
}
</script>
效果:
說明:
- 默認情況下addEventListener() 的第三個參數爲false/不填,表示元素觸發事件在冒泡階段 事件流:btn事件 -> div2事件 -> div1事件。
當處於目標div2 時元素觸發事件,事件就會逐層向上冒泡 div1事件 -> div2事件;當處於目標btn 時元素觸發事件,事件同樣會逐層向上冒泡div1事件 -> div2事件 -> btn事件。
- 非默認情況下addEventListener() 的第三個參數爲true,表示元素觸發事件在捕獲階段 事件流:div1事件 -> div2事件 -> btn事件。
當處於目標div2 時元素觸發事件,事件會根據捕獲階段的事件流,先觸發div2事件,再經過冒泡階段觸發div1事件。當處於目標btn 時,由於div2 addEventListener() 的第三個參數爲true,在捕獲階段觸發。所以先觸發div2事件,再觸發btn事件,最後觸發div1事件。
- 不過要注意一點:不要因爲捕獲而忽略冒泡。
4、標籤中綁定事件
直接在標籤中添加事件,例如:
<input type="button" value="按鈕" id="btn" onclick="fn2()">
function fn2(){
alert(456);
}
5、實例說明
<input type="text" id="username" value="請輸入用戶名" />
<script>
//找到username,綁定獲取焦點事件
document.getElementById('username').onfocus = function () {
document.getElementById('username').value = '';
};
//優化
document.getElementById('username').onfocus = function () {
this.value = '';
};
</script>
在事件處理函數中,this表示綁定事件的那個元素
HTML代碼:
<!- 要求:頁面中有很多個td,點擊td的時候,讓td的背景顏色發生變化 ->
<table>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
</table>
css代碼:
<style>
table,td{
border:solid 1px #ccc;
border-collapse: collapse; /*合併邊框*/
}
td{
width:150px;
height:50px;
}
table{
margin:10px auto; /*讓表格左右居中對齊*/
}
</style>
JS代碼:
<script>
//點擊頁面中的td,點擊之後,讓被點擊的td背景顏色改變成隨機顏色
//先找到所有的td
var tds = document.getElementsByTagName('td'); // 返回數組
//循環,爲每個td都綁定一個單擊事件
for(var i=0; i<tds.length; i++){
tds[i].onclick = function () {
//this 表示綁定事件的那個td
var r = Math.floor(Math.random()*256);
var g = Math.floor(Math.random()*256);
var b = Math.floor(Math.random()*256);
this.style.backgroundColor = 'rgb('+r+', '+g+', '+b+')';
//全變紅色
/*if(this.style.backgroundColor != 'red'){
this.style.backgroundColor = 'red';
}else{
this.style.backgroundColor = 'white';
}*/
};
}
</script>
效果:
(3)常用的事件名
- 頁面事件:
- onload :當頁面載入完畢(頁面中的標籤和外部資源)後觸發
- 焦點事件:
- onfocus :當獲取焦點時觸發
- onblur :當失去焦點時觸發
- 鼠標事件:
- onmouseover :當鼠標懸浮時觸發
- onmouseout :當鼠標離開時觸發
- 鍵盤事件:
- onkeypress :當鍵盤按下時觸發(如果按住某個鍵不鬆開,會一直觸發press事件)
- onkeydown :當鍵盤按下時觸發
- onkeyup :當鍵盤彈起時觸發
- 其他事件:
- onchange :內容改變時會觸發,常用於select>option。
- onsubmit :表單提交時觸發,這個事件要給form綁定而不是給提交按鈕綁定
- onresize : 頁面窗口改變大小時會觸發
- onscroll :滾動條滾動時觸發
(4)什麼是事件對象
事件對象也是一個對象,它提供了一些屬性,這些屬性描述了當前事件的特點;
不同的事件中,事件對象也有所差異,比如單擊事件中,事件對象會提供pageX和pageY屬性,表示點擊的點距離頁面的距離,比如鍵盤事件中,事件對象會提供keyCode屬性,表示按的是什麼鍵。
總之,事件對象中提供了一些屬性,這些屬性可以很好的描述當前的事件的特點。
(5)獲取事件對象
IE 瀏覽器:window.event;
主流瀏覽器:傳遞給事件函數的參數。
同樣的爲了兼容各個瀏覽器,兼容各個瀏覽器的獲取事件對象的方法:
document.getElementsByTagName('input')[0].onclick = function(a){
if(window.event){
e = window.event;
}else{
e = a;
}
// 簡寫
var e = window.event||a;
}
(6)事件對象的常用屬性
下面列舉一些事件對象中的常用屬性:
- target:返回觸發此事件的元素(事件的目標節點)。
- currentTarget:返回其事件監聽器觸發該事件的元素。
- keyCode:表示鍵盤上的鍵對應的數值。
- altKey:表示是否按了alt鍵,按了結果爲true,沒按結果爲false(組合按鍵的時候,纔會有作用)
- shiftKey:表示是否按了shift鍵,按了結果爲true,沒按結果爲false(組合按鍵的時候,纔會有作用)
- ctrlKey:表示是否按了ctrl鍵,按了結果爲true,沒按結果爲false(組合按鍵的時候,纔會有作用)
- pageX: 鼠標距離頁面左邊的距離
- pageY: 鼠標距離頁面上面的距離
- screenX: 鼠標距離屏幕左邊的距離
- screenY: 鼠標距離屏幕上面的距離
實例:
(7)事件對象的方法
stopPropagation() 阻止冒泡事件的發生。
1. 什麼是冒泡事件?
上述小例子中,點擊元素的子元素,會透過子元素觸發元素本身的事件,這就是冒泡事件。
首先,要清楚什麼是事件流?
事件流:
當一個HTML元素產生一個事件時,該事件會在元素節點與根節點之間的路徑傳播,路徑所經過的節點都會收到該事件,這個傳播的過程叫做DOM事件流。
元素觸發事件時,事件的傳播過程稱爲事件流,過程分爲捕獲和冒泡兩種:
冒泡事件: 微軟提出的 事件由子元素傳遞到父元素的過程,叫做冒泡
捕獲事件: 網景提出的 事件由父元素到子元素傳遞的過程,叫做事件捕獲
有些時候要的就是這個效果,可以不做任何處理;有些時候不希望有冒泡事件發生,那麼可以通過事件對象的方法來阻止冒泡的發生。
2. 阻止冒泡事件的發生
阻止冒泡事件的發生有:
- 標準瀏覽器使用 evt.stopPropagation(); //evt指的是事件對象
- IE內核瀏覽器使用 window.event.cancelBubble = true;
可以封裝一個兼容各個瀏覽器的阻止冒泡的方法:
<script>
/*************** 阻止冒泡函數 *************/
function zuzhi(evt){
if(window.event){
window.event.cancelBubble = true;
}else{
evt.stopPropagation(); //evt指的是事件對象
}
}
//分別給兩個div綁定單擊事件
document.getElementById('d1').onclick = function () {
alert(11111);
};
document.getElementById('d2').onclick = function (evt) {
alert(22222);
//阻止冒泡發生
zuzhi(evt); // 此處會阻止11111的彈出
};
</script>
preventDefault() 阻止標籤的默認行爲。
默認行爲就是html標籤的一些默認行爲,比如點擊a標籤會跳轉,比如點擊了submit按鈕表單會提交。這些都屬於標籤的默認行爲。
有些時候,點擊了a標籤或者submit按鈕後不希望執行標籤的默認行爲,這時候就需要阻止默認行爲。
阻止默認行爲:
標準瀏覽器:evt.preventDefault();
IE內核瀏覽器:window.event.returnValue = false;
兼容各個瀏覽器的阻止標籤默認行爲的方法:
<body>
<a href="13冒泡事件.html">跳轉</a>
<form name="f1" action="07全選.html" method="post">
用戶名:<input type="text" name="username"><br>
密 碼:<input type="password" name="pwd"><br>
<input type="submit" id="sub" value="提交">
</form>
<script>
/********* 阻止標籤的默認行爲 *********/
//形參evt標籤標準瀏覽器的事件對象
function zuzhi(evt){
if(window.event){
//IE瀏覽器
window.event.returnValue = false;
}else{
//非IE瀏覽器
evt.preventDefault();
}
}
document.getElementById('sub').onclick = function (evt) {
//檢測用戶名是否爲空
if(document.f1.username.value == ''){
alert('用戶名不能爲空');
//阻止表單提交
zuzhi(evt);
//return false; //return false也可以阻止表單提交
}
};
</script>
注意: return false 同樣可以阻止默認行爲。
綜合案例----可編輯表格
HTML:
<table>
<thead>
<tr>
<th>ID</th>
<th>姓名</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>唐僧</td>
</tr>
<tr>
<td>2</td>
<td>悟空</td>
</tr>
<tr>
<td>3</td>
<td>八戒</td>
</tr>
<tr>
<td>4</td>
<td>沙僧</td>
</tr>
<tr>
<td>5</td>
<td>白龍馬</td>
</tr>
<tr>
<td>6</td>
<td>金箍棒</td>
</tr>
</tbody>
</table>
css:
<style>
*{
margin:0;
padding:0;
border:0 none;
}
table,th,td{
border:solid 1px #1b272e;
border-collapse: collapse; /*合併邊框*/
}
table{
width:400px;
margin:10px auto; /*左右居中對齊*/
}
th,td{
width:50%;
padding:3px;
}
</style>
js:
/* 要求:隔行換色,姓名可修改,且點擊姓名後自動變成 value爲原有值的 input 並且寬高與 td 一致,綁定回車與esc鍵盤事件 */
//兼容各個瀏覽器的獲取完整css樣式的寫法
function getStyle(node, styleName){
if(node.currentStyle){
//說明是IE
return node.currentStyle[styleName];
}else{
return getComputedStyle(node)[styleName];
}
}
// 隔行換色
// 找到所有的 tr 進行遍歷,如果遍歷的 i 能夠整除2,就改變顏色。
var trs = document.querySelectorAll('tbody tr');
for(var i = 0;i<trs.length;i++){
if(i%2 == 0){
trs[i].style.backgroundColor = '#d4d4d4';
}
}
//獲取姓名td
var tds = document.querySelectorAll('tbody td:nth-child(2n)');
//循環遍歷給每個姓名td綁定單擊事件
for(var i = 0;i<tds.length;i++){
tds[i].onclick = function(){
//將每一個td賦值給變量td進行操作,避免改變原有數據
var td = this; //this表示點擊事件的對象td[i]
var text = td.innerText;
td.innerHTML = '';
//創建input框
var input = document.createElement('input');
//設置樣式
input.style.width = getStyle(td,"width");
input.style.height = getStyle(td,"height");
input.style.backgroundColor = getStyle(td,"backgroundColor");
input.style.fontSize = getStyle(td,"fontSize");
input.style.outline= "none";
//將保存的td文本賦值給input.value
input.value = text;
//在td中加入設置好的input框
td.appendChild(input);
//獲取焦點
input.focus();
//綁定鍵盤事件,enter成功設置,esc取消設置(恢復原形)。
input.onkeyup = function (evt) {
var e = window.event||evt;
var keyCode = e.keyCode;
if(keyCode == 13){ //表示按了回車,表示確定
td.innerHTML = ''; //先清空td中的input
td.innerHTML = this.value;
}
if(keyCode == 27){ //按ESC鍵表示取消
td.innerHTML = ''; //先清空td中的input
td.innerHTML = text;
}
};
}
}
效果: