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

      

  • 相关阅读:
    快学Scala-第八章 继承
    快学scala-第七章 包和引入
    快学Scala-第六章 对象
    快学Scala-第五章 类
    快学Scala-第四章 映射和元组
    快学Scala-第三章 数组相关操作
    快学Scala-第二章 控制结构和函数
    快学Scala-第一章 基础
    ReLu(Rectified Linear Units)激活函数
    软件工程的发展史
  • 原文地址:https://www.cnblogs.com/liuqingqing-bloom/p/12390007.html
Copyright © 2020-2023  润新知