DOM 和 BOM

1DOM: 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(文档节点):undefined 或 null

、element(元素节点):undefined 或 null

、attribute(属性节点):属性值

、text(文本节点):文本本身

 

2DOM 查找有四种方法

(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 的下一个兄弟

按节点间关系查找的前提是已经获得了一个节点,用这个节点来查找周围临近的节

点,这种查找方式会连看不见的空字符也算文本节点,会对结果产生一定的干扰,解决

方法是按仅包含元素节点的树结构去查找

、父子

Aelem.parentElement 找 elem 的父元素

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

Celem.firstElementChild 第一个*直接*子元素

Delem.lastElementChild 最后一个*直接*子元素

、兄弟

Aelem.previousElementSibling 找 elem 的前一个兄弟元素

Belem.nextElementSibling 找 elem 的下一个兄弟元素

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

比如: for(var i=0,len= childNodes.length;i<len;i++)

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

按 id 查找: var elem=document.getElementById("id")

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

按标签名查找: var elems=parent.getElementsByTagName("标签名");

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

按 name 属性查找: var elems=document.getElementsByName("name")

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

按 class 属性查找:var elems=parent.getElementsByClassName("class")

按 class 属性查找可在任意父元素上调用,该属性不要求完整匹配,只要包含即可

它会返回多个元素组成的集合,但每次只能按一个条件查找,如果条件复杂,就无法一

句话获得想要的元素

(4). 按选择器查找

①. 只找一个元素

语法: var elem=parent.querySelector("selector");

②. 找多个元素

语法: var elems=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 标签,将转义字符翻译为正文

 

4DOM 两大标准

(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.checke),值都是 bool 类型 true/false

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

 

5修改 css 样式

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

①、问题 1: css 属性名有的带-

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

比如: background-color: backgroundColor、list-style-type: listStyleType

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

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

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

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

A获得完整样式对象 style

语法:var style=getComputedStyle(elem)

B获得 style 对象中的 css 属性

 语法: style.css 属性名

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

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

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

①、获得样式表对象

语法:var sheet=document.styleSheets[i]

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

语法: var rule=sheet.cssRules[i]

③、修改

语法:rule.style.css 属性名=值

 

6添加

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

①、创建空元素:

语法: var a=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)

 

8HTML 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;

属性: .text 代替.innerHTML

.index 表示当前 option 在 select 下的下标位置

 

9HTML 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: var td=tr.insertCell(i); 省略 i 表示右侧末尾追加

insertCell 不支持添加 th,只能添加 td

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

③、获取 td: tr.cells

 

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

(1)、获取表单: var form=document.forms[i/id]

(2)、获取所有表单元素的集合:form.elements (input、select、textarea 、button)

(3)、获得表单中表单元素的个数:form.length => form.elements.length

(4)、获得表单元素:var elem=form.elements[i/id/name]

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

(5)、手动提交表单:form.submit();

(6)、任何方式提交表单之前自动触发:form.onsubmit,常用于在提交之前,验证所有表单元素的内容

(7)、让 elem 获得焦点:elem.focus();

(8)、让 elem 失去焦点:elem.blur();

 

11HTML 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

 

14BOM 打开超链接的 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)

 

16window.onload 页面(HTML CSS JS)加载后触发

<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

 

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

 

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

语法:history.go(n)

(1)、前进: go(1)

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

(3)、刷新:go(0)

 

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

(1)、location.href 保存了完整的 url

在当前窗口打开: location.href=新 url

(2)、location.protocol: 协议

①、.host: 主机名+端口号

②、.hostname: 主机名

③、.port: 端口号

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

①、.hash: 锚点地址#xxx

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

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

Loction 的常见应用有以下几种:

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

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

location.assign("新 url") => location.href="新 url"=> location="新 url"

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

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

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

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

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

 

20event: 绑定事件

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

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

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

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

语法: elem.on 事件名=function(){ //this->elem }

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

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

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

语法:elem.addEventListener("事件名",function(){ //this->elem })

(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页面滚动

(1)事件: window.onscroll

(2)获得页面滚动位置: document.body.scrollTop

 

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

 

 

 

猜你喜欢

转载自blog.csdn.net/weixin_40629244/article/details/86293172