【DOM】DOM概述及DOM操作之如何查找元素_01
目录
一. 什么是DOM
二. 什么是DOM树
三. 查找元素: 4种:
1. 不需要查找就可直接获得的元素: 4种:
2. 按节点间关系查找:
a. 节点树: 包含所有网页内容的完整树结构: 2大类关系, 6个属性
1). 父子关系: 4个属性
2). 兄弟关系: 2个属性
e. 元素树: 2大类关系, 6个属性
1). 父子关系:
2). 兄弟关系: 2个
3. 按HTML特征查找: 4个函数:
(1). 按id查找一个元素对象:
(2). 按标签名查找多个元素对象:
(3). 按class名查找多个元素
(4). 按name名查找多个表单元素:
4. 按选择器查找元素:
a. 只查找一个符合要求的元素:
b. 查找多个符合要求的元素:
四. 购物车案例:
五. 事件概述:
⬛总结: DOM 5件事: 增删改查+事件绑定:
一. 什么是DOM
Document Object Model
文档 对象 模型
1. 什么是DOM:一套专门操作网页内容的对象和函数的集合
🌱当网页被浏览器加载时,浏览器会创建文档对象模型(Document Object Model)
(1). DOM的释义
DOM (Document Object Model) 译为文档对象模型,是 HTML 和 XML 文档的编程接口。
(2). DOM操作的分类
使用JavaScript操作DOM时分为三个方面:DOM Core(核心)、HTML-DOM和CSS-DOM。
2. 何时使用DOM: 今后只要想用js程序操作网页内容,都必须使用DOM提供的对象和方法。
🌱DOM作用——使JS有访问HTML的能力,能够实现对HTML中内容的操作
3. DOM标准: W3C制定的专门操作网页的内容的对象和函数的标准
4. 好处: 几乎所有浏览器100%兼容DOM标准。
5. 能做什么: 增删改查+事件绑定
二. 什么是DOM树
1. 什么是DOM树
在内存中,专门保存一个网页中所有内容的树形结构
2. 为什么使用DOM
树形结构可以直观的展现上下级包含关系!又因为网页的内容刚好也是上下级包含关系的。
3. 如何使用DOM:
(1). 每当浏览器读取到一个网页文件时,先会创建一个树根节点对象——document
(2). 浏览器开始扫描网页中的每一项内容(元素, 文本, 属性...)。每扫描到一项内容,就会在DOM 树上相应位置创建一个节点对象,来保存扫描到的内容。
三. 查找元素: 4种:
1. 不需要查找就可直接获得的元素: 4种:
(1). 根节点对象 document
(2). document.documentElement
(3). document.head
(4). document.body
(5). 示例:输出不需要查找就可获得的四个节点的DOM树关系和节点对象本身的属性
1_domTree.html
DOM Tree Hello 标题一
//用两种方式输出document节点对象 console.log(document); //输出DOM树 console.dir(document); //输出一个对象的存储结构 //用两种方式输出元素节点对象 console.log(document.documentElement); console.dir(document.documentElement); //用两种方式输出元素节点对象 console.log(document.head); console.dir(document.head); //用两种方式输出元素节点对象 console.log(document.body); console.dir(document.body);
运行结果:
2. 按节点间关系查找:
(1). 何时: 如果我们已经获得一个元素,想找它周围附近的元素时
(2). 如何: 其实在内存中有两种DOM树:
a. 节点树: 包含所有网页内容的完整树结构: 2大类关系, 6个属性
1). 父子关系: 4个属性
i. 获得一个节点对象的父节点: 节点对象.parentNode
父 节点
ii. 获得一个节点下所有直接子节点的集合: 节点对象.childNodes
子 节点们
iii. 获得一个节点下第一个直接子节点: 节点对象.firstChild
第一个孩子
iv. 获得一个节点下最后一个直接子节点: 节点对象.lastChild
最后一个孩子
2). 兄弟关系: 2个属性
i. 前一个相邻的兄弟节点: 当前节点.previousSibling
前一个兄弟
ii. 后一个相邻的兄弟节点: 当前节点.nextSibling
下一个兄弟
b. 问题: 节点树中连看不见的空字符,也会被认为是文本节点对象,严重干扰我们的查找
c. 解决: 新版DOM标准中,新增了一种新的树/关系,叫元素树。好处是,只包含元素节点,不包含文本节点,不受看不见的空字符节点的干扰!所以,今后,只要按节点间关系查找元素,都用元素树关系。不用节点树关系了。
d. 什么是元素树: 只包含元素节点,不包含文本节点的树结构
e. 元素树: 2大类关系, 6个属性
1). 父子关系:
i. 获得当前元素的父元素: 元素.parentElement
父 元素
ii. 获得当前元素的所有直接子元素: 元素.children
孩子们
iii. 获得当前元素的第一个直接子元素: 元素.firstElementChild
第一个 元素 孩子
iv. 获得当前元素的最后一个直接子元素: 元素.lastElementChild
最后一个 元素 孩子
2). 兄弟关系: 2个
i. 前一个兄弟元素: 元素.previousElementSibling
前一个 元素 兄弟
ii. 后一个兄弟元素: 元素.nextElementSibling
后一个 元素 兄弟
(3). 示例: 使用元素树关系查找想要的元素
1_domTree2.html
DOM Tree Hello 标题一
//强调: 任何元素都必须先查找再使用! //获得body元素 var body = document.body; console.log(body); //获得body下第一个孩子span //错误: // var span=body.firstChild; //正确: var span = body.firstElementChild; console.log(span); //获得span的下一个兄弟h1 //错误: // var h1=span.nextSibling; var h1 = span.nextElementSibling; console.log(h1); //判断h1的父元素是不是body元素 console.log(h1.parentElement == body); //true
运行结果:
Hello
标题一
true
3. 按HTML特征查找: 4个函数:
(1). 按id查找一个元素对象:
a. var 一个元素对象=document.getElementById("id名")
在网页中 查找 元素 按id
b. 意为: 在整个页面中查找id为指定id名的一个元素对象
c. 返回值:
1). 如果找到,只能返回一个元素对象
2). 如果没找到,返回null
d. 强调:
1). .前的主语必须是document
2). 因为只找到一个,所以函数名中的element是单数,没有s结尾
(2). 按标签名查找多个元素对象:
a. var 类数组对象=任意父元素.getElementsByTagName("标签名");
在任意父元素内查找多个元素按标签名
b. 意为: 在一个指定的父元素范围内,查找所有指定标签名的元素,放入一个类数组对象中返回!
c. 返回值:
1). 如果找到符合要求的元素,则放在一个类数组对象中返回
2). 如果没找到符合要求的元素,则返回空类数组对象: { length:0 }
d. 强调:
1). .前的主语可以是任意父元素,也可以是document。但是,查找范围越小,查找速度越快!所以,应该尽量缩小查找的范围!
2). 因为有可能找到多个元素,所以函数名中Elements是复数,s结尾.
3). 不仅查找直接子元素,而且会在所有后代中查找符合要求的元素!
4). 即使只找到一个符合条件的元素,也会将这唯一的一个元素,放在类数组对象中返回!但是,如果我们想操作找到的这一个元素,必须用[0]从类数组对象中取出这唯一的元素才能继续对这个元素对象执行操作!
(3). 按class名查找多个元素
a. var 类数组对象=任意父元素.getElementsByClassName("class名")
b. 意为: 在一个指定的父元素范围内,查找所有class属性包含指定class名的多个元素,放入一个类数组对象中返回!
c. 返回值:
1). 如果找到符合要求的元素,则放在一个类数组对象中返回
2). 如果没找到符合要求的元素,则返回空类数组对象: { length:0 }
d. 强调:
1). .前的主语可以是任意父元素,也可以是document。但是,查找范围越小,查找速度越快!所以,应该尽量缩小查找的范围!
2). 因为有可能找到多个元素,所以函数名中Elements是复数,s结尾.
3). 不仅查找直接子元素,而且会在所有后代中查找符合要求的元素!
4). 即使只找到一个符合条件的元素,也会将这唯一的一个元素,放在类数组对象中返回!但是,如果我们想操作找到的这一个元素,必须用[0]从类数组对象中取出这唯一的元素才能继续对这个元素对象执行操作!
5). 如果一个元素上被多个class同时修饰,那么,只需要使用其中一个class名,就可找到这个元素。
(4). 按name名查找多个表单元素:
a. var 类数组对象=document.getElementsByName("name名");
b. 意为: 在整个页面范围内,查找所有name属性值为指定name名的多个表单元素,放入一个类数组对象中返回!
c. 返回值:
1). 如果找到符合要求的元素,则放在一个类数组对象中返回
2). 如果没找到符合要求的元素,则返回空类数组对象: { length:0 }
d. 强调:
1). .前的主语必须是document。
2). 因为有可能找到多个元素,所以函数名中Elements是复数,s结尾.
3). 即使只找到一个符合条件的元素,也会将这唯一的一个元素,放在类数组对象中返回!但是,如果我们想操作找到的这一个元素,必须用[0]从类数组对象中取出这唯一的元素才能继续对这个元素对象执行操作!
(5). 示例: 分别使用四个函数按不同的HTML特征查找元素
2_iterator.html
遍历节点树 用户名:
Hello World ! //查找id为nav的一个ul元素 var ul = document.getElementById("nav"); console.log(ul); //查找ul下的所有li var lis = ul.getElementsByTagName("li"); console.log(lis); //六个 //查找ul下所有直接子元素li var children = ul.children; console.log(children); //3个 //想修改span的内容为❀ var span = document.getElementsByTagName("span")[0]; console.log(span); span.innerHTML = "❀"; //想找ul下所有class为item的元素 var items = ul.getElementsByClassName("item"); console.log(items); //6个 //想找到class为active的元素,将其内容改为❀ var active = ul.getElementsByClassName("active")[0]; console.log(active); active.innerHTML = "❀"; //想找到name属性为uname的文本框,并设置其内容为❀ var input = document.getElementsByName("uname")[0]; console.log(input); input.value = "❀";
运行结果:
4. 按选择器查找元素:
(1). 何时: 今后如果查找一个元素的条件比较复杂时,首选按选择器查找!
(2). 如何: 2个函数
a. 只查找一个符合要求的元素:
1). var 一个元素对象=任意父元素.querySelector("选择器")
查找(按)选择器
2). 意为: 在指定父元素范围内,查找第一个符合选择器要求的元素
3). 返回值:
i. 如果找到,返回一个元素对象;
ii. 如果没找到,返回null
4). 强调: 永远只能返回第一个符合选择器要求的元素!
b. 查找多个符合要求的元素:
1). var 类数组对象=任意父元素.querySelectorAll("选择器")
2). 意为: 在指定父元素下,查找所有符合选择器要求的元素,放在一个类数组对象中返回!
3). 返回值:
i. 如果找到,返回类数组对象;
ii. 如果没找到,返回空类数组对象: { length:0 }
四. 购物车案例:
1. 需求:
(1). 点+/-号按钮,修改商品数量
(2). 数量修改,影响小计
(3). 小计修改,影响总计
2. 实现: 点+/-号按钮,修改商品数量:
(1). 今后只要做DOM效果,都可遵循4步完成:
a. 查找触发事件的元素
b. 绑定事件:
c. 查找要修改的元素
d. 修改元素
五. 事件概述:
1. 什么是事件: 用户手动触发的或浏览器自动触发的页面内容或状态的改变。
2. 如何在事件发生时能自动执行一项任务:
(1). 每个元素对象身上都有一批以on开头的特殊属性——事件属性,只不过所有事件属性,在开局时,都默认为null。
(2). 每当我们点击一个元素时,浏览器都会自动去找到这个元素的对应的事件属性。比如: 当单击一个元素时,浏览器会自动找这个元素身上的onclick属性
(3). 如果我们提前在一个元素的onxxx属性上提前保存一个函数。则,只要浏览器找到这个元素的这个事件属性时,就会自动触发我们提前保存的事件处理函数。
元素对象.on事件名=function(){ ... }
其中, 提前保存在事件属性上的这个函数,称为事件处理函数
强调: 事件处理函数,如果不触发事件,是不会执行的!只有触发了事件,才会执行处理函数的内容。如果反复触发事件,就会反复执行处理函数的内容
3. 问题: 在事件处理函数中,想获得当前触发事件的按钮,如果轻易使用事件处理函数以外的变量,极有可能出错!
4. 原因: 事件处理函数是在主程序执行后,不确定什么时候,才触发执行!而从主程序执行完,到实际触发事件处理函数这段时间间隔内,外部的变量值很有可能被篡改!
5. 解决: 今后,在事件处理函数中,想获得正在触发事件的当前元素对象本身,都要用this!
6. 示例:购物车:
3_shoppingcart.html
使用Selector API实现购物车客户端计算 table { width: 600px; text-align: center; border-collapse: collapse; } td, th { border: 1px solid black; } td[colspan="3"] { text-align: right; } /*想让tfoot中最后一个td背景变为黄色*/ tfoot td:last-child { background-color: yellow; } /*想让tbody中每行最后一个td背景变为粉色*/ tbody > tr > td:last-child { background-color: pink; } 商品名称 单价 数量 小计 iPhone6 ¥4488.00 1 ¥4488.00 iPhone6 plus ¥5288.00 1 ¥5288.00 iPad Air 2 ¥4288.00 1 ¥4288.00 Total: ¥14064.00
//DOM4步: //1. 查找触发事件的元素 //本例中: 要找table中所有button元素 //1.1 先找id为data的table var table = document.getElementById("data"); //1.2 在table内查找所有button var btns = table.getElementsByTagName("button"); console.log(btns); //2. 绑定事件处理函数 //本例中: 遍历查找结果中每个按钮元素对象 for (var btn of btns) { //每遍历一个按钮元素对象,就为当前按钮元素对象的onclick属性赋值一个事件处理函数 btn.onclick = function () { /*点击按钮修改数量*/ //3. 查找要修改的元素 //本例中: 查找当前按钮旁边的span的元素 //好的办法: 找当前按钮的爹下的第二个孩子 var span = this.parentElement.children[1]; //4. 修改元素 //本例中: //4.1 先取出span现在的内容,转为数字,保存在变量n中 var n = parseInt(span.innerHTML); //4.2 做计算 //如果当前按钮的内容是+ if (this.innerHTML == "+") { //就将n+1 n += 1; } else if (n > 1) { //否则如果n>1 //才能将n-1; n -= 1; } //4.3 将新值放回span的内容中 span.innerHTML = n; /*数量改变,修改小计*/ //3. 查找要修改的元素 //本例中: 找当前按钮的爹(td)的下一个兄弟td var subTd = this.parentElement.nextElementSibling; //4. 修改元素 //本例中: //4.1 获得单价price,转为数字 var price = parseInt( this.parentElement.previousElementSibling.innerHTML.slice(1) ); //4.2 用单价price*数量n,算出小计 var sub = price * n; //4.3 放入小计格的内容中 subTd.innerHTML = `¥${sub.toFixed(2)}`; /*计算总计*/ //3. 查找要修改的元素 //本例中: table下tfoot下最后一个td var totalTd = table.querySelector( "tfoot td:last-child" //复习第二阶段选择器 ); //4. 修改元素 //4.1 查找tbody中每行最后一个td var subTds = table.querySelectorAll("tbody>tr>td:last-child"); //4.2 计算总计 //本例中: 遍历并累加每个小计格中的内容 var total = 0; for (var td of subTds) { total += parseInt(td.innerHTML.slice(1)); } //4.3 将总计放入总计格的内容中 totalTd.innerHTML = `¥${total.toFixed(2)}`; }; }
运行结果:
注: /*数量改变,修改小计*/
注: /*计算总计*/
◼️总结: 查找函数的返回值规律:
1. 如果原函数返回下标位置, 如果找不到,返回-1
2. 如果原函数返回一个数组或一个对象,如果找不到,返回null
3. 如果原函数返回类数组对象,如果找不到返回空类数组对象: { length:0 }
⬛总结: DOM 5件事: 增删改查+事件绑定:
1. 查找元素:
(1). 不需要查找就可直接获得的元素对象: 4种:
document.documentElement ——
document.head ——
document.body ——
document.forms[i] ——
(2). 如果已经获得一个元素对象,找周围附近的元素对象时,就用按节点间关系查找:2大类关系,6个属性
a. 父子关系: 4种
1). 元素的父元素: 元素.parentElement或元素.parentNode
2). 元素下的所有直接子元素: 元素.children
3). 元素下的第一个直接子元素: 元素.firstElementChild
4). 元素下的最后一个直接子元素: 元素.lastElementChild
b. 兄弟关系: 2种
1). 元素的前一个兄弟: 元素.previousElementSibling
2). 元素的后一个兄弟: 元素.nextElementSibling
(3). 如果用一个特征就能找到想要的元素,就用按HTML特征查找:4个方法:
a. 按id查找:
var 一个元素对象=document.getElementById("id名");
b. 按标签名查找:
var 类数组对象=任意父元素.getElementsByTagName("标签名")、
c. 按class名查找:
var 类数组对象=任意父元素.getElementsByClassName("class名")
d. 按name名查找表单元素:
var 类数组对象=document.getElementsByName("name名")
(4). 如果通过复杂的查找条件,才能找到想要的元素时,就用按选择器查找: 2个方法
a. 只查找一个符合条件的元素:
var 一个元素=任意父元素.querySelector("任意选择器")
b. 查找多个符合条件的元素:
var 类数组对象=任意父元素.querySelectorAll("任意选择器")