DOM一些優化/簡寫與編程技巧

不需要查找可直接獲得的節點

document.documentElement ->html

document.head ->head

document.body ->body

document.forms[id/i]每個表單元素 返回數組

添加和刪除

優化方式:儘量減少操作DOM樹的次數

爲什麼要優化:

    首先HTML的加載原理:

        1、下載HTML

        2、解析HTML爲DOM樹

        3、將CSS解析爲COM

        4、他們結合爲一個Rander Tree,渲染樹用來描述所有的可見的DOM內容,並將CSSOM添加到節點上

這個時候,當修改DOM樹任何一處的時候就需要重新渲染,會非常影響效率

那麼,如何進行優化?

    1、如果同時添加父元素和子元素的情況下:

        那麼,應該在內存中,先將所有子元素添加到父元素中,最後一次性的將父元素添加到DOM樹

    2、如果父元素已經在頁面上,需要添加多個平級的子元素的情況下:

        應該使用文檔片段

    什麼是文檔片段:

        即內存中,臨時保存多個平級子元素的虛擬父元素對象

    何時使用:

        需要添加多個平級子元素的時候

     如何使用:

        分3步:

                1、創建文檔片段:

                    var frag = document.createDocumentFragment();

                2、將子元素添加到文檔片段中

                     frag.appendChild(child)

                3、將文檔片段一次性添加到父元素上

                    parent.appendChild(frag);

        強調:frag將子元素添加到頁面後,frag自動釋放

具體實例:

<title>二級聯動列表</title>
<meta charset="utf-8" />
<style>
	.hide{ display: none; }
</style>


</head>
<body>
	<select name="provs">
		<option>—請選擇—</option><!--0-->	<!--技巧1:避免誤操作-->
		<option>北京市</option><!--1-->
		<option>天津市</option>
		<option>河北省</option>
	</select>
	
	<select name="cities" class="hide"><!--技巧2:用innerHTML情況兩個標籤之間的所有子元素-->
	</select>
  <script>
	/*實現“省”和“市”的級聯下拉列表*/
	var cities=[
      [{"name":'東城區',"value":101},
       {"name":'西城區',"value":102},
       {"name":'海淀區',"value":103},
       {"name":'朝陽區',"value":104}],
      [{"name":'河東區',"value":201},
       {"name":'河西區',"value":202},
       {"name":'南開區',"value":303}],
      [{"name":'石家莊市',"value":301},
       {"name":'廊坊市',"value":302},
       {"name":'保定市',"value":303},
       {"name":'唐山市',"value":304},
       {"name":'秦皇島市',"value":304}]
	   ];
var selProvs = document.getElementsByName("provs")[0];
var selCts = document.getElementsByName("cities")[0];
selProvs.onchange =function(){
	var i = this.selectedIndex;
		if(i == 0){
			selCts.className = "hide";
		}else{
			selCts.innerHTML = "";
			var cts = cities[i-1];
			var frag = document.createDocumentFragment();
			frag.appendChild(new Option("-請選擇-"));	//新方法創建option	
		for(var city of cts){
				frag.appendChild(new Option(city.name));	//新方法創建option
		}
			selCts.appendChild(frag);
			selCts.className = "";
	}
	}
	//使用的優化方式:當子元素擁有同一個相同的父元素時,可以先將子元素加入虛擬父元素frag中,再
	//將frag添加到真正父元素下,即能把所有子元素一次性添加到真正父元素中,減少layout次數,frag使
	//用完成後自動釋放
</script>

  要點:

    1、在select中定義事件需要使用onchange事件,因爲會根據option的改變更觸發

    2、selectedIndex意爲獲取當前選擇option的位置

    3、使用hide樣式控制隱藏

    4、這裏的cites[i-1]是因爲存在一個option爲請選擇,如果不用i-1就會錯位

    5、通過innerHTML可以控制select中的option

    6、新方法簡便創建option:parent.appendChild(new Option(text,value))

    7、定義虛擬父對象frag省去很多創建元素,插入元素的麻煩,增加了渲染速度

如何刪除子對象:

            parent.removeChild(child)

            child.parentNode.removeChild(child)

HTML DOM常用對象,簡化創建

    1、select/option

        常用屬性:value              當前選中項的value

                        selectedIndex 當前選中項的下標

                        options           獲得select下所有option的集合

                        length            相當於.options.length 獲得option的個數

                        清空option:.length = 0

    事件:onchange 當前選中項發生改變時

    方法:

        Option 創建:var opt = new Option(text,value)

        屬性:text,value,index

    2、table

        簡單的創建方法:代替document.createElement

        var thead = .createTHead()

        var tbody = .createTBody()

        var tfoot  = .createTFoot()

        刪除:.deleteTHead()

        .deleteTFoot()

        獲取:.tHead()

        .Bodies[i] 因爲一個表格中可能有很多tbody

        .tFoot

    行分組:

        1、創建行 var tr =.insertRow(i)

        固定套路:

            1、末尾追加一行:insertRow()

            2、開頭插入一行:insertRow(0)

    刪除行:

            .deleteRow(i) 

    問題:i無法自動獲得

    解決:刪除tr的時候首選table.deleteRow(tr.rowIndex)rowIndex是記錄tr在整個表中的位置

    獲取:.rows

tr

    創建:var td = parent.insertCell(i)

    固定用法:末尾追加新格 var td = tr.insertCell()

    強調:只能創建td,不能創建th,可以通過樣式設置

    刪除:.deleteCell(i)

    獲取:.cell

刪除行

    行分組.deleteRow(i) i是相對於當前行分組內的位置

    table.deleteRow(tr.rowIndex) rowIndex是相對於整個表中的位置

    實例:

    

<style>
	table{width:600px; border-collapse:collapse;
		text-align:center;
	}
	td,th{border:1px solid #ccc}
	thead > tr >td{font-weight:bold;}
</style>
</head>
<body>
<div id="data"></div>
  <script>
var json=[
    {"ename":"Tom", "salary":11000, "age":25},
    {"ename":"John", "salary":13000, "age":28},
    {"ename":"Mary", "salary":12000, "age":25}
];
//創建一個table
var table=document.createElement("table");
//創建thead
//將thead追加到table下
var thead = table.createTHead();    //簡寫
//創建tr
//將tr追加到thead下
var tr=thead.insertRow();//新的DOM常用對象行分組寫法,減少代碼量 var tr = 行分組.insertRow()
//遍歷json數組中第一個對象的每個key
for(var key in json[0]){
//創建th      
//設置th的內容爲key
//將th添加到tr下
tr.insertCell().innerHTML = key;//技巧 鏈式操作tr.insertCell()返回一個td
}
tr.insertCell().innerHTML = "opr";
//創建tbody
//將tbody追加到table
var tbody=table.createTBody();		
//遍歷json中每個員工
for(var emp of json){
//創建tr
//將tr追加到tbody中
var  tr = tbody.insertRow();//新的DOM常用對象行分組寫法,減少代碼量 var tr = 行分組.insertRow()
//遍歷當前員工的每個屬性
for(var key in emp){
//創建td
tr.insertCell().innerHTML = emp[key];
/*var td=
document.createElement("td");
//設置td的內容爲key對應的屬性值
td.innerHTML=json[i][key];
//將td追加到tr中
tr.appendChild(td);*/
}
/*格中放一個按鈕,名爲刪除*/
var btn = document.createElement("button");
btn.textContent = "刪除";
btn.onclick = function(){
var tr = this.parentNode.parentNode;	/*技巧:影響數據的操作需要確認*/
//寫確認
/*var ename = this.parentNode.previousSibling.previousSibling.previousSibling.textContent;*/
var ename = tr.cells[0].innerHTML; 
console.log(ename);
if(confirm(`是否繼續刪除${ename}?`) == true){
table.deleteRow(tr.rowIndex);}
else{
alert("刪除失敗");
}
}
tr.insertCell().appendChild(btn);
}
    //將table追加到id爲data的div下 DOM優化的一種方式,將所有的需要添加到父元素的子元素修改完成後統一添加到父元素中,減少layout
    var div=
      document.getElementById("data");
    div.appendChild(table);
  </script>
</body>

要點:

    1、鏈式操作,減少代碼量

    2、簡化創建插入操作 var thead = table.createTHead();    var tr = thead.insertRow()等

    3、技巧之一:影響數據方面的操作需要確認

    4、使用confirm彈出確認取消框來判斷是否繼續刪除

    5、通過tr.cell[0].innerHTML獲得名字

    6、運用deleteRow(tr.rowIndex)刪除

    7、最後一句將table追加到id爲data的div下 運用DOM優化方式-將修改好的子元素統一放入父對象中

Form

獲取表單元素的方法:

    var form = document.forms[i/id]

屬性:

    .elements:獲得所有表單元素的集合

    .length:獲得所有表單元素的個數

方法:

    form.submit()    代替submit按鈕,在程序中手動提交表單

    常用來與普通button按鈕配合一起實現驗證提交

    form.reset()    重置表單

 Element:

    獲得任意表單的元素:form.elements[i/id/name]

    如果表單元素有name屬性:form.name

    如果元素沒有name而且離結尾很近,就用length去減

 方法:

    .focus() 獲取焦點,一般常在驗證出錯時強制修改使用

    實例:

HTML:

<html>
 <head>
	<meta charset="UTF-8">
	<title>實現帶樣式的表單驗證</title>
	<link rel="Stylesheet" href="css/3.css" />
 </head>
 <body>
	<form id="form1">
		<h2>增加管理員</h2>
		<table>
			<tr>
				<td>姓名:</td>
        <td>
					<input name="username"/>
					<span>*</span>
				</td>
				<td>
					<div class="vali_info">
						10個字符以內的字母、數字或下劃線的組合
					</div>
				</td>
			</tr>
			<tr>
				<td>密碼:</td>
				<td>
					<input type="password" name="pwd"/>
					<span>*</span>
				</td>
				<td>
					<div class="vali_info">6位數字</div>
				</td>
			</tr>
			<tr>
				<td></td>
				<td colspan="2">
          <input type="button" value="保存"/>
          <input type="reset" value="重填"/>
				</td>
			</tr>				
	    </table>
	</form>
	<script src="js/3.js"></script>
 </body>
CSS:
table{width:700px}
/*父元素下的第1個,第n個,最後一個td子元素*/
td:first-child{width:60px}
/*IE不支持nth-child*/
td:nth-child(2){width:200px}
/*IE*/
td:first-child+td{width:200px}
/*IE不支持--可以靠總寬度來調節
td:last-child{width:340px}*/
td span{color:red}

.vali_info{/* 頁面初始,驗證消息不顯示 */
	display:none;
}
.txt_focus{/*當文本框獲得焦點時穿上*/
	border-top:2px solid black;
	border-left:2px solid black;
}/*當文本框失去焦點時脫下*/

.vali_success,.vali_fail{
	background-repeat:no-repeat;
  background-position:left center;
	display:block;
}
/* 驗證消息:驗證通過時的樣式 */
.vali_success{
    background-image:url("../images/ok.png");
	padding-left:20px;
	width:0px;height:20px;
	overflow:hidden;
}
/* 驗證消息:驗證失敗時的樣式 */
.vali_fail{
    background-image:url("../images/err.png");
    border:1px solid red;
    background-color:#ddd;
    color:Red;
    padding-left:30px;
}
JS:
//Step1:爲name爲username和pwd的文本框綁定獲得焦點事件
var form = document.forms[0];
var txtName=form.username;
console.log(txtName);
var txtPwd= form.pwd;
console.log(txtPwd);
	txtName.οnfοcus=getFocus;
	txtPwd.οnfοcus=getFocus;
function getFocus(){
  //this->當前文本框
  //當前文本框邊框加粗
  this.className="txt_focus";
  //清除旁邊div的class
  var div=this.parentNode
      .nextElementSibling
      .firstElementChild;
  div.className="";
}
txtName.οnblur=function(){
  vali(this,/^\w{1,10}$/);
}
function vali(txt,reg){	
  //清除當前文本框的class
  txt.className="";
  //獲取旁邊div
  var div=txt.parentNode
    .nextElementSibling
    .firstElementChild;
  //用reg測試當前文本框的內容
  //如果通過,就修改div的class爲vali_success
  if(reg.test(txt.value)){
    div.className="vali_success";
  //添加新的返回值
	return true;}
  //否則修改div的class爲vali_fail
  else{
    div.className="vali_fail";
  //添加新的返回值
	return false;
  }
}
txtPwd.οnblur=function(){
  vali(this,/^\d{6}$/);
}
//查找倒數第二個提交按鈕
//爲其綁定單擊事件
form.elements[form.length-2].onclick = function(){
//驗證用戶名和密碼
/* var rName = vali(txtName,/^\w{1,10}$/);
var rAge = vali(txtPwd,/^\d{6}$/);*/
 //如果兩次驗證都爲true
	if( !vali(txtName,/^\w{1,10}$/))	//如果錯誤強制獲取焦點
		txtName.focus();
	else if(!vali(txtPwd,/^\d{6}$/))	//如果錯誤強制獲得焦點
		txtPwd.focus();
	else													//如果沒錯
		form.submit();//才提交
}


    

發佈了46 篇原創文章 · 獲贊 8 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章