前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >DOM 和 BOM

DOM 和 BOM

作者头像
越陌度阡
发布2020-11-26 16:19:55
2.2K0
发布2020-11-26 16:19:55
举报

1. DOM: Document Object Model

早起 JS操作不同浏览器的 API 没有标准,有严重兼容性问题,后来 W3C 制定了统一的操作网页内容的 API 标准 DOM,使用 DOM API 操作网页内容,几乎 100%兼容所有浏览器,它具有查找, 修改(内容,属性,样式), 添加, 删除的功能。

网页中一切内容在内存中都是以树形结构存储的,树只有一个根节document,它包含了所有网页内容,网页中每一项内容都是树上的一个节点对象,包括: 元素、文字、属性...,每个节点都是一个 node 类型的对象,node 也是所有节点的父类型。

三大节点类型共有的属性:

nodeType 、 nodeName 、 nodeValue

(1). nodeType 节点类型

不同的类型的节点,能执行的操作是不一样的,nodeType 专门用于判断节点的类型

①. document(文档节点):9

②. element(元素节点):1

③. attribute(属性节点):2

④. Text(文本节点):3

(2). nodeName 节点的名称

节点的名称专门用于鉴别元素的标签名,nodeName 返回的是全大写的标签名

①. document(文档节点):#document(始终是)

②. element(元素节点):全大写的标签名

③. attribute (属性节点):属性名

④. text (文本节点):#text(始终是)

(3). nodeValue 节点值

①. document(文档节点):?developer/article/1753649/undefined 或 null

②. element(元素节点):?developer/article/1753649/undefined 或 null

③. attribute(属性节点):属性值

④. text(文本节点):文本本身

2. DOM 查找有四种方法

(1). 不需要查找,可直接获得的元素

html document.documentElement

head document.head

body document.body

form document.form

(2). 按节点间关系查找,节点树包含所有节点,分为元素和文本

①. 父子

A. elem.parentNode

找 elem 的父节点

B. elem.childNodes

找 elem 的所有*直接*子节点,返回所有直接子节点组成的集合,类似于数组

C. elem.firstChild

找 elem 的第一个*直接*子节点

D. elem.lastChild

找 elem 的最后一个*直接*子节点

②. 兄弟

A. elem.previousSibling

找 elem 的前一个兄弟

B. elem.nextSibling

找 elem 的下一个兄弟

按节点间关系查找的前提是已经获得了一个节点,用这个节点来查找周围临近的节点,这种查找方式会连看不见的空字符也算文本节点,会对结果产生一定的干扰,解决方法是按仅包含元素节点的树结构去查找。

①. 父子

A. elem.parentElement

找 elem 的父元素

B. elem.children

找 elem 的所有*直接*子元素,返回所有直接子元素组成的集合,类似于数组

C. elem.firstElementChild

第一个*直接*子元素

D. elem.lastElementChild

最后一个*直接*子元素

②. 兄弟

A. elem.previousElementSibling

找 elem 的前一个兄弟元素

B. elem.nextElementSibling

找 elem 的下一个兄弟元素

注意: childNodes 和 children 返回的都是动态集合,凡是遍历动态集合,都要先缓存元素个数再遍历,这样不会导致反复查找 DOM 树,比如:

for(var i=0,len= childNodes.length;i<len;i++){}

(3). 按 HTML 查找(优势:范围可大可小,可设置条件)

①. 按 ID查找

document.getElementById("id")

按 ID查找只能在 document 对象上调用,返回一个元素对象

②. 按标签名查找

parent.getElementsByTagName("标签名")

按标签名查找可在任意父元素上,不但查找直接子元素,还查找所有后代元素,返回多个元素组成的集合

③. 按 name 属性查找

document.getElementsByName("name")

按属性查找专门找表单中有 name 属性的表单元素,但是它只能在 document 上调用,它是返回多个元素组成的集合

④. 按 class 属性查找

parent.getElementsByClassName("class")

按 class 属性查找可在任意父元素上调用,该属性不要求完整匹配,只要包含即可,它会返回多个元素组成的集合,但每次只能按一个条件查找,如果条件复杂,就无法一句话获得想要的元素

(4). 按选择器查找

①. 只找一个元素

parent.querySelector("selector");

②. 找多个元素

parent.querySelectorAll("selector");

(5). 查找总结

①. 首次查找

A. 如果条件简单: 按 HTML 查找: id、标签、 className

B. 如果条件复杂: 按选择器查找

②. 已经获得一个元素,找周围相邻: 按节点间关系

(6). HTML 查找与按选择器查找的区别

①. 使用的难易程度: 当条件复杂时,按选择器查找简单,按 HTML 查找繁琐

②. 返回值

getElementsByTagName() 返回多个元素的*动态*集合,不实际存储对象的属性值,每次访问,都要重新查找 DOM 树

querySelectorAll() 返回多个元素的*非动态*集合,实际存储对象的所有属性值,即使反复访问集合,也不会导致反复查找DOM 树

③. 单次效率,按 HTML 查找效率高,按选择器查找效率低

3. 元素的内容

(1). elem.innerHTML: 获取或设置元素开始标签到结束标签之间的原始 html 代码片段,实际运用的较多

(2). elem.textContent: 获取或设置元素开始标签到结束标签之间的纯文本内容——IE9+,它可以去掉 html 标签,将转义字符翻译为正文

4. DOM 两大标准

(1). 核心 DOM: 操作一切结构化文档的 API(HTML,XML)

①. elem.attributes

保存了当前元素的所有属性节点

②. elem.getAttribute("属性名")

获取属性值

③. elem.setAttribute("属性名","值")

修改属性值

④. elem.hasAttribute("属性名")

判断是否包含属性

⑤. elem.removeAttribute("属性名")

移除属性

(2). HTML DOM: 对部分常用 DOM API 的简化版本,HTML DOM 将标准属性都预定义在元素对象中

①. elem.属性名

获取属性值

②. elem.属性名="值"

修改属性值

③. elem.属性名===""(全空)

判断是否包含属性

④. elem.属性名=""

移除属性

特例: class 属性和 ES 标准中的 class 重名=>DOM => className

(3). 核心 DOM 与 HTML DOM 的区别

①. 核心 DOM 无法操作三大状态属性(disabled 、selected、checked),只能用 HTML DOM,操作(elem.disabled 、elem.selected 、elem.checked),值都是 bool 类型 true/false

②. HTML DOM 不能操作自定义属性,比如: data-toggle="dropdown",只能用核心 DOM操作

5. 修改 CSS 样式

(1). 仅获取/修改内联样式: elem.style.css 属性名

①. 问题 1: CSS 属性名有的带有 "-"

解决: 所有 CSS 属性名都要去横线变驼峰

如: list-style-type: listStyleType

②. 问题 2: 所有数值类型的属性值都是带单位的字符串

解决: 获取时,都要去单位,转数值,修改时,将单位拼回数

③. 问题 3: 仅能获得内联样式无法获得样式表中的样式

解决: 计算后的样式-最终应用到元素上的完整样式,分两步完成

A. 获得完整样式对象 style

getComputedStyle(element)

B. 获得 style 对象中的 css 属性

style.css 属性名

注意: style 对象中的样式都是只读

结论:获取样式:getComputedStyle,修改样式: elem.style.css 属性名

(2). 运行时修改样式表中的样式,分三步完成

①. 获得样式表对象

document.styleSheets[i]

②. 获得样式表对象中某个 CSSRule(一个选择器{})

sheet.cssRules[i]

③. 修改

rule.style.css 属性名=值

6. 添加

(1). 添加分三步来完成

①. 创建空元素:

document.createElement("a");

结果:<a></a>

②. 设置关键属性

a.href="http://tmooc.cn"

a.innerHTML="go to tmooc";

结果:<a href="http://tmooc.cn">go to tmooc</a>

③. 将元素添加到 DOM 树 3 种

A. parent.appendChild(child)

末尾追加

B. parent.insertBefore(child, oldChild)

中间插入

C. parent.replaceChild(child, oldChild)

替换

D. element.cloneNode()

克隆

(2). 尽量少的修改 DOM 树,每次修改 DOM 树,都会导致重新 layout,耗时较长,所以在操作 DOM 树时应遵循以下优化方案

①. 如果同时添加父元素和子元素时,应该先在内存将子元素都添加到父元素中,再将父元素一次性整体添加到 DOM 树,这样只会触发一次 layout

②. 如果同时添加多个平级子元素,应使用文档片段,文档片段是内存中临时存储多个子元素的虚拟元素,使用文档片段分 3 步来完成.

A. 创建文档片段

var frag=document.createDocumentFragment()

B. 将子元素临时添加到frag中

frag.appendChild(child)

C. 将frag添加到DOM树,frag不会成为页面元素,添加子元素后,frag自动释放

parent.appendChild(frag)

7. 删除

语法:parent.removeChild(child)

8. HTML DOM 常用对象:Select/option

(1). Select 代表页面上的一个 select 元素

①. select.value 当前选中项的 value,如果没有 value,就返回选中项的内容

②. select.options 保存 select 下所有 option 元素对象   

类似: select.getElementsByTagName("option")

③. select.options.length 保存 select 下 option 的个数

清空 select 下所有 option: select.options.length=0;

select.length 等效于 select.options.length

清空 select 下所有 option: select.length=0 或者 select.innerHTML="";

④. select.selectedIndex 当前选中项的下标

⑤. onchange 当选中项发生改变时,配合 sclect.add(option)完成事件

⑥. select.add(option) 向 select 中添加一个 option

类似: select.appendChild(option),此命令不支持文档片段

⑦. select.remove(i) 移除 select 中 i 位置的一个 option

(2). Option: 代表页面上的一个 option 元素

var opt=new Option(text,value);

创建一个 option 对象,同时设置 opt 的内容为 text,设置 opt 的值为 value,类似于:

var opt=document.createElement("option");

opt.innerHTML=text;

opt.value=value;

9. HTML DOM 常用对象:Table,Table 代表网页中一个 table 元素,它管着行分组

(1). 创建行分组

①. 创建表头 var thead=table.createTHead()

②. 创建主体 var tbody=table.create TBody()

③. 创建表尾 var tfoot=table.create TFoot()

(2). 删除行分组

①. 删除表头 table.deleteTHead()

②. 删除表尾 table.deleteTFoot()

(3). 获取行分组

①. 获取表头 table.tHead

②. 获取主体 table.tBodies[i]

③. 获取表尾 table.tFoot

(4). 行分组 Thead、 TBody 、Tfoot 控制行

①. 添加行,在行分组中 i 位置插入一个新行, 中间插入行,原 i 位置的行向后顺移

A. 表头添加行: var tr=thead.insertRow(i);

B. 主体添加行:var tr=tbody. insertRow(i);

C. 表尾添加行: var tr=tfoot.insertRow(i);

D. 固定套路

a. 末尾追加一个新行

thead | tbody | tfoot.insertRow();

b. 开头插入

thead | tbody | tfoot.insertRow(0);

②. 删除行,删除行分组中第 i 行,i 是当前行在行分组内的相对下标位置

thead | tbody | tfoot.deleteRow(i)

删除行时,由于 i 无法自动获得,表格行较多时,手动难以指定,故以上方法较少用,其实在 tr 上都有一个属性 tr.rowIndex,用 tr.rowIndex 删除行,只能通过表格定位下标来删除,以后凡是删除行都用它

table.deleteRow(tr.rowIndex)

③. 获取行: thead | tbody | tfoot.rows

(5). 行 tr 控制单元格 td

①. 添加 td: tr.insertCell(i),

省略 i 表示右侧末尾追加,insertCell 不支持添加 th,只能添加 td

②. 删除 td: tr.deleteCell(i);

③. 获取 td: tr.cells

10. HTML DOM 常用对象 form,form 代表页面上一个表单元素

(1). 获取表单

document.forms[i/id]

(2). 获取所有表单元素的集合

form.elements (input、select、textarea 、button)

(3). 获得表单中表单元素的个数

form.length => form.elements.length

(4). 获得表单元素

form.elements[i/id/name]

如果表单元素有 name 属性:form.name

(5). 手动提交表单

form.submit()

(6). 任何方式提交表单之前自动触发

form.onsubmit

常用于在提交之前,验证所有表单元素的内容

(7). 让 elem 获得焦点

elem.focus()

(8). 让 elem 失去焦点

elem.blur()

11. HTML DOM 常用对象 Image,Image 代表页面上一个 img 元素

语法: var img=new Image();

12. 过渡动画的两种实现方法

(1). css 中: 添加 transition

(2). js 中: 修改 css 属性值

不支持 transition: display 、zIndex

支持: width 、height 、opacity 、bottom、top、left、right

13. BOM(Browser Object Model)

BOM 是专门操作浏览器窗口的 API 比如: alert 、prompt 、confirm,它存在两大问题

(1). 没有标准,存在兼容性问题

(2). 不可定制

window 对象的 2 个角色

(1). 代替 ES 中的 Global 充当全局作用域对象

(2). 封装所有 BOM 和 DOM 的 API

14. BOM 打开超链接的 4 种方法

(1). 在当前窗口打开,可后退

①. html: <a href="url" target="_self"></a>

②. js: window.open("url","_self")

(2). 在当前窗口打开,不可后退

①. js: location.replace("url");

用新 url 代替 history 中当前 url,网页实现无法后退

(3). 在新窗口打开,可打开多个

①. html:<a href="url" target="_blank"></a>

②. js: open("url","_blank")

(4). 在新窗口打开,只能打开一个

①. html:<a href="url" target=" name 值"></a>

②. js: open("url","name 值")

内存中每个窗口都有一个唯一的 name 属性来标示一个窗口,浏览器规定,相同 name属性的窗口只能打开一个,其实 html 中的 target 属性就是在设置新窗口的 name 属性值,如果 target 中使用自定义的窗口名,则只能打开一个,name 属性预定义两种:

①. _self: 默认使用当前窗口自己的 name 属性,新窗口覆盖当前窗口

②. _blank: 意为不指定窗口名,浏览器会随机生成不同的窗口名,每次打开新窗口都随机生成不同的 name 并且可打开任意多个

15. 定时器(2 种)

(1). 周期性定时器-让程序按照指定时间间隔,反复执行一项任务,分 3 步完成

①. 任务函数: 让定时器反复调用的函数

②. 启动定时器: var timer=setInterval(任务函数,间隔的毫秒数)

③. 停止定时器: clearInterval(timer),2 种

A. 用户手动停止定时器: 用按钮调用 clearInterval

B. 自动停止定时器,在任务函数中,设定临界条件,如果达到临界条件就自动调用clearInterval

问题: timer 中的序号会残留在 timer 变量中

解决: 停止定时器后,主动清空 timer=nul

(2). 一次性定时器-让程序先等待一段时间,再自动执行一次任务,执行一次后,定时器自动停止,分 3 步完成

①. 任务函数

②. 启动: var timer=setTimeout(任务函数, 等待的毫秒数)

③. 停止: clearTimeout(timer)

16. window.onload 页面所有加载后触发

<body>和<script>中的 js 很可能和 CSS 并行加载,甚至先与 css 中的 transition 执行,所以,只要一段代码必须在 css 加载后才能执行都要放在 window.onload 中。

笔试: 定时器中的函数,只能在主程序所有程序执行后才能执行???

for(var i=0;i<3;i++){

setTimeout(function(){

console.log(i);

},0);

};

// 结果: 3 3 3

// alert("Hello") 如果不点确定,则永远不输出 333

17. window 常用属性:history、location、document、navigator、screen、event

18. history: 保存当前窗口打开后,成功访问过的历史记录的栈,history 封装的非常严密,只能前进、后退、刷新

语法:history.go(n)

(1). 前进: go(1)

(2). 后退:go(-1)

(3). 刷新:go(0)

19. location: 专门保存当前窗口正在打开的 url 的对象

(1). kk 保存了完整的 url

在当前窗口打开: kk=新 url

(2). location.protocol: 协议

①. host: 主机名+端口号

②. hostname: 主机名

③. port: 端口号

(3). location.pathname: 相对路径

①. hash: 锚点地址#xxx

②. search: 表单提交后地址栏中的查询字符串

③. ?变量名=值&变量名=值&

Loction 的常见应用有以下几种

(1). 替换 history 中当前 url,实现进制后退: location.replace("新 url")

(2). 在当前页面打开,可后退

①. location.assign("新 url")

②. kk="新 url"

③. location="新 url"

(3). 刷新页面: location.reload(false/true);

(4). 笔试: false/true 的差别

浏览器本地是有缓存的,浏览器的缓存中会保存 css 图片等静态资源,每次请求时,首先查看缓存中是否有想要文件,没有想要文件或文件过期,才去服务器下载新文件

①. reload(false) 优先使用本地缓存的文件

②. reload(true) 强制去服务器下载新文件

20. event 绑定事件

(1). 在 HTML 中绑定: <ANY.on 事件名="js 语句">

问题: 不符合内容与行为分离的原则,不便于维护

(2). 在 js 中动态绑定,2 种

①. 一个事件只绑定一个处理函数

elem.on 事件名=function(){ }

解除绑定: elem.on 事件名=null

问题: 每个事件只能绑定一个处理函数

②. 一个事件可同时绑定多个处理函数

elem.addEventListener("事件名",function(){ })

(3). 解除绑定: elem.removeEventListener("事件名","函数名");

如果一个事件处理函数可能被动态移除,则绑定时,不能使用匿名函数,必须使用有名称的函数

21. 事件模型: DOM 标准分为 3 个阶段

(1). 捕获: 由外向内,记录各级父元素绑定的事件处理函数

(2). 目标触发: 首先执行目标元素上的事件处理函数

(3). 冒泡: 由内向外,反向执行捕获阶段记录的处理函数

22. 事件对象

事件发生时自动创建的封装事件信息提供操作事件的 API 的对象通常作为事件处理函数的第一个参数,默认自动传入

on 事件名=function(e){

// e 会自动获得事件对象

}

阻止蔓延/冒泡: e.stopPropagation();

取消事件/阻止默认行为: e.preventDefault();

尽量少的添加事件监听,因为浏览器触发事件监听,是采用遍历查找的方式,添加的监听越多,遍历的速度越慢,如果多个子元素都要绑定相同的事件,只要在父元素绑定一次,所有子元素即可共用,这样绑定需要注意两点:

(1). 获得目标元素,不能用 this, 因为 this 指父元素,应该用 e.target,保存实际点击的目标元素

(2). 鉴别目标元素,先判断目标元素的 nodeName 或 className,只有目标元素符合要求时,才执行事件操作

事件坐标共 3 对

(1). e.screenX | screenY

相对于整个屏幕左上角的坐标

(2). e.clientX | clientY

相对于文档显示区左上角的坐标

(3). e.offsetX | offsetY

相对于当前元素左上角的坐标

23. 页面滚动事件 window.onscroll

24. 屏幕操作相关

(1). document.body.clientWidth

网页可见区域宽

(2). document.body.clientHeight

网页可见区域高

(3). document.body.offsetWidth

网页可见区域宽(包括边线的宽)

(4). document.body.offsetHeight

网页可见区域高 (包括边线的宽)

(5). document.body.scrollWidth

网页正文全文宽

(6). document.body.scrollHeight

网页正文全文高

(7). document.body.scrollTop

网页被卷去的高

(8). document.body.scrollLeft

网页被卷去的左

(9). window.screenTop

网页正文部分上

(10). window.screenLeft

网页正文部分左

(11). window.screen.height

屏幕分辨率的高

(12). window.screen.width

屏幕分辨率的宽

(13). window.screen.availHeight

屏幕可用工作区高度

(14). window.screen.availWidth

屏幕可用工作区宽度

本文参与?腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-01-11 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客?前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体同步曝光计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
http://www.vxiaotou.com