一. 什么是DOM:.
Document Object Model
文档 对象 模型
1. 什么是: 一套专门操作网页中元素内容的对象和方法的集合。
2. 何时: 只要想操作网页中的内容,都要用DOM,其为操作网页的内容底层 jQuery Vue 等等其底层也是经过了dom
3. DOM标准: W3C负责制定和维护了一套DOM标准,几乎所有浏览器100%兼容! 所以有兼容问题可以用dom来解决
4. 如何: 五件事: 增删改查+事件绑定
二. DOM树:
1. DOM树: 内存中保存一个网页中所有内容的树型结构。
2. 为什么: 因为HTML的元素内容,都是上下级包含的嵌套结构。而树形结构是最直观的展现上下级包含关系的结构。
3.dom树构造:
三. 查找元素: 4种方式:
1. 用很简单的方法就可直接获得的节点对象: 4个
(1). 树根对象: document
(2). <html>元素: document.documentElement
(3). <head>元素: document.head
(4). <body>元素: document.body
2. 按节点间关系查找元素: 2大类关系, 6个属性
(1). 节点树: 包含所有网页内容节点的完整树结构
a. 父子关系: 4个属性
1). 获得一个元素的父元素: 元素.parentNode
父 节点/对象
说明: 因为一个元素的直接父元素,只能有一个,所以parentNode,总是返回一个元素对象
2). 获得一个元素下的所有直接子元素: 元素.childNodes
子 节点/对象们
说明: 因为一个元素的直接子元素很可能有多个,所以childNodes总是返回一个类数组对象。其中包含当前元素下的多个直接子元素。
3). 获得一个元素下的第一个直接子元素: 元素.firstChild
第一个孩子
4). 获得一个元素下的最后一个直接子元素: 元素.lastChild
最后一个孩子
b. 兄弟关系: 2个属性
1). 获得当前元素相邻的前一个元素: 元素.previousSibling
前一个 兄弟
2). 获得当前元素相邻的后一个元素: 元素.nextSibling
后一个 兄弟
(2). 问题: 节点树包含所有网页内容,甚至连看不见的换行和缩进,也当做树上的节点对象创建出来!因为程序员只关心元素,不关系换行和缩进等空字符,但是空字符却站着节点树上的位置。严重干扰了查找!——,几乎不用节点树的2大类关系和6个属性(所以可以忽略上面的内容)
(3). 解决: DOM标准又额外定义了一棵元素树。
a. 什么是: 只包含元素对象的树结构,不包含那些不是元素的文本节点。
b. 优点: 只包含元素,不包含文本,所以,不会干扰查找!——只要按节点间关系查找元素时,都用元素树,不用节点数。
(4). 元素树也包含2大类关系,6个属性:
a. 父子关系:
1). 获得元素的父元素: 元素.parentElement
父 元素
2). 获得元素下的所有直接子元素: 元素.children
孩子们
3). 获得元素下的第一个直接子元素: 元素.firstElementChild
第一个 元素 孩子
4). 获得元素下的最后一个直接子元素: 元素.lastElementChild
最后一个 元素 孩子
b. 兄弟关系:
1). 获得元素相邻的前一个兄弟元素: 元素.previousElementSibling
前一个 元素 兄弟
2). 获得元素相邻的后一个兄弟元素: 元素.nextElementSibling
下一个 元素 兄弟
(5). 示例: 使用元素树关系属性查找页面中指定的元素:
1 <!DOCTYPE HTML> 2 <html> 3 4 <head> 5 <title>DOM Tree</title> 6 <meta charset="utf-8" /> 7 </head> 8 9 <body> 10 <span id="s1">Hello</span> 11 <h1>标题一</h1> 12 <script> 13 console.log(document); 14 console.log(document.documentElement); 15 console.log(document.head); 16 console.log(document.body); 17 //DOM中: 18 //console.log()输出的是DOM树结构,而不是当前元素在内存中的对象。 19 //如果想输出/查看当前元素的对象属性: 20 console.dir(document); 21 console.dir(document.documentElement); 22 console.dir(document.head); 23 console.dir(document.body); 24 25 //想获得span元素: body下的第一个直接子元素 26 var span=document.body.firstElementChild; 27 console.log(span); 28 //想获得h1元素:span的下一个兄弟 29 var h1=span.nextElementSibling; 30 console.log(h1); 31 32 //想获得span元素: body下的第一个直接子元素 33 var span=document.body.children[0]; 34 console.log(span); 35 //想获得h1元素: body下第二个直接子元素 36 var h1=document.body.children[1]; 37 console.log(h1); 38 </script> 39 </body> 40 41 </html>
(6). 总结: 只要已经获得一个元素,想找他周围附件的元素时,才用节点间关系查找: 2大类关系,6个属性
关系图如下:
3. 按HTML特征查找: 4个函数:
(1). 问题: 有些要找的元素,藏的很深,或离的很远,就不能用节点间关系查找了
(2). 解决: 可以用HTML特征查找元素
(3). 包括: 可以按4种特征查找:
a. 按id查找一个元素对象
1). var 一个元素对象=document.getElementById("id名")
2). 意为: 在网页中 获得一个元素(通过id名)
3). 返回值:
i. 如果找到指定id名的元素,就返回这个元素对象
ii. 如果没找到指定id名的元素,则返回null
4). 强调:
i. .前的主语必须是document
ii. 因为只找到一个元素,所以函数名中Element没有s结尾
5). 问题: id必须唯一,用id只能找到一个元素!
b. 按标签名查找多个元素
1). var 类数组对象=
任意父元素对象.getElementsByTagName("标签名")
2).意为:
在任意父元素下获得多个元素(通过标签名)
3). 返回值:
i. 如果找到符合要求的元素,则返回一个类数组对象,其中包含多个符合要求的元素
ii. 如果没找到符合要求的元素,则返回一个空的类数组对象:
{ length:0 }
4). 强调:
i. .前的主语可以是任意父元素对象。而查找时,也只在指定的父元素下查找,不会超出指定的父元素的范围。
优化: 将查找范围限制在合理的范围内,可以提高查找效率。
当然!如果确实想在整个网页范围内查找,主语也可以时document对象。
ii. 因为极有可能找到多个元素,所以函数中的Elements是s结尾表示多个。而且返回值还是类数组对象。
iii. 不仅在直接子元素中查找,而且还会在所有后代中查找。
iv. 坑: 如果只找到一个符合要求的元素,也是默认放在一个类数组对象中返回的!但是,我们只想要这一个元素对象,而不想要整个类数组对象。
解决: 只要用[0],就能取出找到的唯一的一个元素对象.
示例: 按Id查找和按标签名查找元素
1 <!DOCTYPE HTML> 2 <html> 3 <head> 4 <title>遍历节点树</title> 5 <meta charset="utf-8"/> 6 7 </head> 8 <body> 9 <span>Hello World !</span> 10 <ul id="nav"> 11 <li>电影</li> 12 <li>综艺 13 <ul> 14 <li>跑男</li> 15 <li>爸爸</li> 16 <li>极限</li> 17 </ul> 18 </li> 19 <li>剧集</li> 20 </ul> 21 <script> 22 //想查找id为nav的一个元素 23 var ulNav=document.getElementById("nav"); 24 console.log(ulNav); 25 26 //想在ulNav下查找所有li元素 27 var lis=ulNav.getElementsByTagName("li"); 28 console.log(lis); 29 //想在ulNav下查找所有a元素 30 var as=ulNav.getElementsByTagName("a"); 31 console.log(as); 32 33 //想找ulNav下的一个ul元素 34 //错误: 只能获得一个大的集合,无法精确获得一个元素对象 35 // var ulSub=ulNav.getElementsByTagName("ul") 36 //正确: 加[0]; 37 var ulSub=ulNav.getElementsByTagName("ul")[0] 38 console.log(ulSub); 39 </script> 40 </body> 41 </html>
c.按class名查找多个元素:
var 类数组对象=任意父元素.getElementsByClassName("class名")
意为: 在任意父元素下 获得多个元素 通过class名
返回值:
1). 如果找到符合要求的元素,就返回一个类数组对象
2). 如果没找到符合要求的元素,就返回空的类数组对象: { length:0 }
强调:
1). 可以在任意指定的父元素下查找。合理的设置查找范围,可以优化查找的效率!当然,如果确实需要在整个页面中查找,也可以写document开头。
2). 因为可能找到多个符合要求的元素,所以,函数名中的Elements是s结尾,表示多个元素。
3). 即使只找到一个元素,也会放在类数组对象中返回,所以,要想获得找到的唯一一个元素,必须加[0]
4). 不仅查找直接子元素,而且会在所有后代中查找符合要求的元素。
5). 即使一个元素上,同时被多个class名修饰,那么只需要其中一个class名就可以找到当前元素。
d. 按name名查找表单元素:
var 类数组对象=document.getElementsByName("name名")
意为: 在页面中 获得多个元素 通过Name名
返回值:
1). 如果找到符合要求的元素,就返回一个类数组对象
2). 如果没找到符合要求的元素,就返回空的类数组对象: { length:0 }
强调:
1). .前必须是document作为主语!
2). 因为可能找到多个符合要求的元素,所以,函数名中的Elements是s结尾,表示多个元素。
3). 即使只找到一个元素,也会放在类数组对象中返回,所以,要想获得找到的唯一一个元素,必须加[0]
示例:按HTML特征查找指定元素
1 <!DOCTYPE HTML> 2 <html> 3 <head> 4 <title>遍历节点树</title> 5 <meta charset="utf-8"/> 6 7 </head> 8 <body> 9 <span>Hello World !</span> 10 <ul id="nav"> 11 <li class="item">电影</li> 12 <li class="item">综艺 13 <ul> 14 <li class="item active">跑男</li> 15 <li class="item">爸爸</li> 16 <li class="item">极限</li> 17 </ul> 18 </li> 19 <li class="item">剧集</li> 20 </ul> 21 <form> 22 用户名:<input name="uname"></br> 23 性别: 24 <label><input type="radio" name="sex" value="1">男</label> 25 <label><input type="radio" name="sex" value="0">女</label> 26 </form> 27 <script> 28 //想查找id为nav的一个元素 29 var ulNav=document.getElementById("nav"); 30 console.log(ulNav); 31 32 //想在ulNav下查找所有li元素 33 var lis=ulNav.getElementsByTagName("li"); 34 console.log(lis); 35 //想在ulNav下查找所有a元素 36 var as=ulNav.getElementsByTagName("a"); 37 console.log(as); 38 39 //想找ulNav下的一个ul元素 40 //错误: 只能获得一个大的集合,无法精确获得一个元素对象 41 // var ulSub=ulNav.getElementsByTagName("ul") 42 //正确: 加[0]; 43 var ulSub=ulNav.getElementsByTagName("ul")[0] 44 console.log(ulSub); 45 46 47 //想查找ulNav下class为item的所有元素 48 var items= 49 ulNav.getElementsByClassName("item"); 50 console.log(items); 51 //想查找class为active的一个元素 52 var liActive= 53 ulNav.getElementsByClassName("active")[0]; 54 console.log(liActive); 55 //想找name为sex的多个单选按钮 56 var radios= 57 document.getElementsByName("sex"); 58 console.log(radios); 59 //想查找name为uname的一个文本框 60 var txtName= 61 document.getElementsByName("uname")[0] 62 console.log(txtName); 63 </script> 64 </body> 65 </html>
4.按选择器查找: 今后只要查找条件非常复杂时,都用选择器查找: 2个函数
(1). 只查找一个符合要求的元素:
a. var 一个元素对象=任意父元素.querySelector("css选择器")
b. 意为 在任意父元素下 用选择器 查找一个元素
c. 返回值:
1). 如果找到,返回一个元素对象
2). 如果没找到,返回null
d. 强调:
1). 也可以在任意父元素范围内查找,当然也可以在整个网页范围内查找
(2). 查找多个符合要求的元素:
a. var 类数组对象=任意父元素.querySelectorAll("css选择器");
b. 意为: 在任意父元素下 用选择器 查找 所有符合要求的元素
c. 返回值:
1). 如果找到多个符合要求的元素,就放在一个类数组对象中返回
2). 如果没找到符合要求的元素,就返回一个空的类数组对象:{ length:0 }
d. 强调:
1). 也可以在任意父元素范围内查找,当然也可以在整个网页范围内查找。
(3)示例: 购物车
(1). 任何DOM效果,都要经历4步:
a. 查找触发事件的元素
b. 为元素绑定事件处理函数
c. 查找要修改的元素
d. 修改元素
(2). 事件概述:
a. 什么是事件: 浏览器自动触发的或用户手动触发的页面中元素状态的变化。
b. 什么是事件处理函数:提前保存在元素的事件属性上的,当事件发生时,自动执行的函数。
c. 何时使用事件处理函数: ,只要希望当事件发生时,能自动执行一项任务时。
d. 如何使用事件处理函数: ——事件绑定,2种:
1). 在HTML中: 2步:
i. 在网页的<head>中,先定义一个事件处理函数
function 函数名(){
... ...
}
ii. 在元素的开始标签中:<元素 on事件名="函数名()">
iii. 问题: 是将js函数的调用和事件绑定,写在HTML中,不符合内容与行为分离的原则,不便于 的维护!
2). 在js中: 2步:
i. 查找触发事件的元素
ii. 为元素绑定事件处理函数:
元素对象.on事件名=function(){
... ...
}
iii. 原理:
先将事件处理函数,暂存在元素对象身上的事件属性上,暂不执行
将来,当用户触发这个元素上的对应事件时,才自动找出之前暂存的事件处理函数,自动调用!
iv. 优点: 所有事件绑定的代码,都集中定义在js中,极其便于 的维护!
v. 说明: 如果在js中绑定事件,则js代码必须写在<body>元素的结尾!所有网页HTML内容之后。因为网页顺序执行,必须先创建HTML元素,才能在js中查找元素,绑定事件。
e. 如何在事件处理函数中,自动获得当前触发事件的元素:
1). 错误: 用事件处理函数外的全局变量!
原因: 因为事件处理函数的定义和将来的触发之间是有时间差的!而全局变量很可能在这个时间差之内,被篡改为其它值。——不靠谱
2). 正确: 只要想在事件处理函数中获得正在触发事件的当前DOM元素对象,都用this!this可在事件发生时,自动指向当前正在触发的元素对象。
f1. 示例: 为购物车中每个按钮绑定单击事件:
1 <!DOCTYPE HTML> 2 <html> 3 4 <head> 5 <title>使用Selector API实现购物车客户端计算</title> 6 <meta charset="utf-8" /> 7 <style> 8 table { 9 width: 600px; 10 text-align: center; 11 border-collapse: collapse; 12 } 13 14 td, 15 th { 16 border: 1px solid black 17 } 18 19 td[colspan="3"] { 20 text-align: right; 21 } 22 </style> 23 24 </head> 25 26 <body> 27 <table id="data"> 28 <thead> 29 <tr> 30 <th>商品名称</th> 31 <th>单价</th> 32 <th>数量</th> 33 <th>小计</th> 34 </tr> 35 </thead> 36 <tbody> 37 <tr> 38 <td>iPhone6</td> 39 <td>¥4488.00</td> 40 <td> 41 <button>-</button> 42 <span>1</span> 43 <button>+</button> 44 </td> 45 <td>¥4488.00</td> 46 </tr> 47 <tr> 48 <td>iPhone6 plus</td> 49 <td>¥5288.00</td> 50 <td> 51 <button>-</button> 52 <span>1</span> 53 <button>+</button> 54 </td> 55 <td>¥5288.00</td> 56 </tr> 57 <tr> 58 <td>iPad Air 2</td> 59 <td>¥4288.00</td> 60 <td> 61 <button>-</button> 62 <span>1</span> 63 <button>+</button> 64 </td> 65 <td>¥4288.00</td> 66 </tr> 67 </tbody> 68 <tfoot> 69 <tr> 70 <td colspan="3">Total: </td> 71 <td>¥14064.00</td> 72 </tr> 73 </tfoot> 74 </table> 75 <script> 76 //1. 查找触发事件的元素 77 //本例中: 用户点击table中的button触发变化 78 //1.1 先查找id为data的table 79 var table=document.getElementById("data") 80 //1.2 再在table下查找所有的按钮 81 var btns= 82 table.getElementsByTagName("button") 83 console.log(btns); 84 //2. 绑定事件处理函数 85 //本例中: 因为所有的按钮都要绑定单击事件,所以需要遍历找到的每个按钮 86 for(var btn of btns){ 87 //每遍历一个按钮,就为这个按钮绑定单击事件处理函数 88 btn.onclick=function(){ 89 // alert("疼!") 90 //希望,点哪个按钮,就只让哪个按钮的内容变成? 91 //错误: 因为btn是全局变量,很可能发生变化 92 // btn.innerHTML="?"; 93 //正确: 94 this.innerHTML="?"; 95 } 96 } 97 98 //3. 查找要修改的元素 99 //4. 修改元素 100 101 </script> 102 </body> 103 104 </html>
f2. 点按钮,修改数量
1 <!DOCTYPE HTML> 2 <html> 3 4 <head> 5 <title>使用Selector API实现购物车客户端计算</title> 6 <meta charset="utf-8" /> 7 <style> 8 table { 9 width: 600px; 10 text-align: center; 11 border-collapse: collapse; 12 } 13 14 td, 15 th { 16 border: 1px solid black 17 } 18 19 td[colspan="3"] { 20 text-align: right; 21 } 22 </style> 23 24 </head> 25 26 <body> 27 <table id="data"> 28 <thead> 29 <tr> 30 <th>商品名称</th> 31 <th>单价</th> 32 <th>数量</th> 33 <th>小计</th> 34 </tr> 35 </thead> 36 <tbody> 37 <tr> 38 <td>iPhone6</td> 39 <td>¥4488.00</td> 40 <td> 41 <button>-</button> 42 <span>1</span> 43 <button>+</button> 44 </td> 45 <td>¥4488.00</td> 46 </tr> 47 <tr> 48 <td>iPhone6 plus</td> 49 <td>¥5288.00</td> 50 <td> 51 <button>-</button> 52 <span>1</span> 53 <button>+</button> 54 </td> 55 <td>¥5288.00</td> 56 </tr> 57 <tr> 58 <td>iPad Air 2</td> 59 <td>¥4288.00</td> 60 <td> 61 <button>-</button> 62 <span>1</span> 63 <button>+</button> 64 </td> 65 <td>¥4288.00</td> 66 </tr> 67 </tbody> 68 <tfoot> 69 <tr> 70 <td colspan="3">Total: </td> 71 <td>¥14064.00</td> 72 </tr> 73 </tfoot> 74 </table> 75 <script> 76 //1. 查找触发事件的元素 77 //本例中: 用户点击table中的button触发变化 78 //1.1 先查找id为data的table 79 var table=document.getElementById("data") 80 //1.2 再在table下查找所有的按钮 81 var btns= 82 table.getElementsByTagName("button") 83 console.log(btns); 84 //2. 绑定事件处理函数 85 //本例中: 因为所有的按钮都要绑定单击事件,所以需要遍历找到的每个按钮 86 for(var btn of btns){ 87 //每遍历一个按钮,就为这个按钮绑定单击事件处理函数 88 btn.onclick=function(){ 89 //this->当前正在触发事件的按钮元素对象 90 //3. 查找要修改的元素 91 //本例中: 点任何按钮,都是要修改旁边的span 92 // 当前按钮的父元素 的孩子们中第二个 93 var span=this.parentElement.children[1]; 94 //4. 修改元素 95 //4.1 取出元素中现在的旧值,转为整数 96 var n=parseInt(span.innerHTML); 97 //4.2 计算出新值 98 //如果点的按钮的内容是+ 99 if(this.innerHTML=="+"){ 100 n++;//就将n+1 101 }else if(n>1){//否则如果点的按钮的内容是-,且只有n>1时 102 n--;//才将n-1 103 } 104 //4.3 再将新值放回元素中 105 span.innerHTML=n; 106 } 107 } 108 </script> 109 </body> 110 111 </html>
f3.数量变,修改小计
1 <!DOCTYPE HTML> 2 <html> 3 4 <head> 5 <title>使用Selector API实现购物车客户端计算</title> 6 <meta charset="utf-8" /> 7 <style> 8 table { 9 width: 600px; 10 text-align: center; 11 border-collapse: collapse; 12 } 13 14 td, 15 th { 16 border: 1px solid black 17 } 18 19 td[colspan="3"] { 20 text-align: right; 21 } 22 </style> 23 24 </head> 25 26 <body> 27 <table id="data"> 28 <thead> 29 <tr> 30 <th>商品名称</th> 31 <th>单价</th> 32 <th>数量</th> 33 <th>小计</th> 34 </tr> 35 </thead> 36 <tbody> 37 <tr> 38 <td>iPhone6</td> 39 <td>¥4488.00</td> 40 <td> 41 <button>-</button> 42 <span>1</span> 43 <button>+</button> 44 </td> 45 <td>¥4488.00</td> 46 </tr> 47 <tr> 48 <td>iPhone6 plus</td> 49 <td>¥5288.00</td> 50 <td> 51 <button>-</button> 52 <span>1</span> 53 <button>+</button> 54 </td> 55 <td>¥5288.00</td> 56 </tr> 57 <tr> 58 <td>iPad Air 2</td> 59 <td>¥4288.00</td> 60 <td> 61 <button>-</button> 62 <span>1</span> 63 <button>+</button> 64 </td> 65 <td>¥4288.00</td> 66 </tr> 67 </tbody> 68 <tfoot> 69 <tr> 70 <td colspan="3">Total: </td> 71 <td>¥14064.00</td> 72 </tr> 73 </tfoot> 74 </table> 75 <script> 76 //1. 查找触发事件的元素 77 //本例中: 用户点击table中的button触发变化 78 //1.1 先查找id为data的table 79 var table=document.getElementById("data") 80 //1.2 再在table下查找所有的按钮 81 var btns= 82 table.getElementsByTagName("button") 83 console.log(btns); 84 //2. 绑定事件处理函数 85 //本例中: 因为所有的按钮都要绑定单击事件,所以需要遍历找到的每个按钮 86 for(var btn of btns){ 87 //每遍历一个按钮,就为这个按钮绑定单击事件处理函数 88 btn.onclick=function(){ 89 //this->当前正在触发事件的按钮元素对象 90 //3. 查找要修改的元素 91 //本例中: 点任何按钮,都是要修改旁边的span 92 // 当前按钮的父元素 的孩子们中第二个 93 var span=this.parentElement.children[1]; 94 //4. 修改元素 95 //4.1 取出元素中现在的旧值,转为整数 96 var n=parseInt(span.innerHTML); 97 //4.2 计算出新值 98 //如果点的按钮的内容是+ 99 if(this.innerHTML=="+"){ 100 n++;//就将n+1 101 }else if(n>1){//否则如果点的按钮的内容是-,且只有n>1时 102 n--;//才将n-1 103 } 104 //4.3 再将新值放回元素中 105 span.innerHTML=n; 106 107 /*数量修改,修改小计*/ 108 //3. 查找要修改的元素 109 //本例中: 查找当前按钮所在行的最后一个td 110 var lastTd= 111 this.parentElement.nextElementSibling; 112 //当前按钮的父元素td 的下一个兄弟元素td 113 //4. 修改元素 114 //4.1 从当前按钮的父元素td的前一个兄弟元素td中获得单价字符串,去掉开头的¥,再转为小数,获得单价 115 var price=parseFloat(//转为小数 116 this.parentElement//当前按钮的父元素td 117 .previousElementSibling//的前一个兄弟元素td 118 .innerHTML//的内容 119 .slice(1)//去掉开头的¥符号 120 ) 121 //4.2 用单价*数量=小计 122 var subTotal=price*n; 123 //4.3 将小计放回当前行最后一个td的内容中 124 lastTd.innerHTML=`¥${subTotal.toFixed(2)}` 125 } 126 } 127 </script> 128 </body> 129 130 </html>
f5. 小计变,修改总计
1 <!DOCTYPE HTML> 2 <html> 3 4 <head> 5 <title>使用Selector API实现购物车客户端计算</title> 6 <meta charset="utf-8" /> 7 <style> 8 table { 9 width: 600px; 10 text-align: center; 11 border-collapse: collapse; 12 } 13 14 td, 15 th { 16 border: 1px solid black 17 } 18 19 td[colspan="3"] { 20 text-align: right; 21 } 22 /*想修改tfoot中最后一个td的背景颜色为黄色*/ 23 tfoot td:last-child{ 24 background-color: yellow; 25 } 26 /*想修改tbody中每行最后一个td的背景色为粉色*/ 27 tbody td:last-child{ 28 background-color: pink; 29 } 30 </style> 31 32 </head> 33 34 <body> 35 <table id="data"> 36 <thead> 37 <tr> 38 <th>商品名称</th> 39 <th>单价</th> 40 <th>数量</th> 41 <th>小计</th> 42 </tr> 43 </thead> 44 <tbody> 45 <tr> 46 <td>iPhone6</td> 47 <td>¥4488.00</td> 48 <td> 49 <button>-</button> 50 <span>1</span> 51 <button>+</button> 52 </td> 53 <td>¥4488.00</td> 54 </tr> 55 <tr> 56 <td>iPhone6 plus</td> 57 <td>¥5288.00</td> 58 <td> 59 <button>-</button> 60 <span>1</span> 61 <button>+</button> 62 </td> 63 <td>¥5288.00</td> 64 </tr> 65 <tr> 66 <td>iPad Air 2</td> 67 <td>¥4288.00</td> 68 <td> 69 <button>-</button> 70 <span>1</span> 71 <button>+</button> 72 </td> 73 <td>¥4288.00</td> 74 </tr> 75 </tbody> 76 <tfoot> 77 <tr> 78 <td colspan="3">Total: </td> 79 <td>¥14064.00</td> 80 </tr> 81 </tfoot> 82 </table> 83 <script> 84 //1. 查找触发事件的元素 85 //本例中: 用户点击table中的button触发变化 86 //1.1 先查找id为data的table 87 var table=document.getElementById("data") 88 //1.2 再在table下查找所有的按钮 89 var btns= 90 table.getElementsByTagName("button") 91 console.log(btns); 92 //2. 绑定事件处理函数 93 //本例中: 因为所有的按钮都要绑定单击事件,所以需要遍历找到的每个按钮 94 for(var btn of btns){ 95 //每遍历一个按钮,就为这个按钮绑定单击事件处理函数 96 btn.onclick=function(){ 97 //this->当前正在触发事件的按钮元素对象 98 //3. 查找要修改的元素 99 //本例中: 点任何按钮,都是要修改旁边的span 100 // 当前按钮的父元素 的孩子们中第二个 101 var span=this.parentElement.children[1]; 102 //4. 修改元素 103 //4.1 取出元素中现在的旧值,转为整数 104 var n=parseInt(span.innerHTML); 105 //4.2 计算出新值 106 //如果点的按钮的内容是+ 107 if(this.innerHTML=="+"){ 108 n++;//就将n+1 109 }else if(n>1){//否则如果点的按钮的内容是-,且只有n>1时 110 n--;//才将n-1 111 } 112 //4.3 再将新值放回元素中 113 span.innerHTML=n; 114 115 /*数量修改,修改小计*/ 116 //3. 查找要修改的元素 117 //本例中: 查找当前按钮所在行的最后一个td 118 var lastTd= 119 this.parentElement.nextElementSibling; 120 //当前按钮的父元素td 的下一个兄弟元素td 121 //4. 修改元素 122 //4.1 从当前按钮的父元素td的前一个兄弟元素td中获得单价字符串,去掉开头的¥,再转为小数,获得单价 123 var price=parseFloat(//转为小数 124 this.parentElement//当前按钮的父元素td 125 .previousElementSibling//的前一个兄弟元素td 126 .innerHTML//的内容 127 .slice(1)//去掉开头的¥符号 128 ) 129 //4.2 用单价*数量=小计 130 var subTotal=price*n; 131 //4.3 将小计放回当前行最后一个td的内容中 132 lastTd.innerHTML=`¥${subTotal.toFixed(2)}`; 133 134 /*小计改变,修改总计*/ 135 //3. 查找要修改的元素 136 //本例中: 总价计算完,要放入tfoot中最后一个td里! 137 var totalTd=document.querySelector( 138 "tfoot td:last-child" 139 ); 140 console.log(totalTd); 141 //4. 修改元素 142 //4.1 查找tbody中每行最后一个td 143 var tds=document.querySelectorAll( 144 "tbody td:last-child" 145 ); 146 console.log(tds); 147 //4.2 遍历每行最后一个td中的小计,累加到总计中 148 var total=0; 149 for(var td of tds){ 150 //每遍历一个td,就获取td的内容,去掉开头的¥,转为浮点数,并累加到总计变量中 151 total+=parseFloat( 152 td.innerHTML.slice(1) 153 ) 154 } 155 //4.3 将总价格式化之后,再放回总价td中 156 totalTd.innerHTML=`¥${total.toFixed(2)}`; 157 } 158 } 159 160 161 162 </script> 163 </body> 164 165 </html>
四,修改 3种东西: 内容,属性,样式
修改内容
(1). 获取或修改元素的开始标签到结束标签之间的原始的HTML内容:
元素.innerHTML
(2). 获取或修改元素的开始标签到结束标签之间的纯文本内容:
元素.textContent
说明: textContent多做2件事:
1). 去掉了内嵌的HTML标签
2). 将特殊符号翻译为正文
(3). 获取或修改表单元素的值:
a. 问题: 绝大多数表单元素都是input,单标记。没有结束标签!
b. 解决: 只要获取或修改表单元素的值,都要用: 元素.value
(4). 示例: 使用三种方式获取元素的内容:
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta http-equiv="X-UA-Compatible" content="IE=edge"> 6 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 7 <title>Document</title> 8 </head> 9 <body> 10 <h3 id="h3">来自<<<a href="#">新华社</a>>>的消息</h3> 11 <input id="txt" type="text"> 12 <button id="btn">百度一下</button> 13 <script> 14 var h3=document.getElementById("h3"); 15 //获取h3开始标签到结束标签之间的原始的HTML内容 16 console.log(h3.innerHTML); 17 //想获得h3开始标签到结束标签之间的纯文本内容: 18 console.log(h3.textContent); 19 20 //单击按钮时,能获得用户在文本框中输入的内容 21 var btn=document.getElementById("btn"); 22 btn.onclick=function(){ 23 var input=document.getElementById("txt") 24 console.log(`用户想搜索${input.value}相关的内容...`) 25 } 26 </script> 27 </body> 28 </html>
(5). 示例: 动画开关门效果:
1 <!DOCTYPE HTML> 2 <html> 3 <head> 4 <title>读取并修改元素的内容</title> 5 <meta charset="utf-8" /> 6 <style> 7 div{float:left; height: 100px; line-height: 100px; } 8 #d1,#d3{ background-color: #ccff00; } 9 #d2{ cursor: pointer; background-color: #ffcc00; } 10 </style> 11 </head> 12 <body> 13 <div id="d1">树形列表</div> 14 <div id="d2"><<</div> 15 <div id="d3">内容的主体</div> 16 <script> 17 //DOM 4步 18 //1. 查找触发事件的元素 19 //本例中: 用户点d2触发变化 20 var d2=document.getElementById("d2"); 21 //2. 绑定事件处理函数 22 d2.onclick=function(){ 23 //一定不要用函数外部的全局变量"d2", 24 //要用this->当前点的d2 25 //3. 查找要修改的元素 26 //本例中: 点击d2,是要显示隐藏d1 27 var d1=document.getElementById("d1"); 28 //4. 修改元素 29 //如果当前点击的d2的内容是<< 30 if(this.innerHTML=="<<"){ 31 //就把d1隐藏: 32 //HTML中: 33 //<div id="d1" style="display:none"> 34 //js中: ↑ ↑ ↑ 35 d1 .style.display="none"; 36 //顺便把当前点击的d2的内容改为>> 37 this.innerHTML=">>" 38 }else{//否则如果当前点击的d2的内容是>> 39 //就把d1显示 40 d1.style.display="";//不用写block,意为所有元素默认都是显示的. 41 //顺便把当前点击的d2的内容改为<< 42 this.innerHTML="<<" 43 } 44 } 45 </script> 46 </body> 47 </html>
修改属性:3种
(1). 字符串类型的HTML标准属性
a. 什么是: HTML标准中规定的,属性值为字符串类型的属性
b. 比如: id, src, title, href ... ...
c. 如何: 2种方式:
1). 使用旧的核心DOM的4个函数:
i. 获取属性值: 元素.getAttribute("属性名")
ii. 修改属性值: 元素.setAttribute("属性名","属性值")
iii. 判断是否包含某个属性: 元素.hasAttribute("属性名")
iv. 移除属性: 元素.removeAttribute("属性名")
2). 新的HTML DOM中推出了简写:
i. 新的HTML DOM已经提前将所有HTML标准属性,定义在了内存中的元素对象身上。无论用不用,都已经长在内存中的元素对象身上了!只不过,暂时没用到的属性,属性值默认为""
ii. 如何访问内存中的元素对象身上的属性: 元素. 属性名
比如:
获取属性值: 元素.属性名
修改属性值: 元素.属性名="新值"
判断是否包含某个属性: 元素.属性名!==""
移除属性: 元素.属性名=""
d. 示例: 分别使用核心DOM和HTML DOM操作a元素的属性
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta http-equiv="X-UA-Compatible" content="IE=edge"> 6 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 7 <title>Document</title> 8 </head> 9 <body> 10 <a id="a1" href="http://www.cnblog.com" target="_blank">go to myblog</a> 11 <script> 12 var a1=document.getElementById("a1"); 13 //想获取a1的href属性 14 //console.log(a1.getAttribute("href")) 15 console.log(a1.href); 16 //想修改a1的target属性 17 //a1.setAttribute("target","_self"); 18 a1.target="_self"; 19 //判断a1是否包含title属性 20 //console.log(a1.hasAttribute("title"));//false 21 console.log(a1.title!=="") 22 //给a1添加title属性 23 //a1.setAttribute("title","欢迎访问myblog") 24 a1.title="欢迎访问 myblog" 25 //判断a1是否包含title属性 26 //console.log(a1.hasAttribute("title"));//true 27 console.log(a1.title!=="") 28 //移除a1的id属性 29 //a1.removeAttribute("id"); 30 a1.id=""; 31 console.log(a1); 32 console.dir(a1); 33 </script> 34 </body> 35 </html>
e. 特例: class属性:
1). 问题: 按理说,操作class属性,也可以用"元素.class"。但是,因为class是ES标准中的关键字!专门用于创建一种类型!所以,DOM就不能用class再操作样式!DOM中的class属性和ES中的class关键字冲突了!
2). 解决: ,只要在DOM中操作元素的class属性,必须更名为"className"。操作"元素.className",等效于操作<元素 class="xxx">
f. 示例: 手风琴效果:
1 <!DOCTYPE HTML> 2 <html> 3 4 <head> 5 <title>1. 实现伸缩二级菜单</title> 6 <meta charset="utf-8" /> 7 <style> 8 li { 9 list-style: none; 10 } 11 12 li span { 13 padding-left: 20px; 14 cursor: pointer; 15 background: url("../images/add.png") no-repeat center left; 16 } 17 18 li ul { 19 display: none; 20 } 21 22 .open { 23 background: url("../images/minus.png") no-repeat center left; 24 } 25 26 .open+ul { 27 display: block; 28 } 29 </style> 30 </head> 31 32 <body> 33 <ul class="tree"> 34 <li> 35 <span class="open">考勤管理</span> 36 <ul> 37 <li>日常考勤</li> 38 <li>请假申请</li> 39 <li>加班/出差</li> 40 </ul> 41 </li> 42 <li> 43 <span>信息中心</span> 44 <ul> 45 <li>通知公告</li> 46 <li>公司新闻</li> 47 <li>规章制度</li> 48 </ul> 49 </li> 50 <li><span>协同办公</span> 51 <ul> 52 <li>公文流转</li> 53 <li>文件中心</li> 54 <li>内部邮件</li> 55 <li>即时通信</li> 56 <li>短信提醒</li> 57 </ul> 58 </li> 59 </ul> 60 <script> 61 //DOM 4步 62 //1. 查找触发事件的元素 63 //本例中: 用户点击每个span触发变化 64 var spans=document.getElementsByTagName("span") 65 //2. 绑定事件处理函数 66 //本例中: 因为多个span都需要单击,所以遍历每个span 67 for(var span of spans){ 68 //为每个span绑定单击事件 69 span.onclick=function(){ 70 //尽量不要用函数外部的spans和span——不靠谱 71 //this->当前点击的这一个span 72 //3. 查找要修改的元素 73 //4. 修改元素 74 //先找到所有的span,清除他们身上的class=open 75 var spans=document.getElementsByTagName("span"); 76 for(var span of spans){ 77 span.className=""; 78 //<span class=""> 79 } 80 //再只给当前span自己加class="open" 81 this.className="open"; 82 } 83 } 84 85 </script> 86 </body> 87 88 </html>
(2). bool类型HTML标准属性: 1种
a. 什么是: HTML标准规定的,只要写在元素开始标签中就起作用的属性,无需指定属性值。
b. 比如: checked, selected, disabled, ...
c. 如何:
1). 不能用核心DOM的4个函数: 因为核心DOM的4个函数,不支持bool类型的值!只支持字符串类型的属性值。
2). 只能用HTML DOM的简写: 元素.属性名,且,属性值必须是bool类型。
d. 补: CSS3中的状态伪类选择器: :checked 专门匹配已选中的元素
e. 示例: 全选和取消全选:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8" /> 5 <title>全选和取消全选</title> 6 </head> 7 <body> 8 <h2>管理员列表</h2> 9 <table border="1px" width="500px"> 10 <thead> 11 <tr> 12 <th><input type="checkbox"/>全选</th> 13 <th>管理员ID</th> 14 <th>姓名</th> 15 <th>操作</th> 16 </tr> 17 </thead> 18 <tbody> 19 <tr> 20 <td><input type="checkbox"/></td> 21 <td>1</td> 22 <td>Tester</td> 23 <td>修改 删除</td> 24 </tr> 25 <tr> 26 <td><input type="checkbox"/></td> 27 <td>2</td> 28 <td>Manager</td> 29 <td>修改 删除</td> 30 </tr> 31 <tr> 32 <td><input type="checkbox"/></td> 33 <td>3</td> 34 <td>Analyst</td> 35 <td>修改 删除</td> 36 </tr> 37 <tr> 38 <td><input type="checkbox"/></td> 39 <td>4</td> 40 <td>Admin</td> 41 <td>修改 删除</td> 42 </tr> 43 </tbody> 44 </table> 45 <script> 46 /*1. 先实现点击全选,选中下方所有checkbox*/ 47 //DOM 4步 48 //1. 查找触发事件的元素 49 //本例中: 用户点击thead中的input,触发全选 50 var chbAll= 51 document.querySelector("thead input"); 52 //2. 绑定事件处理函数 53 chbAll.onclick=function(){ 54 //不能用外部的chbAll 55 //this->当前点击的thead中的checkbox 56 //3. 查找要修改的元素 57 //本例中: 点thead中的input,需要同时修改tbody中所有input 58 var chbs= 59 document.querySelectorAll("tbody input"); 60 //4. 修改元素 61 //本例中: 遍历找到的tbody中所有input,修改每个input的checked状态 62 for(var chb of chbs){ 63 chb.checked=this.checked; 64 } 65 } 66 67 /*2. 点tbody中的checkbox,也影响thead中的全选checkbox*/ 68 //DOM 4步 69 //1. 查找触发事件的元素 70 //本例中: 查找tbody中所有input元素 71 var chbs= 72 document.querySelectorAll("tbody input"); 73 //2. 绑定事件处理函数 74 //本例中: 多个chb都要绑定单击事件,所以遍历 75 for(var chb of chbs){ 76 chb.onclick=function(){ 77 //3. 查找要修改的元素 78 //本例中: 点tbody中的chb,有可能影响thead中的chb 79 var chbAll= 80 document.querySelector("thead input") 81 //4. 修改元素 82 //尝试查找tbody中一个未选中的input 83 var unchecked=document.querySelector( 84 "tbody input:not(:checked)" 85 ); 86 //如果找到未选中的input 87 if(unchecked!=null){ 88 //则顶上的chbAll就不选中 89 chbAll.checked=false; 90 }else{//否则如果没找到未选中的input 91 //则顶上的chbAll就选中 92 chbAll.checked=true; 93 } 94 } 95 } 96 </script> 97 </body> 98 </html>
(3). 自定义扩展属性
a. 什么是: HTML标准中没有规定的,程序员根据自身的需要自发添加的自定义属性。
b. 何时: 2种:
1). 自定义扩展属性,经常用来代替id选择器、类选择器、元素选择器作为触发事件的元素。
i. 其它选择器的问题:
id选择器: 一次只能选一个元素
类选择器: 类选择器本职工作是定义样式!因为样式经常修改,所以元素的class经常被修改。如果查找元素时,使用类选择器查找,则一旦class被修改,js中的交互行为也会被破坏!
元素选择器: 实现同一种效果,可用的元素种类有很多,也可能发生变化。如果用元素选择器查找触发事件的元素,则一旦元素改变,js中的交互行为,又会被破坏!
ii. 解决: 项目中,几乎所有的触发事件的元素,都要用自定义属性查找!
iii. 好处: 将来即使class名和标签名发生变化,也不会影响js的交互行为!
2). 在客户端网页中临时缓存个别业务数据:
i. 问题: 有些常用的数据,如果每次触发事件时,都要反复向服务器请求,则请求次数过多,速度慢,且增大服务器的压力
ii. 解决: 如果频繁使用的业务数据,可以在首次加载时,就提前请求到客户端,保存在HTML元素自己身上的自定义属性中
iii. 好处: 将来反复触发事件时,只要从当前元素自己身上获得自定义属性值即可!无需反复请求服务器端。极大的加快了响应速度,极大的减轻了服务器端的压力。
c. 如何:
1). 手工在HTML中添加自定义扩展属性:
<元素 data-任意自定义属性名="属性值"> xxx </元素>
2). 在js中获取或修改自定义扩展属性: 2种:
i. 旧核心DOM2个函数:
元素.getAttribute("data-自定义属性名")
元素.setAttribute("data-自定义属性名","新属性值")
ii. 新HTML5标准: 前提: 如果HTML中的自定义属性是以data-开头
元素.dataset.自定义属性名="属性值"
强调:
①dataset专门操作html中以data-开头的自定义扩展属性。所以,项目中强烈建议所有自定义扩展属性,都要用data-开头!
②虽然在HTML中自定义扩展属性以data-开头的,但是,js中dataset后的自定义属性名无需data-开头
d. 示例: 使用自定义属性记录按钮单击次数:
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta http-equiv="X-UA-Compatible" content="IE=edge"> 6 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 7 <title>Document</title> 8 </head> 9 <body> 10 <button data-btn data-n="0">click me</button> 11 <script> 12 //DOM 4步: 13 //1. 查找触发事件的元素 14 //本例中: 就是要点带有data-btn属性的按钮\ 15 16 var btn=document.querySelector("[data-btn]"); 17 //2. 绑定事件处理函数 18 btn.onclick=function(){ 19 //3. 查找要修改的元素 20 //本例中:就是要修改自己this 21 //4. 修改元素 22 //4.1 获取出当前按钮身上自定义属性data-n中保存的单击次数,转为整数 23 var n=parseInt( 24 //旧核心DOM 25 // this.getAttribute("data-n") 26 //新HTML5 27 this.dataset.n 28 ); 29 //4.2 将单击次数+1 30 n++; 31 //4.3 将新的单击次数,再放回当前按钮身上的data-n属性中 32 //旧核心DOM 33 // this.setAttribute("data-n",n); 34 //新HTML5 35 this.dataset.n=n; 36 } 37 </script> 38 </body> 39 </html>
e. 示例: 标签页效果:
1 <!DOCTYPE HTML> 2 <html> 3 <head> 4 <title>读取并修改元素的属性</title> 5 <meta charset="utf-8" /> 6 <style> 7 *{ 8 margin:0; 9 padding: 0; 10 } 11 #tab li{ 12 float: left; list-style: none; 13 } 14 #tab li a{ 15 display:inline-block; 16 text-decoration:none; 17 width: 80px; height: 40px; 18 line-height: 40px; 19 text-align: center; 20 color:#000; 21 } 22 #container{ 23 position: relative; 24 } 25 #content1,#content2,#content3{ 26 width: 300px; 27 height: 100px; 28 padding:30px; 29 position: absolute; 30 top: 40px; 31 left: 0; 32 } 33 #tab li:first-child,#content1{ 34 background-color: #ffcc00; 35 } 36 #tab li:first-child+li,#content2{ 37 background-color: #ff00cc; 38 } 39 #tab li:first-child+li+li,#content3{ 40 background-color: #00ccff; 41 } 42 </style> 43 44 </head> 45 <body> 46 <h2>实现多标签页效果</h2> 47 <div class="tabs"> 48 <ul id="tab"> 49 <li><a data-tab data-id="content1" href="#content1">10元套餐</a></li> 50 <li><a data-tab data-id="content2" href="#content2">30元套餐</a></li> 51 <li><a data-tab data-id="content3" href="#content3">50元包月</a></li> 52 </ul> 53 <div id="container"> 54 <div id="content1" style="z-index:10"> 55 10元套餐详情:<br /> 每月套餐内拨打100分钟,超出部分2毛/分钟 56 </div> 57 <div id="content2"> 58 30元套餐详情:<br /> 每月套餐内拨打300分钟,超出部分1.5毛/分钟 59 </div> 60 <div id="content3"> 61 50元包月详情:<br /> 每月无限量随心打 62 </div> 63 </div> 64 </div> 65 <script> 66 //DOM 4步 67 //1. 查找触发事件的元素 68 //本例中: 69 //1.1 先手工的为每个a都添加data-tab自定义属性 70 //1.2 再查找带有data-tab属性的元素 71 var tabs= 72 document.querySelectorAll("[data-tab]") 73 //附加步骤: 先定义一个z=10,用来临时保存目前为止最大的zIndex值 74 var z=10; 75 //2. 绑定事件处理函数 76 //本例中: 因为所有tab按钮都要绑定单击事件,所以遍历 77 for(var tab of tabs){ 78 tab.onclick=function(){ 79 //3. 查找要修改的元素 80 //本例中: 每单击一个tab,就要找到当前tab对应的div是谁? 81 //3.1 先手工为每个a添加data-id属性,值为当前a对应的div的id名 82 //3.2 再在程序中获得当前点击的按钮身上自定义属性data-id中保存的对应div的id名 83 var id名=this.dataset.id; 84 //this.getAttribute("data-id") 85 //3.3 用获得的id名查找当前点击的a对应的div 86 // 不要加"" 87 // 因为id名是变量 88 var div=document.getElementById(id名); 89 //4. 修改元素 90 //4.1 先将z值+1 91 z++; 92 //4.2 再将新的最大的z值设置给找到的对应div的style的zIndex属性上 93 //错误: 虽然css中确实是z-index,但是js中不允许随便用-,会和减法的-冲突! 94 // div.style.z-index=z; 95 //正确: 项目中凡是带-的css属性名,必须去横线变驼峰 96 div.style.zIndex=z; 97 } 98 } 99 //希望开局默认显示第一个标签页对应的div的内容,需要手工为第一个div添加style="z-index:10" 100 </script> 101 </body> 102 </html>
修改样式
(1). 修改内联样式:
a. 元素对象.style.css属性="属性值"
b. 相当于手工: <元素 style="css属性:属性值">
c. 强调:
1). 大小、距离、位置相关的属性,必须加单位(px, rem等)
2). 如果css属性名中带-,则必须改为去横线变驼峰,比如:
z-index 应改为 zIndex
font-size 应改为 fontSize
background-color 应改为 backgroundColor
(2). 获取完整样式:
a. 问题: 元素.style只能表示内联样式,无法包含除内联样式之外的其它地方定义的样式。如果用元素.style方式获取元素的样式,一定会丢掉大部分其它地方定义的样式属性!
b. 解决: 项目中如果想获得一个元素所有css属性的集合,应该获得计算后的样式!
1). 什么是计算后的样式: 最终能够应用到这个元素上的所有css属性的集合!
2). 如何: 2步:
i. 先获得包含计算后的所有css属性的集合对象:
var style=getComputedStyle(元素对象)
浏览器内置函数,无需定义,即可直接使用!
ii. 再从style集合对象中提取出想用的个别css属性值
style.css属性名
c. 坑: 计算后的样式都是只读的,禁止修改的!因为计算后的样式来源不确定!一旦擅自修改,很可能牵一发而动全身!
(3). 总结: 项目中:
a. 如果想获取样式时,首选getComputedStyle()
b. 如果想修改样式时,首选.style
(4). 示例: 获取或修改h1元素的样式:
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta http-equiv="X-UA-Compatible" content="IE=edge"> 6 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 7 <title>Document</title> 8 <style> 9 h1{ 10 background-color:red; 11 } 12 </style> 13 </head> 14 <body> 15 <h1 id="h1" style="color:yellow">Welcome</h1> 16 <p>Welcome dingding</p> 17 <script> 18 var h1=document.getElementById("h1"); 19 //想获得h1元素的完整样式: 20 // 不要加引号 21 // 上一句话查找得到的 22 // 引用h1元素对象的变量 23 var style=getComputedStyle(h1); 24 //想获得h1的字体颜色 25 //正确: 但是不好 26 // console.log(h1.style.color); 27 //正确: 28 console.log(style.color); 29 //想获得h1的背景颜色 30 //错误: 31 // console.log(h1.style.backgroundColor); 32 //正确: 33 console.log(style.backgroundColor); 34 //想获得h1的字体大小 35 //错误: 36 // console.log(h1.style.fontSize); 37 //正确: 38 console.log(style.fontSize); 39 40 //想修改h1的字体大小为64px; 41 //错误: 42 // style.fontSize="64px";//Failed to set the ‘font-size‘ property on ‘CSSStyleDeclaration‘: These styles are computed, and therefore the ‘font-size‘ property is read-only 43 //正确: 44 h1.style.fontSize="64px"; 45 </script> 46 </body> 47 </html>
(4). 问题: 用.style.css属性方式修改元素的样式,一次只能修改一个css属性值。如果再一次交互行为中,需要同时修改一个元素的多个css属性,代码就会很繁琐!
(5). 解决: 项目中只要批量修改一个元素的多个css属性,都应该用class属性代替style属性
(6). 如何: 2步:
a. 先在css中,为元素定义好不同情况下的样式类套装:
b. 再在js中根据不同的情况,更换元素的className为不同的css样式类名。
(7). 示例: 带样式的表单验证:
1 <!doctype html> 2 <html> 3 4 <head> 5 <meta charset="UTF-8"> 6 <title>实现带样式的表单验证</title> 7 <style> 8 table { 9 width: 700px 10 } 11 12 td:first-child { 13 width: 60px 14 } 15 16 td:nth-child(2) { 17 width: 200px 18 } 19 20 td:first-child+td { 21 width: 200px 22 } 23 24 td span { 25 color: red 26 } 27 28 .vali_info { 29 display: none; 30 } 31 32 .txt_focus { 33 border-top: 2px solid black; 34 border-left: 2px solid black; 35 } 36 37 .vali_success, 38 .vali_fail { 39 background-repeat: no-repeat; 40 background-position: left center; 41 display: block; 42 } 43 44 .vali_success { 45 background-image: url("对应×的图片"); 46 padding-left: 20px; 47 width: 0px; 48 height: 20px; 49 overflow: hidden; 50 } 51 52 .vali_fail { 53 background-image: url("对应√的图片"); 54 border: 1px solid red; 55 background-color: #ddd; 56 color: Red; 57 padding-left: 30px; 58 } 59 </style> 60 </head> 61 62 <body> 63 <form id="form1"> 64 <h2>增加管理员</h2> 65 <table> 66 <tr> 67 <td>姓名:</td> 68 <td> 69 <input name="username" /> 70 <span>*</span> 71 </td> 72 <td> 73 <div class="vali_info"> 74 10个字符以内的字母、数字或下划线的组合 75 </div> 76 </td> 77 </tr> 78 <tr> 79 <td>密码:</td> 80 <td> 81 <input type="password" name="pwd" /> 82 <span>*</span> 83 </td> 84 <td> 85 <div class="vali_info">6位数字</div> 86 </td> 87 </tr> 88 <tr> 89 <td></td> 90 <td colspan="2"> 91 <input type="submit" value="保存" /> 92 <input type="reset" value="重填" /> 93 </td> 94 </tr> 95 </table> 96 </form> 97 <script> 98 //DOM 4步 99 //1. 查找触发事件的元素 100 //本例中: 当姓名文本框失去焦点时触发验证 101 var txtName= document.getElementsByName("username")[0]; 102 //2. 绑定事件处理函数 103 104 txtName.onblur=function(){ 105 //3. 查找要修改的元素 106 //本例中: 当文本框失去焦点时,会修改旁边的div的样式: 当前文本框的爹的下一个兄弟的第一个孩子 107 var div=this //当前input文本框 108 .parentElement //当前文本框的爹td 109 .nextElementSibling //当前td的下一个兄弟td 110 .children[0];//下一个兄弟td的第一个孩子 111 //4. 修改元素 112 //4.1 先定义正则表达式描述姓名的规则 113 ////是js中正则表达式的标志 114 //^表示字符串开头位置 115 //$表示字符串结尾位置 116 //^和$连用表示必须从头到尾完整匹配! 117 //\w表示字母或数字或下划线,相当于[0-9A-Za-z_] 118 //{}在正则中表示数量 119 //{最少个数, 最多个数} 120 //比如:{1,10}表示至少1个字,最多10个字 121 var reg=/^\w{1,10}$/; 122 //4.2 再用正则表达式验证当前文本框中用户输入的内容 123 var result=reg.test(this.value); 124 //4.3 如果验证通过 125 if(result==true){ 126 //才修改div的className为vali_success 127 div.className="vali_success"; 128 }else{//4.4 否则如果验证未通过 129 //就修改div的className为vali_fail 130 div.className="vali_fail"; 131 } 132 } 133 </script> 134 </body> 135 136 </html>
五,添加删除替换元素:
1. 添加一个新元素: 3步
(1). 先创建一个新的空元素对象:
a. var 新元素=document.createElement("标签名")
b. 意为: 创建 元素
c. 返回值: 返回一个新创建的元素对象
d. 强调: .前的主语必须是document
e. 比如: 想创建一个a元素:
var a=document.createElement("a");
结果: <a></a>
(2). 为新的空元素添加必要的属性:
比如: 想让a当做超链接使用跳转到tmooc
a.innerHTML="go to tmooc"
a.href="http://tmooc.cn"
结果: <a href="http://tmooc.cn">go to tmooc</a>
(3). 必须将新元素添加到DOM树上指定位置,才能在网页中显示出来,供人们使用!
a. 在一个父元素下所有子元素末尾追加一个新元素:
父元素.appendChild(新元素)
追击 孩子
b. 在一个父元素下的一个现有子元素之前插入一个新元素
父元素.insertBefore(新元素, 现有子元素)
插入到xxx之前
c. 替换一个父元素下的一个现有子元素
父元素.replaceChild(新元素, 现有子元素)
示意图:
2. 示例: 添加一个a元素和一个文本框:
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta http-equiv="X-UA-Compatible" content="IE=edge"> 6 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 7 <title>Document</title> 8 </head> 9 <body> 10 <script> 11 //想在页面中添加一个a元素 12 //1. 创建一个新的空的a元素对象 13 var a=document.createElement("a"); 14 //2. 为a设置必要的关键属性 15 a.innerHTML="go to tmooc"; 16 a.href="http://tmooc.cn"; 17 console.log(a); 18 //3. 将a添加到body的末尾 19 document.body.appendChild(a); 20 21 //想再创建一个普通文本框元素 22 var input=document.createElement("input"); 23 //想把文本框放在a之前? 24 document.body.insertBefore(input,a); 25 //想把文本框放在a之后? 26 // a.body.appendChild(input); 27 //想用文本框代替a? 28 // document.body.replaceChild(input,a); 29 </script> 30 </body> 31 </html>
3. 示例: 动态生成表格:
1 <!DOCTYPE HTML> 2 <html> 3 <head> 4 <title>动态创建表格</title> 5 <meta charset="utf-8" /> 6 <style> 7 table{width:600px; border-collapse:collapse; 8 text-align:center; 9 } 10 td,th{border:1px solid #ccc} 11 </style> 12 13 </head> 14 <body> 15 <div id="data"> 16 <table> 17 <thead> 18 <tr> 19 <th>姓名</th> 20 <th>薪资</th> 21 <th>年龄</th> 22 </tr> 23 </thead> 24 </table> 25 </div> 26 <script> 27 var json=[ 28 { 29 "ename":"Tom", "salary":11000, "age":25 30 }, 31 { 32 "ename":"John", "salary":13000, "age":28 33 }, 34 { 35 "ename":"Mary", "salary":12000, "age":25 36 } 37 ]; 38 //0. 手工在<div id="data">内部创建table和表头行内容 39 //1. 动态创建表格,显示数组中的内容 40 //1.1 先创建tbody, *暂时不要*追加到table中 41 //1.1.1 先创建一个新的空tbody 42 var tbody=document.createElement("tbody"); 43 //1.1.2 再查找id为data的div下的table 44 var table=document.querySelector("#data>table"); 45 //*暂时不要追加到table中* 46 //1.2 遍历json数组中每个员工对象 47 //因为json数组是索引数组,所以用 48 // Employee 49 // 一个员工对象 50 for(var emp of json){ 51 //每遍历一个员工对象,就创建一个tr,追加tbody 52 var tr=document.createElement("tr"); 53 tbody.appendChild(tr); 54 //1.3 进一步遍历当前员工对象中每个属性 55 //因为是遍历对象中每个属性,所以 56 for(var key in emp){ 57 //每遍历一个属性,就创建一个td,追加到tr中 58 var td=document.createElement("td"); 59 tr.appendChild(td); 60 //设置当前td的内容为当前属性的属性值 61 td.innerHTML=emp[key]; 62 } 63 } 64 //原1.1.3剪切到此;(为了页面不至于多次的重绘重排) 65 //4. 最后再一次性将tbody追加到table中 66 table.appendChild(tbody); 67 </script> 68 </body> 69 </html>
4. 优化:
(1). 问题: 每修改一个DOM结构,都会导致整个网页重排重绘,如果频繁修改DOM树结构,就会导致频繁重排重绘,极大的降低网页加载效率。
(2). 解决: 项目中,动态生成元素时,一定更要想尽办法,尽量减少操作DOM树的次数!就可以减少重排重绘的次数
(3). 如何: 2种:
a. 如果父元素和子元素都是动态生成的,则不要过早将父元素添加到DOM树。而是先在内存中,将所有子元素,添加到父元素上之后,最后再一次性将父元素添加到DOM树。——只需要更新一次DOM树,一次重排重绘即可!
b. 如果父元素已经在DOM树上了,只是动态生成子元素而已。就必须借助于文档片段对象来减少重排重绘的次数。
1). 什么是文档片段对象: 是内存中临时保存多个平级子元素的虚拟父元素。
2). 如何: 3步:
i. 创建文档片段对象
var 文档片段对象=document.createDocumentFragment();
创建 文档 片段
ii. 将多个平级子元素添加到文档片段对象中暂存
iii. 最后再一次性将整个文档片段对象添加到DOM树上指定父元素下
3). 强调: 文档片段对象将多个子元素添加到DOM树之后,就自动释放了!不会成为页面上真正的一级元素!
4). 示例: tbody已经在table中了,既要用文档片段动态添加子元素。
1 <!DOCTYPE HTML> 2 <html> 3 4 <head> 5 <title>动态创建表格</title> 6 <meta charset="utf-8" /> 7 <style> 8 table { 9 width: 600px; 10 border-collapse: collapse; 11 text-align: center; 12 } 13 14 td, 15 th { 16 border: 1px solid #ccc 17 } 18 </style> 19 20 </head> 21 22 <body> 23 <div id="data"> 24 <table> 25 <thead> 26 <tr> 27 <th>姓名</th> 28 <th>薪资</th> 29 <th>年龄</th> 30 </tr> 31 </thead> 32 <tbody> 33 </tbody> 34 </table> 35 </div> 36 <script> 37 var json = [ 38 { 39 "ename": "Tom", "salary": 11000, "age": 25 40 }, 41 { 42 "ename": "John", "salary": 13000, "age": 28 43 }, 44 { 45 "ename": "Mary", "salary": 12000, "age": 25 46 } 47 ]; 48 //1. 动态创建表格,显示数组中的内容 49 //0. 手工在<div id="data">内部创建table和表头行内容 50 //假设tbody已经手工添加到页面上table中了 51 //1.1 先创建文档片段对象 52 var frag = document.createDocumentFragment(); 53 //1.2 遍历json数组中每个员工对象 54 //因为json数组是索引数组,所以用 55 // Employee 56 // 一个员工对象 57 for (var emp of json) { 58 //每遍历一个员工对象,就创建一个tr,追加文档片段对象 59 var tr = document.createElement("tr"); 60 frag.appendChild(tr); 61 //1.3 进一步遍历当前员工对象中每个属性 62 //因为是遍历对象中每个属性,所以 63 for (var key in emp) { 64 //每遍历一个属性,就创建一个td,追加到tr中 65 var td = document.createElement("td"); 66 tr.appendChild(td); 67 //设置当前td的内容为当前属性的属性值 68 td.innerHTML = emp[key]; 69 } 70 } 71 //4. 最后再一次性将文档片段对象追加到table中tbody内 72 var tbody = 73 document.querySelector("#data>table>tbody"); 74 tbody.appendChild(frag); 75 </script> 76 </body> 77 78 </html>
5. 删除元素: 父元素.removeChild(子元素)
移除 孩子
6. 示例: 为表格添加删除行的功能:
1 <!DOCTYPE HTML> 2 <html> 3 <head> 4 <title>动态创建表格</title> 5 <meta charset="utf-8" /> 6 <style> 7 table{width:600px; border-collapse:collapse; 8 text-align:center; 9 } 10 td,th{border:1px solid #ccc} 11 </style> 12 13 </head> 14 <body> 15 <div id="data"> 16 <table> 17 <thead> 18 <tr> 19 <th>姓名</th> 20 <th>薪资</th> 21 <th>年龄</th> 22 <th>操作</th><!--手工为表头行多加一格--> 23 </tr> 24 </thead> 25 </table> 26 </div> 27 <script> 28 var json=[ 29 { 30 "ename":"Tom", "salary":11000, "age":25 31 }, 32 { 33 "ename":"John", "salary":13000, "age":28 34 }, 35 { 36 "ename":"Mary", "salary":12000, "age":25 37 } 38 ]; 39 //0. 手工在<div id="data">内部创建table和表头行内容 40 //1. 动态创建表格,显示数组中的内容 41 //1.1 先创建tbody, *暂时不要*追加到table中 42 //1.1.1 先创建一个新的空tbody 43 var tbody=document.createElement("tbody"); 44 //1.1.2 再查找id为data的div下的table 45 var table=document.querySelector("#data>table"); 46 //*暂时不要追加到table中* 47 //1.2 遍历json数组中每个员工对象 48 //因为json数组是索引数组,所以用 49 // Employee 50 // 一个员工对象 51 for(var emp of json){//外层循环为了添加行tr 52 //每遍历一个员工对象,就创建一个tr,追加tbody 53 var tr=document.createElement("tr"); 54 tbody.appendChild(tr); 55 //1.3 进一步遍历当前员工对象中每个属性 56 //因为是遍历对象中每个属性,所以 57 for(var key in emp){//内层循环为tr中添加td 58 //每遍历一个属性,就创建一个td,追加到tr中 59 var td=document.createElement("td"); 60 tr.appendChild(td); 61 //设置当前td的内容为当前属性的属性值 62 td.innerHTML=emp[key]; 63 } 64 /*实现点击按钮删除行*/ 65 //先在添加完所有的数据格td之后,再在当前行内额外添加一个td 66 var td=document.createElement("td"); 67 tr.appendChild(td); 68 //再创建一个button,将button放入td中 69 var btn=document.createElement("button"); 70 btn.innerHTML="×"; 71 td.appendChild(btn); 72 //为按钮绑定单击事件: 73 btn.onclick=function(){ 74 //点哪个按钮,让当前按钮变成花 75 // this.innerHTML="?"; 76 //找到当前按钮所在的行tr 77 var tr=this //当前按钮 78 .parentElement //当前td 79 .parentElement; //当前tr 80 //找到tbody: 其实就是tr的父元素 81 var tbody=tr.parentElement; 82 //获得当前行中的员工姓名?就是当前行中第一个子元素td的内容 83 var ename=tr.children[0].innerHTML; 84 //先跟用户确认是否继续删除 85 var result= 86 confirm(`是否继续删除 ${ename} 吗?`); 87 //如果用户确认要删除当前行了,才 88 if(result==true){ 89 //真正用tbody删除当前tr 90 tbody.removeChild(tr); 91 } 92 } 93 } 94 //原1.1.3剪切到此: 95 //4. 最后再一次性将tbody追加到table中 96 table.appendChild(tbody); 97 </script> 98 </body> 99 </html>
扩充小知识:
浏览器中三大对话框:
1. 如果想请用户输入一个字符串: 用输入框:
var str=prompt("提示信息");.
2. 如果想警告用户一件事: 用警告框
alert("警告信息")
3. 如果想跟用户确认是否继续时: 用确认框
var result=confirm("确认信息")
含返回值 如果是确定的话放回true 取消的话返回false;
原文:https://www.cnblogs.com/CIBud/p/14409783.html