DOM和BOM详细讲解

1.什么是DOM:document object model
DOM:专门操作网页内容的一套函数和对象
DOM还是一个标准,由W3C指定
为什么:
广义js= ECMAScript + DOM + BOM
核心语法 +操作网页内容的一套函数和对象+访问浏览器软件信息对象
要想操作网页内容,为页面添加交互效果,其实只能用DOM函数和对象。
问题:早期DOM没有标准
解决:W3C指定了同意的DOM函数和对象的标准
几乎所有u浏览器100%兼容
特例:IE8
何时:只要操作网页内容,为网页添加交互行为,只能用DOM
包括:5件事:增加元素、删除元素、修改元素、查询元素、事件绑定
2.DOM树:
什么是:在内存中,集中保存一个网页中所有内容的树形结构
为什么:树形结构是最直观的保存上下级包含关系的数据结构,而网页中的HTML标签,刚好也是父子嵌套的上下级包含关系,所以网页中的每一项内容在内存中都是存在一颗树形结构上的
如何:
1.当浏览器读取到一个.html文件时,会先在内存中创建一个document对象,作为真棵树的树根对象
2.开始扫描.html中每个元素,文本等内容每扫描到一项内容,就在document下对应位置创建一个节点(node)对象。
3.查找元素:
1.不需要查找,就可直接获得:
Document.documentElement
Document.head
Document.body
2.按节点间关系查找:
树上的每个节点都不是孤立存在的,都和上下左右的节点之间的各种各样的关系,可以互相访问到
包括:
节点树:包含所有节点内容的完整树结构
2大类关系:
1.父子关系:
节点.parentNode 获得当前节点的父节点
父节点.chiIdNodes 获得当前父节点下的所有直接子节点的集合。
强调:chiIdNodes返回的是一个类数组对象,今后我都简称集合
父节点.firstChild 获得当前父节点下的第一个子节点
父节点.laseChild 获得当前父节点下的最后一个直接子节点。
2.兄弟关系:
节点.previousSibling 获得当前节点平级的前一个相邻的兄弟节点
节点.nextsibling 获得当前节点平级的下一个相邻的节点
问题:同时包含看不见的换行和空字符,也是节点对象,严重干扰查找。
解决:元素树
元素树:仅包含元素节点的树结构
说明:元素树不是一颗新树,而是原来节点树中添加了仅指向元素节点的新属性而形成的一颗子树结构
2大类关系:
2.父子关系:
节点.parentElement 获得当前节点的父节点
说明:其实也可以用parentNode
父节点.chiIdren 获得当前父节点下的所有直接子节点的集合。
强调:chiIdren 返回的是一个类数组对象,今后我都简称集合
父节点.firstElementChild 获得当前父节点下的第一个子节点
父节点.laseElementChild 获得当前父节点下的最后一个直接子节点。
2.兄弟关系:
节点.previousElementSibling 获得当前节点平级的前一个相邻的兄弟节点
节点.nextElementSibling 获得当前节点平级的下一个相邻的节点
总结:今后只要按照节点间关系查找就都用元素树的属性代替节点树的旧属性
何时:今后只要已经获得一个节点对象,找周围附近的节点时,就用节点间关系查找。
鄙视(笔试):定义一个函数,遍历一个指定的父元素下的所有后代元素;
1.定义一个函数,仅遍历直接子元素
2.如果当前子元素有更夏季的直接子元素,则对当前子元素继续调用当前函数,查找子元素
3.按HTML特征查找:
4种
1.按id属性查找
Var 元素=document.getElementById(“id”)
在整个页面中查找id为指定名名称的一个元素
返回值:如果找到,返回一个元素对象
如果没找到。返回null
强调:只能用document调用。不能在随意父元素上调用
2.按标签查找
Var 集合=父元素。GetElementsByTagName(“标签名”)
在指定的父元素下查找所有变签名为指定标签名的后代元素
返回值:如果找到,返回多个元素组成的集合:[].length=0
强调:
1.可在任意父元素下查找。通常指定在某个父元素下查找后代,是为了减少查找范围,提高查找效率。
2.不止查找直接子元素,而是在所有后代中查找。
比如:nav.getElementsByTagName(“li”)

3.按calss属性查找 Var 集合=父元素.getElementsByClassName(“类名”) 在指定父元素内,查找calss属性中包含指定类名的所有元素 返回值:如果找到,返回多个元素组成的集合 如果没找到,返回空集合:[].length=0

强调:
1.可限制在任意父元素内查找,减少查找范围
2.不仅查找直接子元素,且在所有后代中查找。
3.如果一个元素同时被多个calss修饰,则使用其中一个class,就可以找到改元素,无需所有class都满足
比如:nav.getElementsByClassName(“active”)

4.按name属性查找
Var 集合=document.getElementsByName(“name名”)
在整个网页中查找name属性值为指定name名的元素.
返回值:如果找到,返回多个元素组成的集合
如果没找到,返回空集合:[].length=0
强调:
1.只能用document调用,不能用随意一个父元素调用.
何时:在表单中查找表单元素时
问题:所有返回集合的查找函数,在任何情况下都会返回一个集合,即使只找到一个元素,也放在一个集合中返回。
比如:

Var 集合=document.getElementsByName(“uname”)
集合:[]
如果想使用集合中返回的这唯一的一个对象,应该?
解决:var 文本框对象=
Document.getElementsByName(“uname”)[0]
其中:[0]表示取出集合中仅有的一个元素对象,单独使用.
以上四种查找方式,最大的问题是:
一次只能用一个特征作为查找条件。
如果查找条件非常繁琐:
4.用选择器当条件查找元素:
2个函数: 1.只查找一个符合条件的元素
var元素=父元素.querySelector(“任意复杂的选择器”)
返回值:如果找到,返回一个元素对象
如果没找到返回-1
2.查找多个符合条件的元素:
Var 集合=父元素.querySelectorAll(“可以放任意复杂的选择器”)
在指定父元素下查找符合选择器要求的多个元素
返回值:如果找到返回多个元素的集合
如果没找到返回[]length=0
强调:1.可以以任意父元素调用来限制查找的范围
2.()中的选择器参数,不用每次都写完整,只要以.前的父元素为起点开始写就行!

    ul.querySelectorAll(“li li”)
    • 4.不仅查找直接子元素,且在所有后代中查找符合条件的。 4.选择器查找: Var 元素=父元素.querySelector(“任意选择器”) Var 集合=父元素.querySelectorAll(“任意选择器”) DOM都有哪些优化之一: 如果只用一个条件就可以找到想要的元素时 尽量使用getElementsByxxx 查找——因为他们的效率高 只有查找条件复杂时,才能选择按选择器查找。——效率低 总结: 1.不需要查找就可直接获得 Document.documentElement Document.head Document.body 2.按节点间关系查找 1.父子关系 元素.parentNode 父元素.children 元素.firstElementChild 元素.lastElementChild 2.兄弟关系: 元素.previousElementSibling 元素.nextElementSibling 3.按HTML特征查找: Var 元素=document.getElementByld(“id”) Var 集合=父元素.getElementsByTagName(“标签名”) Var 集合=父元素.getElementsByClassName(“class名”) Var 集合=document.getElementsByName(“name名”) 4.修改 3样: 1.内容:3个属性 1.获取或修改原始HTML片段:元素.innerHTML 2.获取或修改纯文本内容:元素.textContent Vs innerHTML 1.textContent 去掉了内嵌的标签 2.TextContent将特殊符号翻译为正文 以上两个获得的都是双标记中,开始标记和结束标记之间的内容 问题: 表单元素是单标记,没有结束标记,所以也就没有innerHTML和textContent 3. 获取或设置表单元素的内容: 表单元素.value 2. 属性: 3种: 1. HTML标准属性: 什么是: HTML标准中规定的那些字符串类型的属性。比如: id, title, class, name, value, src, href... 获取或修改HTML标准属性: 2种方式: 1. 早期的核心DOM函数: 4个: var 属性值=元素.getAttribute("属性名") 获取属性值 元素.setAttribute("属性名","新值") 修改属性值 var bool=元素.hasAttribute("属性名") 判断元素是否包含该属性 元素.removeAttribute("属性名") 移除元素上的指定属性 2. 后来的HTML DOM函数: 什么是HTML DOM: 是在旧版基础上,对部分常用函数和常用对象提供的简化版函数。 做的第一个简化: 每个元素对象中都提前预置好了所有HTML标准属性,只不过,值暂时为""。 今后在操作HTML标准属性时,只要用: 元素.属性名 特例: html中: <元素 class="类名" js中不能用.class,因为class是js的关键词。所以,凡是操作html中的class属性,一律更名为className。js中操作className等效于操作HTML中的class。 获取属性值: 元素.属性名 修改属性值: 元素.属性名=值 强调: 只要修改标准属性,值必须是字符串。如果给的不是字符串,DOM会自动转为字符串。 判断是否包含指定属性: 元素.属性名!=="",说明包含。因为所有标准属性的默认值是""。 移除属性: 元素.属性名=""; 只要把元素的属性值改为空字符串,则当前属性失效。 问题: 以上函数,只能操作字符串类型的HTML标准属性。无法操作bool类型的HTML属性: 2. 状态属性: 什么是: HTML标准中规定的,值为bool类型的属性: disabled selected checked multiple ... 特征: 所有状态属性在HTML中使用时,都不带=和属性值。加上,就起作用。去掉就失去作用。 如何操作: 不能用核心DOM的4个函数(getAttribute(), setAttribute(), hasAttribute(), removeAttribute()),因为核心DOM的四个函数只能操作字符串类型的属性 只能用.来访问,值都是bool类型: 比如: 禁用一个按钮: btn.disabled=true 相当于: ... 启用一个按钮:btn.disabled=false 选中一个checkbox: chb.checked=true; 相当于: 取消选中一个checkbox: chb.checked=false;
      		补: CSS中有一组状态伪类: 
      			:disabled   :checked    :selected
      			专门用于选择处于某种状态的元素
      			比如: input:checked 选择的是被选中的input元素
      				button:disabled 选择的是被禁用的按钮
      
      	3. 自定义扩展属性: 
      		什么是自定义扩展属性: HTML标准中没有规定的,程序员自发添加的属性。
      		何时: 2个典型用途: 
      			1. 在客户端html元素上临时缓存数据
      				比如: data-target="id值";
      			2. 代替其他选择器,用来选择触发事件的元素,为元素绑定事件。
      				比如: data-toggle="dropdown"
      		如何: 
      			1. 为元素添加自定义扩展属性: 
      				行业规范: 
      					<元素 data-自定义属性名="值"
      			2. 用自定义扩展属性作为查询条件,只能用属性选择器: 
      			[data-属性名=值]
      			3. 获取或修改自定义属性的值: 
      				不能用.访问自定义扩展属性: 
      					因为自定义扩展属性是程序员在html标准之外,后天添加的自定义属性。则HTML DOM的元素对象中就不包含这些自定义扩展属性。
      				1. 可以用核心DOM: ——没有兼容性问题
      					元素.getAttribute("data-属性名")
      					元素.setAttribute("data-属性名",值)
      					为什么: getAttribute()每次都是去HTML代码中查找属性。
      				2. HTML5标准中规定: 有兼容性问题
      					可以 元素.dataset.属性名
      					其中dataset可以自动收集页面上所有data-开头的自定义扩展属性。这就是为什么自定义扩展属性名习惯上都要带data-前缀的原因!
      				
      
      3. 样式: 
      	1. 修改内联样式: 
      		每个元素都有一个style属性,代表html中开始标签中的style属性。
      		元素的style属性中又包含了所有css样式属性
      		修改元素对象的style属性中的css样式属性,等效于直接修改html中开始标签中的style=""
      		比如: 元素.style.backgroundColor="red"
      		等效于: <元素 style="background-color:red">
      		再比如: 显示隐藏: 
      			元素.style.display="block"
      				等效于: <元素 style="display:block"
      			元素.style.display="none"
      				等效于: <元素 style="display:none"
      		强调: 所有带-的css属性,一律去横线,变驼峰命名。
      			比如: list-style-type  -> listStyleType
                       background-color -> backgroundColor
      	2. 获取样式: 
      		问题: 元素.style仅包含内联样式,不包含样式表中的样式。所以,如果用元素.style.css属性,也只能获得内联样式,无法获得样式表中定义的样式。
      		解决: 获得计算后的样式: 
      			什么是计算后的样式: 最终应用到这个元素上的所有样式的集合。
      			何时: 今后,只要获取样式,都要获取计算后的样式。
      			如何: 2步: 
      				1. 先获得计算后的样式对象
      					var style=getComputedStyle(元素)
      					获得指定元素计算后的完整样式对象
      					强调: getComputedStyle是内置的全局函数,可直接使用!
      					返回值: 是一个包含所有css属性的巨大的对象
      				2. 才是从样式对象中提取想要的css属性: 
      					var 属性值=style.css属性
      				强调: 计算后的样式,都是只读的。
      					因为样式的来源不确定,不确定有多少元素正在共享该属性。所以不允许擅自修改。以免牵一发而动全身。
      	总结: 想修改一个元素的css属性:
      			元素.style.css属性=值
      		想获取一个元素的css属性: 
      			getComputedStyle(元素).css属性
      
      	问题: 修改样式时,style.css属性一句话只能改一个css属性。而网页中一个效果的变化,可能同时涉及多个css说行。如果用style.css属性=值 修改,代码会很繁琐。而且,加样式时繁琐一次,去掉样式时同样繁琐!
      	解决: 当批量修改样式时,用className修改是最划算的!
      

总结:
修改:

  1. 内容:
    1. 原始html 片段: .innerHTML
    2. 纯文本: .textContent
    3. 表单元素的内容: .value
  2. 属性:
    1. HTML标标准属性:
      1. 核心DOM: .getAttribute()
        .setAttribute()
        .hasAttribute()
        .removeAttribute()
      2. HTML DOM: 也可用.改
    2. 状态属性: 只能用.改
    3. 自定义扩展属性:
      定义: <元素 data-自定义属性名=“值”
      获取或修改:
      元素.getAttribute(“data-属性名”)
      元素.setAttribute(“data-属性名”,“值”)
      HTML5: 元素.dataset.属性名
  3. 样式:
    1. 修改内联样式: 元素.style.css属性=“值”
    2. 获取: getComputedStyle(元素).css属性

4.添加/删除
添加/删除
1. 添加: 3步:
1. 创建一个空元素
var a=document.createElement(“a”);
创建 元素
强调: 只能用document调用
问题:
2. 为空元素添加关键属性和内容
a.href=“http://tmooc.cn”
a.innerHTML=“go to tmooc”
go to tmooc
问题: 网页上依然看不见a
因为: 网页的排版和绘制,都是以DOM树为依据。而新创建的元素对象,还没有加载到DOM树上。排版引擎和绘图引擎不知道多了新元素,自然就不会画到页面上
3. 将空元素挂载到DOM树
3种:
1. 追加到一个父元素下的所有子元素末尾
父元素.appendChild(新元素)
追加
2. 插入到一个父元素下的某个子元素之前
父元素.insertBefore(新元素, 现有元素)
插入 之前
3. 替换父元素下一个现有的旧元素
父元素.replaceChild(新元素,旧元素)
替换
强调: 将新元素挂到DOM树上,都要先找到它的父元素,由父元素调用函数,将新元素添加到自己的子元素中。

2. 优化: 尽量减少操作DOM树的次数
	为什么: 只要修改一次DOM树,就会导致重排重绘
	如果频繁重排重绘严重: 会闪屏
	解决: 
		1. 如果同时添加父元素和子元素,应该先在内存中将子元素先添加到父元素中,最后再将父元素整体一次性添加到DOM树——只重排重绘一次!
		2. 如果父元素已经在页面上了,要添加多个平级子元素。应该找一个临时的爹: 文档片段对象。先将多个平级子元素,在内存中,添加到文档片段对象中,再将文档片段对象整体一次性添加到DOM树上——也只重排重绘一次
			什么是文档片段: 内存中临时保存多个平级子元素的虚拟父元素
			何时: 只要父元素已经在页面上了,要添加多个平级子元素
			如何: 3步: 
				1. 创建文档片段
					var frag=
				document.createDocumentFragment();
						 创建   文档    片段
				2. 将子元素添加到文档片段中
					frag对象是一个虚拟的父元素,所以,用法和真实父元素完全一样。
					比如: frag.appendChild(新元素)
				3. 将文档片段对象一次性添加到DOM树
					真实父元素.appendChild(frag)
			问题: 文档片段会不会成为页面上实际的元素?
			答: 不会,文档片段在将子元素添加到DOM树后,就自动释放。不会成为实际页面元素。

3. 删除: 父元素.removeChild(子元素)

5.HTML DOM常用对象:
HTML DOM对部分常用的复杂的元素对象,提供了一些简写的函数和属性:
1. Image对象:代表页面上一个元素
唯一的简化: 创建元素: var img=new Image()
代替: var img=document.createElement(“img”);
强调: new Image()只创建元素,不负责挂载。还需要用多一句appendChild()。。。将元素挂载到DOM树上。
2. Select/Option:
1. Select 对象: 代表页面上一个元素
属性:
.selectedIndex 获得当前选中的option在整个select下的位置下标。
.value 获得当前选中的option的value属性值。如果option上没有value属性,则返回option的内容文本代替。
.options 获得当前select下所有option对象的集合。
.options.length 获得当前select下共有几个option对象
.length == .options.length 也可以获得当前select下共有几个option对象
方法:
.add(option) 向select下添加一个option对象
.remove(i) 移除i位置的option对象。

	2. Option对象: 代表页面上一个
  1. BOM: Browser Object Model
    什么是: 专门操作或访问浏览器软件的一批函数和对象
    何时: 只要想获取浏览器软件的信息,或操作浏览器窗口时
    如何:
    包括:
    1个最大的对象: window
    3个角色
    1. 代替ECMAScript中的global充当全局作用域对象。
    所以,所有我们自己声明的全局变量和全局函数默认都是在window中。
    2. 包含了所有ECMAScript,DOM和BOM的函数和对象:
    比如: window.Array
    window.document
    window.alert
    3. 代表着当前正在打开的浏览器窗口
    比如: 获取浏览器窗口的大小:
    1. 完整大小:
    window.outerWidth
    window.outerHeight
    2. 文档显示区大小:
    window.innerWidth
    window.innerHeight

    打开和关闭窗口:
    1. 打开新窗口: 4种需求:
    1. 在当前窗口打开,可后退:
    html:
    js: window.open(“url”, “_self”)
    2. 在当前窗口打开,禁止后退:
    js: location.replace(“新url”)
    3. 在新窗口打开,可打开多个:
    html:
    js: window.open(“url”, “_blank”)
    4. 在新窗口打开,只能打开一个:
    html:
    js: window.open(“url”, “自定义窗口名”)
    原理:
    1. 在浏览器内存中,每个窗口都有一个name属性,唯一标识一个窗口
    2. a的target属性和open()的第二个参数,其实是在给新窗口起名字(name属性)
    3. 浏览器规定: 同名的窗口,只能开一个!后打开的同名窗口,会覆盖先打开的同名窗口。
    有两个预定义的特殊意义的窗口名:
    _self: 自动获得当前窗口的name名给新窗口——结果: 新窗口覆盖旧窗口
    _blank: 空白,不给新窗口指定窗口名。而是靠浏览器随机生成!——结果: 新窗口的名字,一定不重复!即使打开多个窗口,也不会覆盖。

总结: 优化:

  1. 查找:
    如果只要一个条件就可以找到元素时:
    首先按HTML特征查找: getElementsByXXX
    如果查找条件复杂时: 用选择器查找
    querySelector()和querySelectorAll()

  2. 尽量减少操作DOM树的次数

    1. 添加删除:
      如果同时添加父元素和子元素,应该先在内存中将子元素添加到父元素中。最后,再将父元素一次性添加到DOM树
      如果父元素已经在页面上了,应该先在内存中创建文档片段对象,将所有平级子元素先添加到文档片段中。最后,再将文档片段一次性添加到父元素上
    2. 修改时: 能一次修改完成的,就不分两句话修改!
      比如: 元素.style.width=“200px”
      元素.style.height=“100px”
      其实: 元素.style.cssText=width:200px; height:100px;
  3. 实现5s后自动关闭页面:

    所需知识: window.close()可关闭当前网页
    需求:
    1. 打开页面时,页面5s可每隔1秒倒计时一次: 5 4 3 2 1
    2. 5s后,页面自动关闭
    3. 5s内单击留在本页,可停止定时器,不再关闭页面

  4. Promise鄙视(笔试)题:
    //假设有一个服务端接口,可根据条件分别查询三种商品的数量:
    http://localhost:5050/?type=a,
    http://localhost:5050/?type=b,
    http://localhost:5050/?type=c
    分别返回a类商品的总数,b类商品的总数,c类商品的总数
    每个接口,因为数据量很大,所以,可能有3秒的返回延迟。
    在day03/homework/文件夹下,运行:
    node server.js
    可测试以上三个地址:
    需求: 在.html网页中如何获得a类, b类, c类商品的总和
    考虑程序完成的总时间最少。
    //现只有一个已封装的基本的ajax函数,暂时不支持promise。
    //步骤:

    1. 修改ajax.js中的ajax函数,使其支持Promise
    2. 使用自己修改好的支持Promise的ajax函数,实现规定的需求。
      BOM
      1.window下包含:
      History 管前进后退
      Location 管地地址栏
      Document 其实即使dom中的document对象
      Navigator 管浏览器配置信息
      Screen 管显示设备的信息
      Event 管事件

(1)History
什么是:保存当前窗口打开后,成功访问过的url的历史记录数组
何时:只要用程序自动前进后退时,都用history
如何:前进一次:history.go(1)
后退一次:history.go(-1)
有时候后退一次不管用,可history.go(-2)后退两步.
刷新:history.go(0)
(2)location
什么是:专门保存地址栏中的地址信息,以及提供执行跳转操作的方法和对象,
何时:1.希望获得地址栏中的url信息时
2.希望执行一些特殊的跳转操作时
如何:
1.获取地址栏里的url信息:
Location.href 完整url
Location.protocol 协议
.host 主机名+端口号
.hostname 主机名
.port 端口号
.pathname 相对路径
.search 获得?以及之后的查询字符串
.hash 获得#锚点地址
2.在当前窗口打开,禁止后退:
Location.replace(“新url”)
3.刷新页面2种:
1.普通刷新:有限从浏览器缓存中获取资源,缓存中过期或没有时才去服务器重新获取
History.go(0)
Location.reload()
F5
2.强制刷新:始终跳过浏览器缓存,总是从服务器端获取新内容:
Location:reload(true)
问题:每次都需要从服务器重新获取,导致加载慢,且增大服务器的压力
(3)Navigator:
什么是:保存浏览器配置信息的对象
何时:获取浏览器配置信息时
包括:
1.判断是否安装某个插件
什么是插件:为浏览器添加新功能的小伙伴
如果判断是否安装了某个插件:
浏览器中所有已安装的插件信息都保存在navigator的plugins集合中,插件名就是插件信息在集合中的下标名.
可以强行访问插件名下标,如果返回的是undefined,就说明没安装.如果返回的不是undefined.就说明安装了
2.判断浏览器的名称和版本号:
浏览器的名称和版本号都包含在一个navigator的userAgent属性中.
但是,userAgent是一个巨大的字符串,我们需要通过字符串查找的方式判断浏览的名称和版本号.
2.事件
什么是:浏览器自动触发的,或用户手动触发的页面内容状态的改变
事件属性:每个元素上都有一批以on开头的事件属性,用于提前保存时间处理函数,当事件发生时,浏览器会自动找到该事件属性上绑定的处理函数,自动执行.
事件处理函数:只要希望事件发生时,能自动执行一项任务.
如何:
1.绑定事件处理函数:3种
1.HTML中:
问题:不便于维护和重新用
2.Js中用赋值方式绑定:
DOM元素 . on事件名=function(。。。}
问题:一个事件属性,只能绑定一个处理函数,如果多次绑定处理函数,只有最后一个事件处理函数可以生效
3.js中用添加事件监听处理方式:
添加 事件 监听
DOM元素 . addEventListener(
“事件名”,事件处理函数
)
原理:
1.其实在浏览器中有一个事件监听对象排列.
2.每为一个DOM元素,绑定一个事件处理函数,就会在监听对象队列中添加一个新的监听对象.
DOM元素 . on事件名=function也是添加事件监听对象的意思,但是第二次执行=function时,不是新增一个对象,而是找到原监听对象替换
DOM元素 . addEventListener是不管当前元素有没有这个事件的处理函数,都增加一个新的监听对象.
3.当事件发生时,浏览器会遍历整个监听对象的队列,找到符合条件的监听对象,执行其中的处理函数

4.当事件发生时,浏览器自动调用对应元素上的对应事件处理函数执行.
5.移除事件监听:
DOM元素 . removeEventListener(
“事件名”,原处理函数对象
)
强调:如果一个处理函数可以被移除,那么在绑定时候就不要用匿名函数,而要用有名称的函数绑定!这样,在移除时,才能通过函数名找到原函数.

DOM事件模型:
什么是:从事件发生开始,到所有处理函数触发完,所经历的整个过程:
包括;3个阶段
1.捕获:由外向内,依次记录各级父元素上绑定的处理函数——只记录,不执行
2.目标触发:先触发目标元素上的处理函数
目标元素:最初想点击的那个元素
3.冒泡:由内向外,依次触发捕获阶段记录的各级父元素上的处理函数

事件对象:
什么是:当事件发生时,浏览器自动创建的,保存时间信息的对象
何时:2种:
1.希望获得事件相关的信息时
2.希望改变事件模型的默认行为
如何:
1.不用自己创建!需要获取即可!
事件对象,总是作为处理函数的第一个参数自动传入,——信任!
当事件发生时:
//window创建event对象

//DOM元素 . on 事件名(event);
DOM元素 . on 事件名=function(e){
//e就获得了window自动创建的event
}
2.取消冒泡:
E.stopPropagation();
停止 蔓延
事件委托(delegate)/利用冒泡:
优化:尽量减少事件监听的个数.
因为:浏览器触发事件时采用的是遍历队列的方式,队列中监听对象多,遍历查找的速度就可能慢,事件响应的速度就可能延迟,队列中监听对象少,遍历查找的速度就快!
如何:今后只要多个评级子元素都要绑定相同的事件时,只要将事件在父元素绑定一次,所有子元素都可通过冒泡原理共享父元素的事件使用!
难题:
1.每个按钮做的事不一样,如何获得实际点击的目标元素?
错误:this不能用!
正确:用e.target代替this
E.target是始终保存目标元素的特殊属性,不随冒泡而改变
2.如何鉴别目标元素是否是想要的:凡是执行正式操作之前,都要先验证目标元素的特征。
优点:
1.事件监听对象个数少,无论有多少个子元素,都可共享一个事件处理函数
2.即使动态添加的元素,也可自动获得处理函数
4.阻止默认行为:
什么是:有些元素上自带了一些默认行为:
比如: 默认回调顶部
默认胡子爱url结尾添加#
如何:e.preventDefault();
5.鼠标位置
3种
1.相对于屏幕左上角的位置:
E.screenX,e.screenY
屏幕 屏幕
2.相对于浏览器种文档显示区左上角的位置
E.clientX,E.clientY
客户端 客户端
3.相对于当前事件绑定的元素左上角的偏移量
E.offsetX e.offsetY
偏移 偏移

总结:DOM优化:
1.查找
如果只有一个条件就可以找到元素时,首选getelementsByxx
如果查找条件复杂,就首选按选择器查找
2.修改样式:能一句话修改的,就不用两句话修改:
为了减少重排重绘
元素.style.cssText=”width:200px;height:100px”
代替:元素.style.width=”200ox”;
元素.style.height=”100px”
3.添加元素,为了减少重排重绘,应该尽量减少操作DOM树的次数
如果同时添加父元素和子元素,应该将子元素添加到父元素,最后再将父元素一次性添加到DOM树
如果父元素已经在页面上,需要同时添加多个平级子元素时,应该创建文档片段,将子元素先加入文档片段中,最后在一次性将文档片段添加到DOM树
4.尽量减少事件监听的个数
只要多个平级元素要绑定相同级的事件时,都要用事件委托
1.将事件绑定在父元素上一份,所有子元素冒泡公用
2.用e.target代替this
3.判断e.target的特征,只有符合条件的目标元素才能执行后续正常的操作.

你可能感兴趣的:(DOM和BOM详细讲解)