DOM_BOM

DOM

一. 什么是DOM: Document Object Model
文档 对象 模型

  1. 什么是: 一套专门操作网页中元素内容的对象和方法的集合。
  2. 何时: 今后,只要想操作网页中的内容,都要用DOM
    在这里插入图片描述
  3. DOM标准: W3C负责制定和维护了一套DOM标准,几乎所有浏览器100%兼容!
  4. 如何: 五件事: 增删改查+事件绑定

DOM树

对应小程序视频: 小程序->在线->DOM->day01 0 DOM Tree 树
https://pan.baidu.com/s/1cCNhWz8tMLPOvIBGtRcNsg 提取码:xa87

  1. DOM树: 内存中保存一个网页中所有内容的树型结构。
  2. 为什么: 因为HTML的元素内容,都是上下级包含的嵌套结构。而树形结构是最直观的展现上下级包含关系的结构。
  3. 如何:
    在这里插入图片描述

查找元素: 4种

强调: 所有元素对象,必须找到才能使用!没有任何一个节点/元素可以直接使用!

  1. 用很简单的方法就可直接获得的节点对象: 4个
    (1). 树根对象: document
    (2). 元素: document.documentElement
    (3). 元素: document.head
    (4). 元素: document.body
  2. 按节点间关系查找元素: 2大类关系, 6个属性
    对应小程序视频: 小程序->在线->DOM->day01 1. 按节点间关系查找
    https://pan.baidu.com/s/1T1Fzo2U1gbsf1ir269NRcg 提取码:wut1
    (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). 示例: 使用元素树关系属性查找页面中指定的元素:

在这里插入图片描述
(6). 总结: 今后,只要已经获得一个元素,想找他周围附件的元素时,才用节点间关系查找: 2大类关系,6个属性
在这里插入图片描述
3. 按HTML特征查找: 4个函数:
对应小程序视频: 小程序->在线->DOM->day01 2. 按HTML特征查找
https://pan.baidu.com/s/1SHfsFjxWF1C30ZeXOoWcCg 提取码:a1nf
(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],就能取出找到的唯一的一个元素对象.
c. 示例: 按Id查找和按标签名查找元素

在这里插入图片描述
总结: DOM 4步:

  1. 先查找触发事件的元素
  2. 再为元素绑定事件处理函数
  3. 查找要修改的元素
  4. 修改元素

总结: DOM 5件事: 增删改查+事件绑定:
//不要背!用到时,来查找,复制粘贴就行了!

  1. 查找元素: 4种
    (1). 不需要查找就可直接获得的元素对象: 4种:
    document 根节点 document
    document.documentElement ——
    document.head ——
    document.body ——
    (2). 如果已经获得一个元素对象,找周围附近的元素对象时,就用按节点间关系查找:2大类关系,6个属性
    a. 父子关系: 4种
    1). 元素的父元素: 元素.parentElement
    2). 元素下的所有直接子元素: 元素.children
    3). 元素下的第一个直接子元素: 元素.firstElementChild
    4). 元素下的最后一个直接子元素: 元素.lastElementChild
    b. 兄弟关系: 2种
    1). 元素的前一个兄弟: 元素.previousElementSibling
    2). 元素的后一个兄弟: 元素.nextElementSibling
    (3). 如果用一个特征就能找到想要的元素,就用按HTML特征查找:4个方法:
    a. 按id查找:
    var 一个元素对象=document.getElementById(“id名”);
    b. 按标签名查找:
    var 类数组对象=任意父元素.getElementsByTagName(“标签名”)、在这里插入图片描述

一. 查找:
对应小程序视频: 小程序->在线->DOM->day01 2. 按HTML特征查找
https://pan.baidu.com/s/1SHfsFjxWF1C30ZeXOoWcCg 提取码:a1nf

  1. 按HTML特征查找: 4个函数:
    (1). 按id查找一个元素:
    var 一个元素对象=document.getElementById(“id名”)
    (2). 按标签名查找多个元素:
    var 类数组对象=任意父元素.getElementsByTagName(“标签名”)
    (3). 按class名查找多个元素:
    a. var 类数组对象=任意父元素.getElementsByClassName(“class名”)
    b. 意为: 在任意父元素下
    获得多个元素
    通过class名
    c. 返回值:
    1). 如果找到符合要求的元素,就返回一个类数组对象
    2). 如果没找到符合要求的元素,就返回空的类数组对象:
    { length:0 }
    d. 强调:
    1). 可以在任意指定的父元素下查找。合理的设置查找范围,可以优化查找的效率!当然,如果确实需要在整个页面中查找,也可以写document开头。
    2). 因为可能找到多个符合要求的元素,所以,函数名中的Elements是s结尾,表示多个元素。
    3). 即使只找到一个元素,也会放在类数组对象中返回,所以,要想获得找到的唯一一个元素,必须加[0]
    4). 不仅查找直接子元素,而且会在所有后代中查找符合要求的元素。
    5). 即使一个元素上,同时被多个class名修饰,那么只需要其中一个class名就可以找到当前元素。
    (4). 按name名查找表单元素:
    a. var 类数组对象=document.getElementsByName(“name名”)
    b. 意为: 在页面中 获得多个元素
    通过Name名
    c. 返回值:
    1). 如果找到符合要求的元素,就返回一个类数组对象
    2). 如果没找到符合要求的元素,就返回空的类数组对象:
    { length:0 }
    d. 强调:
    1). .前必须是document作为主语!
    2). 因为可能找到多个符合要求的元素,所以,函数名中的Elements是s结尾,表示多个元素。
    3). 即使只找到一个元素,也会放在类数组对象中返回,所以,要想获得找到的唯一一个元素,必须加[0]
    (5). 示例:按HTML特征查找指定元素
    在这里插入图片描述

  2. 按选择器查找: 今后只要查找条件非常复杂时,都用选择器查找: 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. 示例: 购物车
    对应小程序视频: 小程序->在线->DOM->day01 3. 购物车 shoppingcart
    https://pan.baidu.com/s/1FXlLwTg40DsMl48PU_jZBg 提取码:bxb8
    (1). 任何DOM效果,都要经历4步:
    a. 查找触发事件的元素
    b. 为元素绑定事件处理函数
    c. 查找要修改的元素
    d. 修改元素
    (2). 事件概述:
    a. 什么是事件: 浏览器自动触发的或用户手动触发的页面中元素状态的变化。
    b. 什么是事件处理函数:提前保存在元素的事件属性上的,当事件发生时,自动执行的函数。
    c. 何时使用事件处理函数: 今后,只要希望当事件发生时,能自动执行一项任务时。
    d. 如何使用事件处理函数: ——事件绑定,2种:
    1). 在HTML中: 2步:
    i. 在网页的中,先定义一个事件处理函数
    function 函数名(){
    … …
    }
    ii. 在元素的开始标签中:<元素 on事件名=“函数名()”>
    iii. 问题: 是将js函数的调用和事件绑定,写在HTML中,不符合内容与行为分离的原则,不便于今后的维护!
    2). 在js中: 2步:
    i. 查找触发事件的元素
    ii. 为元素绑定事件处理函数:
    元素对象.on事件名=function(){
    … …
    }
    iii. 原理:
    先将事件处理函数,暂存在元素对象身上的事件属性上,暂不执行
    将来,当用户触发这个元素上的对应事件时,才自动找出之前暂存的事件处理函数,自动调用!
    iv. 优点: 所有事件绑定的代码,都集中定义在js中,极其便于今后的维护!
    v. 说明: 如果在js中绑定事件,则js代码必须写在元素的结尾!所有网页HTML内容之后。因为网页顺序执行,必须先创建HTML元素,才能在js中查找元素,绑定事件。
    e. 如何在事件处理函数中,自动获得当前触发事件的元素:
    1). 错误: 用事件处理函数外的全局变量!
    原因: 因为事件处理函数的定义和将来的触发之间是有时间差的!而全局变量很可能在这个时间差之内,被篡改为其它值。——不靠谱
    2). 正确: 今后只要想在事件处理函数中获得正在触发事件的当前DOM元素对象,都用this!this可在事件发生时,自动指向当前正在触发的元素对象。
    f. 示例: 为购物车中每个按钮绑定单击事件:
    在这里插入图片描述
    在这里插入图片描述
    (3). 点按钮,修改数量
    在这里插入图片描述
    在这里插入图片描述
    (4). 数量变,修改小计在这里插入图片描述
    在这里插入图片描述
    (5). 小计变,修改总计
    在这里插入图片描述
    在这里插入图片描述
    二. 修改: 3种东西: 内容,属性,样式

  4. 内容: 3种
    对应小程序视频: 小程序->在线->DOM->day02 0.1 修改元素的内容
    链接:https://pan.baidu.com/s/1tOPWvgH3IK67S1JgMzMO2w 提取码:kutr
    (1). 获取或修改元素的开始标签到结束标签之间的原始的HTML内容:
    元素.innerHTML
    (2). 获取或修改元素的开始标签到结束标签之间的纯文本内容:
    元素.textContent
    说明: textContent多做2件事:
    1). 去掉了内嵌的HTML标签
    2). 将特殊符号翻译为正文
    (3). 获取或修改表单元素的值:
    a. 问题: 绝大多数表单元素都是input,单标记。没有结束标签!
    b. 解决: 今后只要获取或修改表单元素的值,都要用: 元素.value
    (4). 示例: 使用三种方式获取元素的内容:

在这里插入图片描述
(5). 示例: 动画开关门效果:
对应小程序视频: 小程序->在线->DOM->day02 1. 动画 开关门效果 door
链接:https://pan.baidu.com/s/1PQxXy8U5z6rQ7tCmnW4Q9w 提取码:r54y
在这里插入图片描述
2. 属性: 3种
(1). 字符串类型的HTML标准属性
对应小程序视频: 小程序->在线->DOM->day02 0.2 修改元素的属性 字符串类型
链接:https://pan.baidu.com/s/1QMgX5kt43Np8PAIafbIoAw 提取码:0q8p
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元素的属性:
在这里插入图片描述
e. 特例: class属性:
1). 问题: 按理说,操作class属性,也可以用"元素.class"。但是,因为class是ES标准中的关键字!专门用于创建一种类型!所以,DOM就不能用class再操作样式!DOM中的class属性和ES中的class关键字冲突了!
2). 解决: 今后,只要在DOM中操作元素的class属性,必须更名为"className"。操作"元素.className",等效于操作<元素 class=“xxx”>
f. 示例: 手风琴效果:
对应小程序视频: 小程序->在线->DOM->day02 2. 下拉菜单 手风琴效果 动画
链接:https://pan.baidu.com/s/1bKyV3el6knq5a5suQbFWhQ 提取码:hzxj
在这里插入图片描述
在这里插入图片描述
(2). bool类型HTML标准属性: 1种
对应小程序视频: 小程序->在线->DOM->day02 0.3 修改元素的属性 bool类型
链接:https://pan.baidu.com/s/10DrQrBFlPupgxc-jWF3COQ 提取码:p02k
a. 什么是: HTML标准规定的,只要写在元素开始标签中就起作用的属性,无需指定属性值。
b. 比如: checked, selected, disabled, …
c. 如何:
1). 不能用核心DOM的4个函数: 因为核心DOM的4个函数,不支持bool类型的值!只支持字符串类型的属性值。
2). 只能用HTML DOM的简写: 元素.属性名,且,属性值必须是bool类型。
d. 补: CSS3中的状态伪类选择器: :checked 专门匹配已选中的元素
e. 示例: 全选和取消全选:
在这里插入图片描述
(3). 自定义扩展属性
对应小程序视频: 小程序->在线->DOM->day02 4.1 自定义扩展属性
链接:https://pan.baidu.com/s/14gf-YzkV1Yui9eNHEvv24A 提取码:4eti

对应小程序视频: 小程序->在线->DOM->day02  4.2 标签页 tabs
链接:https://pan.baidu.com/s/1iJwKs2we7zRTAGmsZXcnog 提取码:69ie

对应小程序视频: 小程序->在线->DOM->day02 4.1 自定义扩展属性
链接:https://pan.baidu.com/s/14gf-YzkV1Yui9eNHEvv24A 提取码:4eti
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. 示例: 使用自定义属性记录按钮单击次数:

e. 示例: 标签页效果:
对应小程序视频: 小程序->在线->DOM->day02 4.2 标签页 tabs
链接:https://pan.baidu.com/s/1iJwKs2we7zRTAGmsZXcnog 提取码:69ie
在这里插入图片描述

  1. 样式:
    对应小程序视频:小程序->在线->JSCORE->day03: 1 修改样式, 计算后的样式
    链接:https://pan.baidu.com/s/1ITGMlBVQRohGS_86zo0K4g 提取码:ifj2
    (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元素的样式:

(3). 问题: 用.style.css属性方式修改元素的样式,一次只能修改一个css属性值。如果再一次交互行为中,需要同时修改一个元素的多个css属性,代码就会很繁琐!
(4). 解决: 今后只要批量修改一个元素的多个css属性,都应该用class属性代替style属性
(5). 如何: 2步:
a. 先在css中,为元素定义好不同情况下的样式类套装:
b. 再在js中根据不同的情况,更换元素的className为不同的css样式类名。
(6). 示例: 带样式的表单验证:
作业: 带class样式的表单验证valiWithCss
链接:https://pan.baidu.com/s/1QI5LRZohca4NGt6IWOZRPQ 提取码:vdyy
在这里插入图片描述

二. 添加删除替换元素:
对应小程序视频: 小程序->在线->JSCORE->day03: 2 DOM 添加新元素…
链接:https://pan.baidu.com/s/111PZogkjuP19_UYOEOH4Sg 提取码:a3b4

  1. 添加一个新元素: 3步
    (1). 先创建一个新的空元素对象:
    a. var 新元素=document.createElement(“标签名”)
    b. 意为: 创建 元素
    c. 返回值: 返回一个新创建的元素对象
    d. 强调: .前的主语必须是document
    e. 比如: 想创建一个a元素:
    var a=document.createElement(“a”);
    结果:
    (2). 为新的空元素添加必要的属性:
    比如: 想让a当做超链接使用跳转到tmooc
    a.innerHTML=“go to tmooc”
    a.href=“http://tmooc.cn”
    结果: go to tmooc
    (3). 必须将新元素添加到DOM树上指定位置,才能在网页中显示出来,供人们使用!
    a. 在一个父元素下所有子元素末尾追加一个新元素:
    父元素.appendChild(新元素)
    追击 孩子
    b. 在一个父元素下的一个现有子元素之前插入一个新元素
    父元素.insertBefore(新元素, 现有子元素)
    插入到xxx之前
    c. 替换一个父元素下的一个现有子元素
    父元素.replaceChild(新元素, 现有子元素)
    在这里插入图片描述

  2. 示例: 添加一个a元素和一个文本框:

  3. 示例: 动态生成表格:
    在这里插入图片描述

  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中了,既要用文档片段动态添加子元素.
    在这里插入图片描述

  5. 删除元素: 父元素.removeChild(子元素)
    移除 孩子

  6. 示例: 为表格添加删除行的功能:
    在这里插入图片描述

BOM

一. 什么是BOM: Browser Object Model
浏览器 对象 模型

  1. 什么是: 专门操作浏览器窗口的一套对象和方法的集合。

  2. 何时: 2种:
    (1). 想获取或操作窗口相关的信息
    比如: 想获得窗口大小、想打开一个新创建、想关闭现有窗口…
    (2). 获取浏览器软件的配置信息:
    比如: 浏览器的名称和版本号、安装了什么插件…

  3. 包括:
    window history location document navigate screen event

  4. 问题: BOM没有标准!兼容性极差!所以,用的越来越少!
    二. window对象:

  5. 3个角色:
    (1). 代替了ES标准中的global对象,充当全局作用域对象
    所有ES标准中规定的,可直接使用的内置对象和函数,都保存在window中
    而且我们自己创建的全局变量和函数,默认也是保存在window中
    (2). 包含了所有原生的直接可用的js对象和函数:
    原生=ES标准+DOM标准+BOM
    (3). 代表了当前浏览器窗口:
    a. window可获得窗口的大小: 2组
    1). 整个窗口的完整大小:
    window.outerWidth window.outerHeight
    2). 仅文档显示区范围的大小:
    window.innerWidth window.innerHeight
    b. window还可以打开和关闭浏览器窗口;
    1). window.open()
    2). window.close() 脚本只能关闭它们打开的窗口。

  6. 打开新链接总结: 4种
    对应小程序视频: 小程序->在线->DOM->day03 4. 打开新链接4种方式
    链接:https://pan.baidu.com/s/1rlMf1cLJWhLuZzOrNMld6Q 提取码:f90f
    (1). 在当前窗口打开新链接,可后退
    a. html: 文本

    b. js: window.open(“url”,"_self")
    (2). 在当前窗口打开新链接,禁止后退
    a. js: location.replace(“新url”)
    b. 后退的原理: 见history
    c. 阻止后退的原理: 用新的url,去代替history中旧的url。一旦旧的url被代替了,不复存在了!自然就不能后退了!
    在这里插入图片描述
    (3). 在新窗口打开新链接,可同时打开多个
    a. html: 文本

    b. js: window.open(“url”,"_blank")
    (4). 在新窗口打开新链接,只能打开一个
    a. html: 文本

    b. js: window.open(“url”, “自定义窗口名”)
    (5). 原理:
    a. 其实每个浏览器窗口在内存中都有一个唯一的名字
    b. 浏览器规定,相同名称的窗口,只能打开一个。后打开的同名窗口会覆盖先打开的同名窗口
    c. 窗口名是由a元素或js语句在打开新窗口时指定的:

     window.open("url", "自定义窗口名")
    

    d. 结果: a元素或js语句中定义的新窗口名会自动保存在新窗口的name属性中!
    e. 正因为如此,将来我们自己起变量名时,不要使用"name"作为变量名!因为"name"在BOM中有特殊意义,作为窗口的名称。
    f. 预定义窗口名:
    1). _self: 自动获得当前旧窗口自己的名称,作为新窗口的名称。结果,新窗口会覆盖旧窗口,相当于在当前窗口打开新链接。
    2)._blank: 不指定新窗口名,但是浏览器也不会让新窗口名空着。浏览器会自动在底层(我们看不见),为每个新窗口随机生成窗口名!结果,因为随机生成的窗口名不重复,所以可以反复打开多个!
    (6). 示例: 实现四种打开新链接的方式:

对应小程序视频: 小程序->在线->DOM->day04 0. history, location, navigator
链接:https://pan.baidu.com/s/1Ic8NMJVJ4BSWXE6CK9ZBRQ 提取码:lrzc

三. history:

  1. 什么是: 内存中专门保存当前窗口打开后,成功访问过的url的历史记录数组
  2. 原理:
    (1). 只要在当前窗口中成功打开一个新链接,history都会以push方式,将新链接追加到history中保存
    在这里插入图片描述
    (2). 如果又访问了一个新的url地址,同样会被push进history中保存。但是,因为history中之前已经有旧的url地址,所以,新地址追加入history后,就可后退了!
    在这里插入图片描述
    (3). 此时,如果点了一下后退,退到前一个旧的url,就可以点前进了。在这里插入图片描述
  3. 常用操作:
    (1). 前进一步: history.go(1)
    (2). 后退一步: history.go(-1)
    有时,如果后退一步不好使,可以后退2步history.go(-2)
    (3). 刷新页面: history.go(0)
  4. 示例: 在多个页面之间前进后退:

四. location对象:

  1. 什么是: 专门保存当前正在打开的url信息的对象

  2. 何时: 2种:
    (1). 获得浏览器地址栏中当前url信息
    (2). 执行一些页面跳转操作时

  3. 属性: location可完整或分段的获得url中的信息
    (1). location.href 获得地址栏中完整url信息
    (2). location.protocol 协议
    (3). location.host 主机名+端口号
    (4). location.hostname 主机名
    (5). location.port 端口号
    (6). location.pathname 相对路径
    (7). location.search ?及其之后的查询字符串参数列表
    (8). location.hash #及其之后的锚点地址
    (9). 示例: 访问location的各个属性值:

  4. 方法:
    (1). 也能实现在当前窗口打开可后退:
    location.assign(“新url”); 等效于 window.open(“新url”,"_self")
    (2). 也能实现刷新页面:
    location.reload(); 等效于 history.go(0)
    (3). 独立的可以实现在当前页面打开,禁止后退:
    location.replace(“新url”)
    五. navigator:

  5. 什么是: 专门保存浏览器软件的配置信息的对象

  6. 何时: 今后只要想获得浏览器软件的配置信息时

  7. 主要用途:
    (1). 获得当前浏览器软件的名称、版本号和内核
    navigator.userAgent
    (2). 判断当前浏览器是否安装某个插件
    a. navigator.plugins 集合中保存了当前浏览器已经安装的所有插件的信息:
    b. 如何判断是否安装某个插件?
    if(navigator.plugins[“完整插件名”]!==undefined){ //强行访问插件名
    说明已经安装该插件了
    }else{
    说明未安装该插件
    }

  8. 示例: 查看userAgent字符串,并判断浏览器是否安装某些插件

六. 事件

  1. 什么是事件: 浏览器自动触发的或用户手动触发的页面中内容或状态的改变

  2. 什么是事件处理函数: 希望在事件发生时,能自动执行的一个函数

  3. 什么是事件绑定: 提前将事件处理函数,保存在元素对象的事件属性上,暂存,暂不执行!

  4. 事件绑定的结果: 当浏览器中某个元素上发生了事件时,浏览器就会自动找到这个元素上对应事件属性上提前保存的事件处理函数,自动执行!

  5. 如何绑定: 3种:
    对应小程序视频:小程序->在线->DOM->day04 1. 添加事件监听,移除事件…
    链接:https://pan.baidu.com/s/13pK15bk5c1d21UidoXs2lQ 提取码:g2d5
    (1). 在HTML中手工绑定: 2步:
    a. 先在之前的

e. 原理:
1). addEventListener()其实做了2件事:
i. 先创建一个事件监听对象,保存住这个事件绑定相关的三样东西:
当前元素对象+当前事件名+事件处理函数
ii. 将事件监听对象添加到浏览器中一个巨大的事件监听对象队列中保存
2). 当元素上触发事件时: 2件事:
i. 浏览器会先找到元素对象身上on事件名属性中保存的事件处理函数,优先执行
ii. 浏览器还会继续去事件监听对象的队列中查找是否包含符合条件的事件监听对象。只要找到符合条件的事件监听对象,就会自动取出事件监听对象中保存的事件处理函数,自动执行。
在这里插入图片描述
f. 移除事件监听:
1). 元素对象.removeEventListener(“事件名”, 原事件处理函数对象)
移除 事件监听对象
2). 坑: 在移除事件监听对象时,如果事件处理函数只是写的和原事件处理函数完全一样!是无法移除!
3). 原因: function底层等效于new Function()。意味着,如果在添加事件监听时和移除事件监听时,分别写了两次function,就意为着分别创建了两个不同的函数对象。即使函数内容一样,也不是统一函数对象!地址不同!
在这里插入图片描述4). 解决: 今后,如果一个事件处理函数有可能被移除,则绑定时就不能用匿名函数绑定!应该用有名称的函数来绑定!函数名可以保存住最初的函数对象地址,并在移除事件监听时,反复使用原函数地址。
在这里插入图片描述
5). 坑: 一旦采用有名称的函数添加事件监听,则只能添加一个事件监听了。无法添加多个完全相同的事件监听了!——只能等到jq中才能解决
g. 示例: 移除事件监听对象:

  1. 事件模型:
    对应小程序视频: 小程序->在线->DOM->day04 2. 事件模型
    链接:https://pan.baidu.com/s/13pK15bk5c1d21UidoXs2lQ 提取码:g2d5
    (1). 问题:点在内层子元素上,也会触发外层父元素上的单击事件处理函数
    (2). 原因: 事件模型:
    a. 什么是: 从触发事件开始,到所有事件处理函数执行完,所经历的整个过程。
    b. DOM标准规定,事件模型包括3个阶段:
    1). 捕获: 由外向内, 从根节点document开始,依次遍历实际触发事件的元素的各级父元素。并记录各级父元素上绑定的事件处理函数。只记录,暂时不执行
    2). 目标触发: 浏览器总是预先触发事件点击的元素上的事件处理函数。
    实际点击的元素,也成为目标元素(target)
    3). 冒泡: 按照捕获阶段记录的反向,由内向外,依次触发各级父元素上绑定的事件处理函数。
    在这里插入图片描述
  2. 事件对象:
    (1). 什么是事件对象: 当事件发生时,浏览器自动创建的,保存事件相关信息的对象。
    (2). 何时: 2种:
    a. 想获取事件相关的信息时
    b. 想改变事件默认的行为时
    (3). 如何使用: 事件对象不用自己创建,就可直接使用: 2步:
    a. 在事件处理函数上,添加形参变量e
    元素.οnclick=function(e){
    b. 在事件处理函数内,形参变量e,就能自动接到浏览器创建并传来的事件对象。
    e自动接到事件对象
    }
    c. 原理: 当事件发生时,浏览器注定会自动创建一个事件对象,并自动传递给事件处理函数的第一个形参变量e。——信任!
  3. 事件对象可以:
    (1). 停止冒泡: e.stopPropagation()
    停止 蔓延
    示例: 点内层元素,只内层元素喊疼,其它元素不要喊!
    在这里插入图片描述

(2). 利用冒泡/事件委托:
对应小程序视频: 小程序->在线->DOM->day04 3. 利用冒泡 事件委托
链接:https://pan.baidu.com/s/18_S9n2MMpmREsn2SK1E6hA 提取码:vodj
a. 优化: 尽量减少事件绑定的次数!
1). 问题: 因为每次触发事件时,浏览器都是通过遍历事件监听队列的方式来查找符合要求的事件监听对象。
2). 所以,队列中事件监听对象的个数,应该越少越好!因为个数越少,遍历查找就快,事件响应的速度就快!
b. 如何: 利用冒泡/事件委托 3步
1). 如果多个子元素都要绑定相同的事件时,其实只要在父元素上集中绑定一个事件处理函数,所有子元素注定都能通过冒泡机制共用父元素上的事件处理函数。
i. 问题: this不能用了!
ii. 原因: 因为如果利用事件委托,事件是绑定在父元素上,不是绑定在子元素上了!而且执行时,是在父元素上执行的!所以事件委托中的this,不再执行子元素,而是统一指向父元素了!——不是我们想要的了!
2). 今后,只要使用事件委托,都要用e.target代替this!
i. 什么是e.target: 事件对象中,始终保存最初点击的目标元素的特殊属性。
ii. 和this相比:
this,会随冒泡而改变,可能指向父元素了
e.target,一旦保存住最初的实际点击的目标元素,就不会随冒泡而改变,
iii. 强调: 如果想用e.target,事件处理函数必须添加形参变量e
iv. 问题: 父元素div,是块元素,所以子元素之外的剩余空间也都属于父元素范围。所以,点在子元素周围的空白范围内,也会触发事件!——不是我们想要的!
3). 在事件处理函数内,在正式执行事件处理逻辑之前,必须先判断当前点击的目标元素是不是我们想要的!只有当前点击的目标元素是我们想要的时,我们才执行事件处理逻辑。否则,就什么也不干!
在这里插入图片描述
c. 示例: 使用事件委托事件购物车效果:

(3). 阻止默认行为:
对应小程序视频: 小程序->在线->DOM->day04 4. 阻止默认行为
链接:https://pan.baidu.com/s/1IZF3psHaSG-c159EQgfLJA 提取码:64vu
a. 问题: HTML中个别元素身上带有一些默认的行为,有些默认行为是有害的!使我们不希望的!
b. 比如: xxx,会自动在地址栏中url结尾添加#
巧了,将来vue框架的客户端路由导航也是用#作为标志。
如果让a擅自修改url结尾的#xxx,一定会和vue和路由导航冲突!
c. 解决:
1). 如果是a元素: xxx 就不会有任何多余的操作
i. javascript 意为让a不要跳转,而是执行一条js语句
ii. ; 是一条什么也不干的空语句!
iii. javascript:; 意为让a,什么也不干!
2). 如果是除了a以外的元素,也想去掉比想要的默认行为:
元素.οnclick=function(e){
e.preventDefault();
阻止 默认行为
然后再写我们自己的逻辑
}
d. 示例: 使用两种方法阻止a元素执行默认行为

(4). 获得鼠标位置: 每单击一次页面,都能获得3组坐标位置:
对应小程序视频: 小程序->在线->DOM->day04 5. 鼠标坐标x y 原生DOM
链接:https://pan.baidu.com/s/1CD0OW3_WcUxZqNllFrsxUA 提取码:eb7o
a. 相对于屏幕左上角的x,y坐标: e.screenX, e.screenY
屏幕 屏幕
b. 相对于文档显示区左上角的x,y坐标: e.clientX, e.clientY
客户端 客户端
浏览器 浏览器
c. 相对于当前点击的元素左上角的偏移量: e.offsetX, e.offsetY
偏移 偏移
在这里插入图片描述
d. 示例: 点击页面中某个位置,显示三组坐标:

总结: 不要背英文名字!反而应该记中文能做哪些事儿!
(2). 修改属性: 3种
a. 字符串类型的HTML标准属性: 2种:
1). 旧核心DOM: 4个函数
i. 元素.getAttribute(“属性名”);
ii. 元素.setAttribute(“属性名”, “属性值”)
iii. var bool=元素.hasAttribute(“属性名”)
iv. 元素.removeAttribute(“属性名”)
优点: 万能, 缺点: 繁琐
2). 新HTML DOM:
i. 元素.属性名
ii. 元素.属性名=“属性值”
iii. 元素.属性名!==""
iv. 元素.属性名=""
优点: 简单, 缺点: 不万能
b. bool类型的HTML标准属性:
1). 不能用旧核心DOM4个函数修改
2). 只能用HTML DOM的"元素.属性名"方式获取或修改,且值为bool类型
c. 自定义扩展属性:
1). 何时: 2种
i. 代替id、class、元素等选择器作为查找触发事件的元素的条件
ii. 在客户端元素上临时缓存业务数据
2) HTML中: <元素 data-自定义属性名=“属性值”>
3). js中: 2种: (不能用.访问)
i. 核心DOM:
var 属性值=元素.getAttribute(“data-自定义属性名”)
元素.setAttribute(“data-自定义属性名”,“属性值”)
ii. HTML5标准: 元素.dataset.自定义属性名
(3). 修改样式:
a. 修改元素的内联样式:
元素.style.css属性=“属性值”
b. 获取元素的完整样式:
var style=getComputedStyle(元素对象);
style.css属性
计算后的样式都是只读的
c. 批量修改元素的样式时,都用class:
元素.className=“class名”
总结: 不要背英文名字!反而应该记中文能做哪些事儿!
3. 添加/删除元素:
(1). 只添加一个新元素: 3步
a. 创建一个新元素:
var 新元素=document.createElement(“标签名”)
b. 为元素设置关键属性:
新元素.属性名=“属性值”;
c. 将新元素添加到DOM树: 3种:
1). 末尾追加:
父元素.appendChild(新元素)
2). 在某个元素前插入:
父元素.insertBefore(新元素, 现有元素)
3). 替换某个元素:
父元素.replaceChild(新元素, 现有元素)
(2). 优化: 尽量减少操作DOM树的次数,2种:
a. 如果同时添加父元素和子元素,应该先将子元素添加到父元素,最后再将父元素一次性添加到DOM树
b. 如果父元素已经在页面上,要添加多个平级子元素。应该利用文档片段对象
1). 创建文档片段对象:
var frag=document.createDocumentFragment()
2). 将子元素添加到文档片段对象中:
frag.appendChild(子元素)
3). 最后将文档片段对象一次性添加到DOM树上父元素下
父元素.appendChild(frag);
(3). 删除元素: 父元素.removeChild(子元素)

总结:
BOM:

  1. window:
    (1). 获得窗口大小:
    a. 获得完整窗口大小:
    window.outerWidth和window.outerHeight
    b. 获得文档显示区大小:
    window.innerWidth和window.innerHeight
    (2). 打开和关闭窗口:
    window.open()和window.close()
  2. 打开新链接4种方式:
    (1). 在当前窗口打开,可后退
    a. html:
    b. js: window.open(“url”, “_self”);
    (2). 在当前窗口打开,禁止后退
    a. js: location.replace(“新url”)
    (3). 在新窗口打开,可同时打开多个
    a. html:

    b. js: window.open(“url”, “_blank”);
    (4). 在新窗口打开,只能打开一个
    a. html:

    b. js: window.open(“url”, “自定义窗口名”)
  3. history:
    (1). 前进: history.go(n)
    (2). 后退: history.go(-n)
    (3). 刷新: history.go(0)
  4. location:
    (1). 属性: 分段获得url中各个部分:
    a. location.href 完整url
    b. location.protocol 协议
    c. location.host 主机名+端口号
    d. location.hostname 主机名
    e. location.port 端口号
    f. location.pathname 相对路径
    g. location.search ?及其之后的查询字符串参数列表
    h. location.hash #锚点地址
    (2). 方法:
    a. 在当前窗口打开,可后退:
    location.assign(“新url”) 或 location.href=“新url”
    b. 在当前窗口打开,禁止后退:
    location.replace(“新url”)
    c. 刷新: location.reload();
  5. navigator
    (1). 查看浏览器的名称和版本号: navigator.userAgent
    (2). 查看浏览器中安装的插件列表: navigator.plugins

总结: 事件:

  1. 绑定事件: js中:
    (1). 一个事件只绑定一个处理函数
    元素.on事件名=function(){ … }
    (2). 一个事件绑定多个处理函数
    元素.addEventListener(“事件名”, 事件处理函数)
    (3). 移除一个事件监听:
    元素.removeEventListener(“事件名”, 原事件处理函数对象)
  2. 事件模型: 捕获,目标触发,冒泡
  3. 事件对象:
    (1). 获得事件对象:
    元素.on事件名=function(e){ … }
    (2). 阻止冒泡: e.stopPropagation()
    (3). 当多个子元素都要绑定相同事件时,利用冒泡/事件委托3步:
    a. 事件只在父元素上绑定一次
    b. e.target代替this
    c. 判断e.target的任意特征是否是我们想要的元素
    (4). 阻止元素默认行为:
    e.preventDefault()
    (5). 获取鼠标位置:
    a. 相对于屏幕左上角的x,y坐标:
    e.screenX, e.screenY
    b. 相对于文档显示区左上角的x,y用坐标:
    e.clientX, e.clientY
    c. 相对于事件所在元素左上角的x,y坐标:
    e.offsetX e.offsetY

今日对应小程序视频列表:
小程序->在线->DOM->day03
4. 打开新链接4种方式
链接:https://pan.baidu.com/s/1rlMf1cLJWhLuZzOrNMld6Q 提取码:f90f
小程序->在线->DOM->day04
0. history, location, navigator
链接:https://pan.baidu.com/s/1Ic8NMJVJ4BSWXE6CK9ZBRQ 提取码:lrzc
1. 添加事件监听,移除事件监听 …
链接:https://pan.baidu.com/s/1ilh-VpLUx54YExIzw8v-dA 提取码:2n2e
2. 事件模型
链接:https://pan.baidu.com/s/13pK15bk5c1d21UidoXs2lQ 提取码:g2d5
3. 利用冒泡 事件委托
链接:https://pan.baidu.com/s/18_S9n2MMpmREsn2SK1E6hA 提取码:vodj
4. 阻止默认行为
链接:https://pan.baidu.com/s/1IZF3psHaSG-c159EQgfLJA 提取码:64vu
5. 鼠标坐标x y 原生DOM
链接:https://pan.baidu.com/s/1CD0OW3_WcUxZqNllFrsxUA 提取码:eb7o

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值