DOM操作

一. 什么是DOM

1. 什么是DOM:

Document Object Model

 DOM: 专门操作网页内容的API的标准——W3C

2.为什么:

为了统一所有浏览器的操作网页的API标准

何时: 只要操作网页的内容,都要用DOM

 包括: 增,删,改,查,事件绑定

3. 查找元素:

 JS=ES(核心语法)+DOM(专门操作网页内容的API)+BOM(专门操作浏览器软件的API)

二. DOM Tree

1.什么是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{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>
shoopingCart

四. 修改:

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">&lt;&lt;</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=="&lt;&lt;"){
    if(d2.textContent=="<<"){
        //<div id="d1" style="display:none">
        d1.style.display="none";
        //修改当前d2的内容为>>
        //d2.innerHTML="&gt;&gt;";
        d2.textContent=">>";
    }else{//否则
        d1.style.display="block";
        d2.textContent="<<";
    }
}
</script>
</body>
</html>
door

 2.属性:

  三种:

  1). HTML标准属性: 2种:

   *). 核心DOM API: 4个
     获取属性值: var value=elem.getAttribute("属性名")

     修改属性值: 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>
menu

  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>
selectAll

  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 />&nbsp;每月套餐内拨打100分钟,超出部分2毛/分钟
      </div>
      <div id="content2">
        30元套餐详情:<br />&nbsp;每月套餐内拨打300分钟,超出部分1.5毛/分钟
      </div>
      <div id="content3">
        50元包月详情:<br />&nbsp;每月无限量随心打
      </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>
tabs

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>
vailWIthCSS

四. 添加/删除

 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>
createTable.HTMLDOM

   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>
createTable.HTMLDOM

  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();//才提交表单
  }
}
验证文本框

  

原文地址:https://www.cnblogs.com/liuqingqing-bloom/p/12390007.html