一. 什么是DOM |
1. 什么是DOM:Document Object Model DOM: 专门操作网页内容的API的标准——W3C 2.为什么:为了统一所有浏览器的操作网页的API标准 何时: 只要操作网页的内容,都要用DOM 包括: 增,删,改,查,事件绑定 3. 查找元素:JS=ES(核心语法)+DOM(专门操作网页内容的API)+BOM(专门操作浏览器软件的API) |
二. DOM Tree1.什么是DOM Tree:内存中保存一个网页中所有内容的树形结构 2.为什么:因为树形结构是最容易保存复杂的上下级包含关系的结构 3.如何:形成: 浏览器在加载一个HTML网页时,都会创建一棵DOM数。包括: 唯一的根节点对象: document 每个网页内容(元素、属性、文字)都会成为树上的节点对象 4.每个节点对象都有三个属性:1). node.nodeType: 节点类型 何时: 需要判断节点类型时可通过节点的值 值是一个数字: document文件 9 element元素 1 attribute属性 2 text文本 3 问题: 只能区分节点类型,不能更细致的区分元素的名称 2). node.nodeName: 节点名 何时: 判断当前节点的元素名时 包括: document #document element 全大写的标签名 attribute 属性名 text #text 3). node.nodeValue: 节点值——几乎不用 包括: document null element null attribute 属性值 text 文本内容 三.查找元素1. 不用查找就可直接获得的元素:4个 document.documentElement <html> document.head <head> document.body <body> document.forms[i] <form> 2. 按节点间关系查找:1).何时: 在首先获得了一个元素后,要找周围附近的元素时 2). 节点树: 包含所有节点对象的完整树结构 两大类关系: *). 父子关系: .parentNode 当前元素的父节点对象 .childNodes 当前元素的所有直接子节点对象 .firstChild 当前元素的第一个直接子节点对象 .lastChild 当前元素的最后一个直接子节点对象 *). 兄弟关系: .previousSibling 当前元素的前一个兄弟节点对象 .nextSibling 当前元素的下一个兄弟节点对象 问题: 不但包含元素节点,还受看不见的空字符节点干扰 3).元素树: 仅包含元素节点的树结构 元素树不是一棵新树,而是节点树中的一个子集而已 优点: 只包含元素节点,不包含文本节点,不会受干扰 包括: *).父子关系: .parentElement 当前元素的父元素对象 .children 当前元素的所有直接子元素对象 .firstElementChild 当前元素的第一个直接子元素对象 .lastElementChild 当前元素的最后一个直接子元素对象 *). 兄弟关系: .previousElementSibling当前元素的前一个兄弟元素对象 .nextElementSibling 当前元素的下一个兄弟元素对象 总结: 今后只要按节点间关系查找元素时,首选元素树的属性 查找一个节点下的所有后代节点: 两步: *). 先定义函数,仅遍历直接子元素: *). 在函数内,对每个直接子元素,调用和父元素完全相同的当前函数本身。 3. 按HTML特征查找:4种1). 按id查找一个元素: 何时: 当要查找的元素身上有id属性时,都首选用id查找 如何: var elem=document.getElementById("id名") 强调: getElementById只能用document调用 2). 按标签名查找多个元素: 何时: 当元素上没有id,name,class时,就可用标签名查找 如何使用: var elems=任意父元素.getElementsByTagName("标签名") 3). 按name属性查找多个元素: var elems= document.getElementsByName("name") 强调:只能在document上调用 4). 按class属性查找多个元素: var elems= parent.getElementsByClassName("class") 强调: *). 可用任意父元素找 *). 不仅查找直接子元素,而是在所有后代中查找符合条件的。 4. 按选择器查找1).何时: 如果单靠一个条件/特性无法精确的找到元素时 2).如何: 2个API: *). 只查找一个元素: var elem=任意父元素.querySelector("选择器") *). 查找多个元素: var elems=任意父元素.querySelectorAll("选择器")
<!DOCTYPE HTML> <html> <head> <title>使用Selector API实现购物车客户端计算</title> <meta charset="utf-8" /> <style> table{width:600px; text-align:center; border-collapse:collapse; } td,th{border:1px solid black} td[colspan="3"]{text-align:right;} /*tbody中每行最后一个td背景变为粉色*/ table>tbody>tr>td:last-child{ background:pink } /*tfoot中最后一个td背景变为黄色*/ table>tfoot>tr>td:last-child{ background:yellow } </style> </head> <body> <table id="data"> <thead> <tr> <th>商品名称</th> <th>单价</th> <th>数量</th> <th>小计</th> </tr> </thead> <tbody> <tr> <td>iPhone6</td> <td>¥4488.00</td> <td> <button>-</button> <span>1</span> <button>+</button> </td> <td>¥4488.00</td> </tr> <tr> <td>iPhone6 plus</td> <td>¥5288.00</td> <td> <button>-</button> <span>1</span> <button>+</button> </td> <td>¥5288.00</td> </tr> <tr> <td>iPad Air 2</td> <td>¥4288.00</td> <td> <button>-</button> <span>1</span> <button>+</button> </td> <td>¥4288.00</td> </tr> </tbody> <tfoot> <tr> <td colspan="3">Total: </td> <td>¥14064.00</td> </tr> </tfoot> </table> <script> //用id查找table: 查找id为"data"的元素 var table=document.getElementById("data"); console.log(table); //用标签名查找button: 查找table下所有button元素 var buttons= table.getElementsByTagName("button"); console.log(buttons); //事件绑定: //事件: 浏览器自动触发的或用户手动触发的页面内容的状态改变 //事件处理函数: 当事件发生时,自动执行的函数 //事件绑定: 提前将处理函数,赋值给元素的事件属性,保存住。但是暂不执行。 for(var button of buttons){ //当单击按钮时:为当前button绑定单击事件的处理函数 button.onclick=function(){ //在事件处理函数中,this可随时获得单击的当前按钮对象 var btn=this;//先获得当前单击的按钮对象 //1. 修改数量 //查找btn旁边的span var span=btn.parentNode.children[1]; // td span //获得span中的数字 var n=parseInt(span.innerHTML); //如果btn的内容是+ if(btn.innerHTML=="+"){ n++;//就将数字+1 }else if(n>1){//否则,如果数字>1 n--;//才能数字-1 } //将数字保存回span的内容中 span.innerHTML=n; //2. 修改小计 //获得前一个td中的内容中的单价 var price=parseFloat( btn .parentNode //td .previousElementSibling //前一个td .innerHTML //"¥4488.00" .slice(1) //"4488.00" );//4488 //计算小计=单价*数量 var subTotal=price*n; //将小计放到后一个td的内容中 btn.parentNode.nextElementSibling.innerHTML="¥"+subTotal.toFixed(2); //3. 修改总计 //获得tbody中每行最后一个td var tds=table.querySelectorAll( "tbody>tr>td:last-child" ); console.log(tds); //定义变量total=0,准备累加小计 var total=0; for(var td of tds){//遍历找到的每个td //取出当前td的内容,去掉开头的¥,转为数字,累加到total上 total+=parseFloat(//4488 td.innerHTML //"¥4488.00" .slice(1) //"4488.00" ) } //将total保存到tfoot中最后一个td的内容中 table.querySelector( "tfoot>tr>td:last-child" )//return 最后一个td .innerHTML="¥"+total.toFixed(2) }//触发: 当前按钮.onclick() } </script> </body> </html> |
四. 修改:1.内容:三种: 1). 获取或修改原始的HTML片段内容: elem.innerHTML 2). 获取或修改纯文本内容: elem.textContent 比innerHTML多做两件事: *). 翻译特殊符号为正文 *). 去掉内嵌的子标签,只保留文字 3). 表单元素的值: elem.value <!DOCTYPE HTML> <html> <head> <title>读取并修改元素的内容</title> <meta charset="utf-8" /> <style> div{float:left; height: 100px; line-height: 100px; } #d1,#d3{ background-color: #ccff00; } #d2{ cursor: pointer; background-color: #ffcc00; } </style> </head> <body> <div id="d1">树形列表</div> <div id="d2"><<</div> <div id="d3">内容的主体</div> <script> //1. 查找触发事件的元素: var d2=document.getElementById("d2"); //2. 绑定事件处理函数 d2.onclick=function(){ var d2=this;//获得当前单击的d2 //3. 查找要修改的元素: var d1=document.getElementById("d1"); //4. 修改元素:控制d1的显示或隐藏 //如果当前d2的内容是<< //if(d2.innerHTML=="<<"){ if(d2.textContent=="<<"){ //<div id="d1" style="display:none"> d1.style.display="none"; //修改当前d2的内容为>> //d2.innerHTML=">>"; d2.textContent=">>"; }else{//否则 d1.style.display="block"; d2.textContent="<<"; } } </script> </body> </html> 2.属性:三种: 1). HTML标准属性: 2种: *). 核心DOM API: 4个 修改属性值: elem.setAttribute("属性名","新值") 移除属性: elem.removeAttribute("属性名") 判断是否包含属性: var bool=elem.hasAttribute("属性名") *). HTML DOM API: 对常用核心DOM API的简化 HTML DOM提前将所有HTML标准属性,定义在内存中的元素对象上: elem.属性名 特例: class是ES标准中的关键字 DOM中不允许再使用class作为属性名 class一律都要改为className DOM中的className属性等于HTML中的class <!DOCTYPE HTML> <html> <head> <title>1. 实现伸缩二级菜单</title> <meta charset="utf-8" /> <link rel="stylesheet" href="css/1.css" /> </head> <body> <ul class="tree"> <li> <span class="open">考勤管理</span> <ul> <li>日常考勤</li> <li>请假申请</li> <li>加班/出差</li> </ul> </li> <li> <span>信息中心</span> <ul> <li>通知公告</li> <li>公司新闻</li> <li>规章制度</li> </ul> </li> <li> <span>协同办公</span> <ul> <li>公文流转</li> <li>文件中心</li> <li>内部邮件</li> <li>即时通信</li> <li>短信提醒</li> </ul> </li> </ul> <script> //1. 查找触发事件的元素 //查找class为tree的ul下的li下的所有span var spans=document.querySelectorAll( "ul.tree>li>span" ); console.log(spans); //2. 绑定事件处理函数 for(var span of spans){//遍历每个span //为每个span绑定单击事件处理函数 span.onclick=function(){ var span=this;//获得当前单击的span //3. 查找要修改的元素 //4. 修改元素 //如果当前span自己是开着的 if(span.className=="open"){ span.className="";//只要把自己关闭即可 }else{//否则(如果自己是关着的) //查找其它可能开着的span: //class为tree的ul下的class为open的span var openSpan=document.querySelector( "ul.tree>li>span.open" ); if(openSpan!=null){//如果找到 //就将其它开着的span关闭 openSpan.className=""; } //然后才把当前span自己打开 span.className="open"; } } } </script> </body> </html> 2). 状态属性: enabled disabled selected checked 值都是bool类型,不是字符串类型,不能用核心DOM API修改。 只能用HTML DOM的.来访问 补充: CSS3中有一种特殊的选择器: 状态伪类: :enabled :disabled :checked :selected <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>全选和取消全选</title> </head> <body> <h2>管理员列表</h2> <table border="1px" width="500px"> <thead> <tr> <th><input type="checkbox"/>全选</th> <th>管理员ID</th> <th>姓名</th> <th>操作</th> </tr> </thead> <tbody> <tr> <td><input type="checkbox"/></td> <td>1</td> <td>Tester</td> <td>修改 删除</td> </tr> <tr> <td><input type="checkbox"/></td> <td>2</td> <td>Manager</td> <td>修改 删除</td> </tr> <tr> <td><input type="checkbox"/></td> <td>3</td> <td>Analyst</td> <td>修改 删除</td> </tr> <tr> <td><input type="checkbox"/></td> <td>4</td> <td>Admin</td> <td>修改 删除</td> </tr> </tbody> </table> <button>删除选定</button> <script> //1. 查找触发事件的元素: table下thead下的input var chbAll=document.querySelector( "table>thead input" ); //2. 绑定事件处理函数 chbAll.onclick=function(){ var chbAll=this;//获得当前单击的chbAll对象 //3. 查找要修改的元素:tbody下每行第一个td中的input var chbs=document.querySelectorAll( "table>tbody>tr>td:first-child>input" ); console.log(chbs); //4. 修改元素 for(var chb of chbs){//遍历每个chb //修改当前chb的checked属性的值为chbAll的checked属性值 chb.checked=chbAll.checked; } } //1. 查找触发事件的元素 //查找table下tbody下每行第一个td中的input,保存在chbs中 var chbs=document.querySelectorAll( "table>tbody>tr>td:first-child>input" ); //2. 绑定事件处理函数 for(var chb of chbs){//遍历chbs中每个chb //为当前chb绑定单击事件处理函数 chb.onclick=function(){ //3. 查找要修改的元素 //查找table下thead下的input var chbAll=document.querySelector( "table>thead input" ); //4. 修改元素 var chb=this;//获得当前单击的chb对象 //如果当前chb是取消选中的 if(chb.checked==false){ chbAll.checked=false; }else{//否则(如果当前chb被选中) //尝试查找tbody中每行第一个td中“未选中”的input var unchecked=document.querySelector( "table>tbody>tr>td:first-child>input:not(:checked)" ); //如果没找到(说明都选中了) if(unchecked==null){ chbAll.checked=true; } } } } </script> </body> </html>
3). 自定义扩展属性: 什么是: HTML标准中没有规定的,程序员自行添加的属性 何时: 2种: *). 用自定义扩展属性作为条件,选择要绑定事件的元素 为什么不用id,class,元素 选择器 id只能选择一个元素 class是定义样式用的,经常变化 元素选择器限制太死。实现一种效果,可能用不同的元素都行。 使用自定义扩展属性作为条件绑定事件的好处: 不受个数,样式,元素名的干扰! *). 在客户端元素上临时缓存业务数据 为什么: 避免重复请求服务端,造成延迟 定义自定义扩展属性: <ANY 自定义属性名="值"> HTML5标准中: <ANY data-自定义属性名="值" 获取或修改自定义扩展属性: *). 核心DOM API: .getAttribute() .setAttribute() .removeAttribute() .hasAttribute() 强调: HTML DOM API不能操作自定义扩展属性 因为自定义扩展属性是后天自定义的,HTML标准中没有。所以不包含在元素对象中。所以不能用.直接访问。 *). HTML5标准中: elem.dataset //可自动获得所有data-*开头的属性 .自定义属性名 //使用dataset访问自定义属性时,不用data-前缀
<!DOCTYPE HTML> <html> <head> <title>读取并修改元素的属性</title> <meta charset="utf-8" /> <link rel="stylesheet" href="css/3.css" /> <style></style> </head> <body> <h2>实现多标签页效果</h2> <div class="tabs"> <ul id="tab"> <li><a href="#" data-target="content1" data-toggle="tab">10元套餐</a></li> <li><a href="#" data-target="content2" data-toggle="tab">30元套餐</a></li> <li><a href="#" data-target="content3" data-toggle="tab">50元包月</a></li> </ul> <div id="container"> <div id="content1"> 10元套餐详情:<br /> 每月套餐内拨打100分钟,超出部分2毛/分钟 </div> <div id="content2"> 30元套餐详情:<br /> 每月套餐内拨打300分钟,超出部分1.5毛/分钟 </div> <div id="content3"> 50元包月详情:<br /> 每月无限量随心打 </div> </div> </div> <script> //起始时,默认显示第一个div的内容 document.getElementById("content1") .style.zIndex=9; //1. 查找触发事件的元素 var tabs=document.querySelectorAll( "[data-toggle=tab]" ); console.log(tabs); var n=10;//用来递增z-index的值 //2. 绑定事件处理函数 for(var tab of tabs){ tab.onclick=function(){ var tab=this; //3. 查找要修改的元素 //先获取保存在当前tab上的目标div的id var id=tab.getAttribute("data-target"); //tab.dataset.target; //再用id查找对应的div var content=document.getElementById(id); //4. 修改元素 //<div style="z-index:10" //所有带-的css属性,都要去-变驼峰 content.style.zIndex=n; n++; } } </script> </body> </html> 3.样式:1).修改内联样式: elem.style.css属性名="值" 等效于: <ELEM style=" css属性名:值" 强调: *). css属性名中如果带-,需要去横线变驼峰: z-index => zIndex list-style => listStyle background-color => backgroundColor *). 如果是带单位的数字属性: 修改时: 必须手动拼接单位到结尾: .style.width=12+"px"; 获取时: 必须去掉结尾的px,才能做计算 比如: width="12.5px" parseFloat(width) => 12.5 问题: elem.style 仅代表内联样式: 修改时,如果elem.style,优先级最高! 获取时,只能获取内联样式,无法获取外部样式表中的样式。 获取样式: 不能用style 应该获取计算后的样式: 最终应用到元素上的所有样式的集合。 如何: 2步: *). 先获得计算后的样式的集合对象: var style=getComputedStyle(elem) *). 获取一个css属性的值: style.css属性 强调: 因为计算后的样式属性来源不确定,所以都是只读的。
问题: elem.style修改样式,一句话只能修改一个css属性 如果同时修改多个css属性,代码会很繁琐 解决: 今后,只要批量修改css属性,都要首选class方式修改
<!doctype html> <html> <head> <meta charset="UTF-8"> <title>实现带样式的表单验证</title> <link rel="Stylesheet" href="css/5.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="submit" value="保存"/> <input type="reset" value="重填"/> </td> </tr> </table> </form> <script> //当文本框获得焦点时 //给当前文本框自己穿"txt_focus"让边框变粗 //找到当前文本框旁边的div,清除其class //1. 查找触发事件的元素 //分别查找name为username和pwd的两个文本框 var txtName= document.getElementsByName("username")[0]; //[input][0] var txtPwd= document.getElementsByName("pwd")[0]; //2. 绑定事件处理函数 //var a; var b; a=b=3; txtName.onfocus=txtPwd.onfocus=function(){ //3. 查找要修改的元素 var txt=this;//获得当前文本框自己 var div=//找到旁边的div txt.parentNode //td .nextElementSibling //下一个td .children[0]; //div //4. 修改元素 txt.className="txt_focus"; div.className=""; } //当文本框失去焦点时 //清除当前文本框的class,让边框恢复正常 //定义正则表达式 //验证当前文本的内容 //如果验证通过 //就给当前文本框旁边的div穿"vali_success" //否则 //就给当前文本框旁边的div穿"vali_fail" //1. 查找触发事件的元素 //2. 绑定事件处理函数 txtName.onblur=function(){ vali(this,/^\w{1,10}$/); } function vali(txt,reg){ //3. 查找要修改的元素 var div=//找到旁边的div txt.parentNode //td .nextElementSibling //下一个td .children[0]; //div //4. 修改元素 txt.className=""; //如果验证通过 if(reg.test(txt.value)==true){ div.className="vali_success"; }else{//否则 div.className="vali_fail"; } } txtPwd.onblur=function(){ vali(this,/^\d{6}$/); } </script> </body> </html> 四. 添加/删除1.添加:1).3步: *). 创建一个空元素对象 var a=document.createElement("a") a: <a></a> *). 设置关键属性 a.href="http://tmooc.cn"; a.innerHTML="go to tmooc"; a: <a href="http://tmooc.cn"> go to tmooc </a> *). 将新对象挂载到DOM树上指定位置 3种: a). 在当前父元素下的结尾,追加一个新元素: 父元素.appendChild(a) b). 在父元素下的某个子元素之前插入: 父元素.insertBefore(a, child) c). 替换父元素的某个子元素: 父元素.replaceChild(a, child)
2).优化: 尽量减少修改DOM树的次数 因为每修改一次DOM树,浏览器都会重绘页面 页面加载过程: html -> DOM树 ↓ 加载树 -> 排版 -> 绘制 ↑ 非常耗时 css -> COM模型 每次修改DOM树都会导致重排重绘 <!DOCTYPE HTML> <html> <head> <title>动态创建表格</title> <meta charset="utf-8" /> <style> table{width:600px; border-collapse:collapse; text-align:center; } td,th{border:1px solid #ccc} </style> </head> <body> <div id="data"> <!-- <table>//创建table元素,并追加到div#data下 <thead>//创建thead元素,并追加到table下 <tr>//创建tr元素,并追加到thead下 //遍历json数组中第一个对象的每个属性 //for(var key in json[0]) //创建<th>并追加到<tr>下 //设置<th>的内容为key <th>ename</th> <th>salary</th> <th>age</th> </tr> </thead> <tbody>//创建tbody,并追加到table下 //遍历json中每个员工对象 //每遍历一个对象就创建一个tr追加到tbody下 <tr> //遍历当前员工对象的每个属性 //每遍历一个属性就创建一个td并追加到tr下,并设置td的内容为当前属性的值 <td>Tom</td> <td>11000</td> <td>25</td> </tr> </tbody> </table>--> </div> <script>//day03/2_createTable_HTMLDOM.html 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元素,并追加到table下 var thead=document.createElement("thead"); table.appendChild(thead); //创建tr元素,并追加到thead下 var tr=document.createElement("tr"); thead.appendChild(tr); //遍历json数组中第一个对象的每个属性 for(var key in json[0]){ //创建<th>并追加到<tr>下 var th=document.createElement("th"); tr.appendChild(th); th.innerHTML=key;//设置<th>的内容为key } //创建tbody,并追加到table下 var tbody=document.createElement("tbody"); table.appendChild(tbody); for(var emp of json){//遍历json中每个员工对象 //每遍历一个对象就创建一个tr追加到tbody下 var tr=document.createElement("tr"); tbody.appendChild(tr); //遍历当前员工对象的每个属性 for(var key in emp){ //每遍历一个属性就创建一个td并追加到tr下,并设置td的内容为当前属性的值 var td=document.createElement("td"); tr.appendChild(td); td.innerHTML=emp[key];//当前属性的值 //emp["key"]; //emp.key; } } //最后,再将整个table一次性追加到div#data下 document.getElementById("data") .appendChild(table); </script> </body> </html> 3).如何: 2种: *). 如果同时添加父元素和子元素时,应该先在内存中将子元素添加到父元素中,最后再一次性将父元素添加到DOM树 *). 如果父元素已经在页面上了,要同时添加多个平级子元素时。先将多个子元素临时加入文档片段对象中。再一次性将文档片段对象添加到DOM树上。 文档片段对象将子元素送到DOM树后,自动释放不占页面空间 。 文档片段: 内存中,临时保存多个平级子元素的,虚拟的父元素。 何时: 同时添加多个平级子元素到DOM树时 如何: a). 先创建一个文档片段对象: var frag=document.createDocumentFragment(); b). 将子元素添加到frag中 frag.appendChild(child) c). 将frag整体添加到DOM树 父元素.appendChild(frag) 4). 删除: 父元素.removeChild(child) <!DOCTYPE HTML> <html> <head> <title>二级联动列表</title> <meta charset="utf-8" /> <style> .hide{ display: none; } </style> </head> <body> <select name="provs"> <option>—请选择—</option><!--0--> <option value="bj">北京市</option><!--1--> <option value="tj">天津市</option> <option value="hb">河北省</option> </select> <select name="cities" class="hide"> </select> <script> /*实现“省”和“市”的级联下拉列表*/ var cities=[ [ {"name":'东城区',"value":101}, {"name":'西城区',"value":102}, {"name":'海淀区',"value":103}, {"name":'朝阳区',"value":104} ], [ {"name":'河东区',"value":201}, {"name":'河西区',"value":202}, {"name":'南开区',"value":203} ], [ {"name":'石家庄市',"value":301}, {"name":'廊坊市',"value":302}, {"name":'保定市',"value":303}, {"name":'唐山市',"value":304}, {"name":'秦皇岛市',"value":305} ] ]; //1. 查找触发事件的元素 var selProvs= document.getElementsByName("provs")[0]; //2. 绑定事件处理函数 //当selProvs中的选中项改变时自动执行 selProvs.onchange=function(){ //alert(this.value); //3. 查找要修改的元素:第二个select var selCts= document.getElementsByName("cities")[0] //4. 修改元素 var selProvs=this; var i=selProvs.selectedIndex; if(i>0){ var cts=cities[i-1]; var frag= document.createDocumentFragment(); //先添加一个<option>-请选择- /*var opt=document.createElement("option"); opt.innerHTML="-请选择-";*/ frag.appendChild(new Option("-请选择-")); for(var city of cts){ //每遍历一个城市,就创建一个option,并加入frag中 /*var opt=document.createElement("option"); frag.appendChild(opt); //将当前城市对象的name放入option中 opt.innerHTML=city.name;*/ frag.appendChild(new Option(city.name)) } //每次添加新option之前,先清除旧的内容 selCts.innerHTML=""; selCts.appendChild(frag); selCts.className=""; }else{ selCts.className="hide"; } } </script> </body> </html> 五. HTML DOM常用对象:Image Select/option Table/... Form/... 1. Image:var img=new Image(); 2.Select对象:代表页面上一个<select> 1).属性: .selectedIndex 快速获得当前选中项的位置 .options 快速获得select下所有option的集合 .options.length 获得select下option的个数 .length => .options.length .value 获得select中当前选中项的值 如果选中项没有value,则用内容作为value 2).方法: .add(option) 向select中添加一个option 问题: 不支持文档片段,无法有优化,所以还是需要用appendChild .remove(i) 移除select中i位置的option 3.Option对象:代表select中每个option元素 1).创建: var opt=new Option(text,value)
4.Table对象:代表页面上一个<table>元素 1).管着行分组: 添加行分组: var thead=table.createTHead() var tbody=table.createTBody() var tfoot=table.createTFoot()
2).删除行分组: table.deleteTHead() table.deleteTFoot() 3).获取行分组: table.tHead table.tFoot table.tBodies[i] 4).行分组管着行: 添加行: var tr=行分组.insertRow(i) 在当前行分组中i位置,插入一个新行 固定用法: *). 行分组.insertRow(0) 开头插入 *). 行分组.insertRow() 末尾追加 删除行: 行分组.deleteRow(i) 删除行分组内的i位置的行 强调: i是相对于行分组内的下标 问题: 行分组内的下标位置无法自动获得 解决: 今后只要删除行,都用: table.deleteRow(tr.rowIndex) 其中: tr.rowIndex可获得tr在整个表中的下标位置 获取行: 行分组.rows[i] 获得当前行分组中的第i行 <!DOCTYPE HTML> <html> <head> <title>动态创建表格</title> <meta charset="utf-8" /> <style> table{width:600px; border-collapse:collapse; text-align:center; } td,th{border:1px solid #ccc} table>thead 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元素,并追加到table下 var thead=table.createTHead(); //创建tr元素,并追加到thead下 var tr=thead.insertRow(); //遍历json数组中第一个对象的每个属性 for(var key in json[0]){ //创建<th>并追加到<tr>下 tr.insertCell().innerHTML=key; } //新建一个th tr.insertCell().innerHTML="删除"; //创建tbody,并追加到table下 var tbody=table.createTBody(); for(var emp of json){//遍历json中每个员工对象 //每遍历一个对象就创建一个tr追加到tbody下 var tr=tbody.insertRow(); //遍历当前员工对象的每个属性 for(var key in emp){ //每遍历一个属性就创建一个td并追加到tr下,并设置td的内容为当前属性的值 tr.insertCell().innerHTML=emp[key]; } //创建一个新的td var td=tr.insertCell(); td.innerHTML=`<button>×</button>`; //查找td下唯一一个元素,并绑定单击事件处理函数 td.children[0].onclick=function(){ //获得当前按钮: var btn=this; //获得当前按钮所在的行 var tr=btn.parentNode.parentNode; //td //tr var ename=tr.cells[0].innerHTML; // 第一个td 的 内容 //如果确认删除 if(confirm(`是否继续删除 ${ename}?`)){ //删除当前按钮所在的行 table.deleteRow(tr.rowIndex); } } } //最后,再将整个table一次性追加到div#data下 document.getElementById("data") .appendChild(table); </script> </body> </html> 5).行管着格: 添加格: var td=tr.insertCell(i) 固定用法: tr.insertCell() 在行末尾追加新格 问题: 只能创建td,不能创建th 删除格: tr.deleteCell(i) 获取格: tr.cells[i] 5.Form对象:代表页面上一个表单元素 1).获取: var form=document.forms[i]; 2).属性: .elements 可获得表单中所有表单元素的集合 .elements.length 获得表单中所有表单元素的个数 .length => .elements.length 3).方法: form.submit() 手动调用程序控制提交表单 4).表单元素: 获取: .elements[i/id/name] 如果表单元素上有name属性(比如input表单元素有name属性值): form.name属性值 方法: elem.focus() 让当前表单元素获得焦点 elem.blur() 让当前表单元素失去焦点
5).onsubmit 在最终提交表单之前触发 //Step1:为name为username和pwd的文本框绑定获得焦点事件 var form=document.forms[0]; //var txtName=form.elements["username"]; var txtName=form.username; var txtPwd=form.pwd; 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; }else{//否则修改div的class为vali_fail div.className="vali_fail"; return false; } } txtPwd.onblur=function(){ vali(this,/^\d{6}$/); } //找到倒数第2个保存按钮,并绑定单击事件 form.elements[form.length-2].onclick=function(){ /*//验证每个文本框 var rname=vali(txtName,/^\w{1,10}$/); var rpwd=vali(txtPwd,/^\d{6}$/); //只有都验证通过 if(rname==true&&rpwd==true){ form.submit();//才提交表单 }*/ //如果验证姓名文本框未通过 if(vali(txtName,/^\w{1,10}$/)==false){ txtName.focus();//让姓名文本框获得焦点 }else if(vali(txtPwd,/^\d{6}$/)==false){//否则如果验证密码框未通过 txtPwd.focus();//让密码框获得焦点 }else{//否则 form.submit();//才提交表单 } }
|