您的位置:首页 > 编程语言

DOM一些优化/简写与编程技巧

2018-03-06 23:15 155 查看

不需要查找可直接获得的节点

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>河北省</opti
4000
on>
</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.onfocus=getFocus;
txtPwd.onfocus=getFocus;
function getFocus(){
//this->当前文本框
//当前文本框边框加粗
this.className="txt_focus";
//清除旁边div的class
var div=this.parentNode
.nextElementSibling
.firstElementChild;
div.className="";
}
txtName.onblur=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.onblur=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();//才提交
}


    
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: