DOM
DOM查询
- 通过
domcument
对象获取元素节点:-
getElementById("id")
:通过id
属性获取一个元素节点对象; -
getElementsByTagName("tag")
:通过标签名获取一组元素节点对象; -
getElementsByTagName("*")
:支持通配符,获取所有节点对象; -
getElementsByName("name")
:通过name
属性获取一组元素节点对象。 - 获取元素节点的属性值:
节点对象.属性名
,但对于class
属性,节点对象.className
-
- 通过具体的元素节点对象获取其子节点:
-
childNodes
:获取其所有的子节点,包括文本节点、换行、标签间的空白等,但IE8
不会; -
children
:获取所有的子元素,只获取标签元素,且是直接子元素; -
firstChild/lastChild
:获取第一个/最后一个子节点,也包括文本节点、换行,空白等; -
firstElementChild
:获取第一个标签元素,不兼容<=IE8
;
-
- 获取父节点和兄弟节点:
-
parentNode
:获取当前节点的父节点; -
previousSibling/nextSibling
:获取前/后一个兄弟节点; -
previousElementSibling
:获取前一个兄弟标签元素,也不兼容<=IE8; -
innerText/innerHTML/textContent
:都可以获取一个标签的内容,innerHTML
的内容包含子标签,而innerText
和textContent
只获取标签内的字符串文本; - 只获取标签内自己的字符串:
firstChild.nodeValue
,没有字符串文本,则返回空字符串;对于不能做父元素的标签,如<img/>
, 其firstChild
为null
-
- 每个节点(包括文本节点)都具有的
3
个属性:nodeName、nodeType、nodeValse
- 文档节点:
nodeName =>#document、nodeType =>9、nodeValse =>null
- 元素节点:
标签名、1、null
- 属性节点:
属性名、2、属性值
- 文本节点:
#text、3、文本内容
- 文档节点:
-
document.documentElement/body
:获取<html>/<body>
的元素对象; -
document.all/document.getElementsByTagName("*")
:获取所有节点的标签元素; -
getElementsByClassName('选择器名称')
:根据class
属性值获取一组元素,兼容到>=IE8
-
querySelector('CSS选择器')
:根据CSS
选择器获取标签元素,只返回第一个,兼容到>=IE8
; -
querySelectorAll('CSS选择器')
:返回一组标签元素; -
HTML
是自顶向下解析的,不能提前获取document
节点- 在
<body>
标签之后使用<script>
,可以获取节点对象; -
window.onload = function(){ ... }
:等待HTML
文档加载并渲染完成再执行.
- 在
DOM增删改
-
appendChild()/removeChild()/replaceChild()
:添加/删除/替换子节点; -
insertBefore(newNode, oldNode)
:在指定的子节点前插入新的子节点; -
createElement()/createAttribute()/createTextNode()
:创建元素/属性/文本节点;
var li = document.createElement("li"); --> 创建一个<li>
var text = document.createTextNode("Mark"); --> 创建文本节点
li.appendChild(text); --> 把文本节点添加到<li>中
-
innerHTML
也可以完成DOM的增删改:li.innerHTML="<span>Smith</span>"
var li = document.createElement("li");
li.innerHTML = "Mark"; --> create与innerHTML结合使用
-
setAttribute()/getAttribute()
:设置/获取指定的属性; -
confirm(str)
:确认/取消提示框,带有确认和取消按钮,返回true/false
;
<button>Button-1</button> <button>Button-2</button>
window.onload=function(){
var btns = document.getElementsByTagName("button")
for (var i=0; i<btns.length; i++) {
btn[i].onclick=function(){
confirm(this.innerHTML); --> this指向当前button对象
confirm(btns[i].innerHTML); -->报异常undefined,此时的i=btns.length
}; --> 页面加载完成,首先执行的是for循环,而不会执行函数;
} --> 在点击按钮时,此时的i=btns.length,所以报异常;
}; --> 而函数内的this始终指向调用者,所以可以正常执行。
DOM操作CSS
JS修改元素样式
- 选择器中的样式是无法获取,也无法修改的,但可以操作元素的内联样式,其优先级高于选择器;
-
元素对象.style.样式名 = "样式值"
,通用写法:元素对象.style["样式名"] = "样式值"
- 对于
-
连接的属性,则去掉-
,并把后面的首字母大写:btn.style.fontSize="20px"
; - 通用形式则不需要去掉属性名中的连接符:
btn.style["font-size"]="20px"
; -
<style>
中的选择器应避免使用!important
,它表示样式的最高优先级,内联样式也无法覆盖; -
element.setAttribute('style', 'width:20px;height:30px;')
:设置元素的style
属性; -
element.setAttribute('style')
:移除元素的style
属性,也即删除style
样式; - 如果要修改多个样式,可以在
<style>
中预定义CSS样式选择器,再赋值给元素的className
属性,这种方式的性能比较高,也使得JS和CSS更好的分离。
JS获取元素样式
-
element.style
:获取的是当前元素上的所有内联样式,包括默认存在的内联样式; -
element.style.样式名、element.style["样式名"]
:根据属性名获取内联样式的属性;- 获取的只是内联样式上的属性,如果内联样式上没有手动设置该属性,则获取的属性值为'';
-
element.style.cssText
:只获取标签上手动设置的CSS样式,是一个字符串;
element.style.cssText = "width:100%;font-size:16px;" -->修改/添加内联样式
-
element.getAttribute('style')
:获取标签上的style属性值,同element.style.cssText
-
element.currentStyle.样式名
:IE独有的,获取元素当前正在使用的所有样式信息;如果没有手动设置样式的默认值,则返回auto
; -
getComputedStyle(element, null)
:window
的方法,获取元素当前正在使用的的所有样式;
let sty = getComputedStyle(btn, null)
-
sty["background-color"]
返回的是rgb
值,btn.style["background-color"]
返回的是当前样式中设置的background-color
属性值; - 不兼容
<=IE8
-
-
currentStyle
和getComputedStyle()
获取的属性都是只读的,不能修改; - 获取CSS样式属性的兼容方式:
function getStyle(element, styleName) {
if(window.getComputedStyle) {
return getComputedStyle(element, null)[styleName];
} else { --> IE8的window中没有getComputedStyle,则返回undefined,即false
return element.currentStyle[styleName];
} --> 属性styleName要显示设置一个默认值,否则浏览器可能返回auto
}
DOM属性事件
-
clientWidth/clientHeight
:获取元素的可见宽高,不带单位px
,返回的是数值;clientWidth = width + paddingLeft + paddingRight
-
clientWidth和clientHeight
都是只读属性; - 浏览器窗口的宽度/高度:
document.documentElement.clientWidth/clientHeight
-
scrollWidth/scrollHeight
:获取元素的滚动区域宽高;- 如果元素区域带有滚动条,
clientWidth/clientHeight
只能获取滚动窗口内可见的宽高,而scrollWidth/scrollHeight
获取的宽高,包含滚动窗口外的宽高; -
clientWidth/clientHeight
获取的宽高包含滚动条的宽度/高度; -
scrollLeft/scrollTop
:水平/垂直滚动的距离; - 当垂直滚动条滚到底部时,
clientHeight == scrollHeight-scrollTop
-
element.onscroll = function(){};
:绑定滚动条滚动事件
- 如果元素区域带有滚动条,
-
offsetWidth/offsetHeight
:获取元素的整个宽度和高度,width+padding+border
-
offsetParent
:获取距离最近的、使用了定位的父元素对象,如果都没有定位,则返回body
; -
offsetLeft/offsetTop
:当前元素相对于其定位父元素的水平/垂直偏移量,都是只读的属性;
上传图片
<input type="file" accept="image/*" onchange="uploadImg(this)" />
- accept:指定上传文件的类型,打开资源管理器展示的文件类型;
- onchange:<input/>中的内容发生变化时的事件;
- 预览图片,FileReader是H5提供的,用于读取文件
uploadImg(ev) {
let file = ev.files[0]
let reader = new FileReader() -->创建FileReader对象
reader.onloadstart = function (e) { //开始读取 }
reader.onprogress = function (e) { //正在读取中 }
reader.onabort = function (e) { //中断读取 }
reader.onerror = function (e) { //读取异常 }
reader.onload = function (e) { --->读取成功的回调
let img = document.querySelector("input[type=file]")
img.src = e.target.result
}
reader.readAsDataURL(file) --->开始读取本地选择的文件
}
-
element.onmousemove = function(event){}
:鼠标在元素中移动时被触发;- 回调的参数
event
中封装了所有信息,如鼠标的水平/垂直坐标:clientX/clientY
- 但在
IE8
中不会回调event
,而是将事件对象保存在window
的属性中:window.event
-
clientX/clientY
只针对当前浏览器的可见窗口,窗口左上角的坐标始终是(0, 0)
; -
pageX/pageY
:鼠标相对于当前页面的坐标,页面左上角的坐标才是(0, 0)
,不兼容IE8
;
- 回调的参数
- 页面垂直滚动时,
scrollTop
的兼容性:获取页面滚动的距离;-
document.body.scrollTop
:只适用于Chrome
浏览器,其他浏览器返回0
; -
document.documentElement.scrollTop
:适用于Foxfire、IE
,但Chrome
仍返回0
; - 水平方向滚动时,
scrollLeft
同理。
-
-
事件冒泡:如果父节点和子节点绑定了相同的事件,那么触发子节点事件时,父节点也会触发;
- 事件只会向上传递父节点的相同事件,不会向下传递;
- 阻止事件冒泡:
event.stopPropagation(); --> 不兼容IE
-
IE
浏览器特有的阻止事件冒泡:window.event.cancelBubble = true;
事件委托
事件委托:多个子元素需要注册同一种事件时,给其共同的父元素注册该事件,事件响应时,通过回调参数 event
获取每个子元素,根据不同的子元素,执行不同的代码;
<ul>
<li><a href="javascript:;">超链接一</a></li>
<li><a href="javascript:;">超链接二</a></li>
</ul>
var uls = document.getElementsByTagName("ul")[0];
uls.onclick = function(event) {
event = event || window.event; --> 兼容IE
var node = event.target; --> 获取当前点击的子元素节点对象
};
-
event.currentTarget 、 event.target
-
click
事件实际注册到<ul>
标签上,event.target
获取的是实际点击标签的元素对象;
点击<li>
,则event.target
就是li
;点击<a>
,则event.target
就是a
。 -
event.currentTarget
获取的是实际注册click
事件的元素对象,始终是<ul>
对象。
-
-
event.relatedTarget
返回与事件的目标节点相关的节点- 对于
mouseover
事件来说,该属性是鼠标指针移到目标节点上时所离开的那个节点。 - 对于
mouseout
事件来说,该属性是离开目标时,鼠标指针进入的节点。 - 对于其他类型的事件来说,这个属性没有用。
- 对于
函数节流:
- JS中有些事件的触发频率特别高,比如:onresize,onmousemove
- 对于短时间内高频率触发的函数,可以在函数内使用定时器减少触发次数,实现函数节流;
- 在触发定时器之前,先清除一次定时器,只保留最后一次定时器任务;
clearTimeout(timer); timer = setTimeout(function{ ... }, 200);
事件
-
addEventListener("事件名", function, false)
:事件绑定,事件名不带on
; -
element.onclick=function(event){}
; ->属性的方式绑定事件,多次绑定同一事件时,最后一次绑定会覆盖之前的事件; - addEventListener() 可以重复绑定同一事件,响应事件时,从第一次绑定时开始响应;
uls.addEventListener('click', function(){}, false); --> 绑定click事件
-
removeEventListener('事件名', callback)
:移除绑定的事件,callback
并不是移除事件的回调,而是addEventListener()
的回调函数名,因为它可以对同一事件绑定多次; -
addEventListener()
只兼容到IE9
,而在IE8
中,绑定事件使用attachEvent()
-
attachEvent("事件名", function)
:事件名中带on
,也可以多次绑定同一个事件,但事件的响应顺序与addEventListener()
相反; -
addEventListener()
中的this
指向绑定事件的对象,而attachEvent()
中指向window
; - 兼容性:
function bind(obj, event, callback) {
if(obj.addEventListener) {
obj.addEventListener(event, callback, false);
} else {
obj.attachEvent("on"+event, function() {
callback.call(obj); // 让回调函数中的this指向绑定的对象
});
}
}
- 事件的传播:
- 微软公司认为事件应该从内向外,即事件冒泡的形式;而网景公司认为恰恰相反;
-
W3C
综合两种方案,将事件传播分为3
个阶段:捕获阶段、目标阶段、冒泡阶段 - 捕获阶段:事件从最外层的父元素,向目标子元素进行事件的捕获,但默认此时不会触发事件;
- 目标阶段:事件捕获到目标元素,捕获结束,开始在目标元素上触发事件;
- 冒泡阶段:事件从目标元素向父元素传递,并依次触发父元素上的事件;
- 在捕获阶段也触发事件:
addEventListener("事件名", function, true)
-
IE<=8
没有事件捕获阶段。
- 鼠标按下/移动/松开:
onmousedown、onmousemove、onmouseup
- 拖拽网页中的内容时,浏览器默认会执行搜索内容,导致拖拽功能异常;
-
return false;
禁止默认行为,但不兼容IE8
-
element.setCapture();
捕获element绑定的相关事件,优先响应; -
element.releaseCapture();
释放捕获; - 但是,
setCapture()
只有IE
支持,Firefox
不会报错,Chrome
会报错;
element.setCapture && element.setCapture(); --> 有setCapture()方法,则执行
- 鼠标拖拽标签:
element.onmousedown = function(event){ // 给被拖拽的标签注册鼠标的按下事件
if (event.button != 0) return; // 只有鼠标左键按下才有效
element.setCapture&&element.setCapture() // 兼容IE
document.onmousemove = function(e){ // 把移动事件注册到document上,防止卡顿
...... // 更改标签的left/top,达到移动效果
e.preventDefault(); // 阻止浏览器的默认行为
}
document.onmouseup = function(e){ // 抬起事件也必须注册到document上,任何地方
document.onmousemove = null; // 都可以取消事件
document.onmouseup = null;
document.releaseCapture&&document.releaseCapture(); // 兼容IE
}
// 屏蔽第二次拖拽时的鬼影,return false 无效
event.preventDefault();
event.stopPropagation();
}
- 鼠标滚轮:
onmousewheel
,但Firefox
不支持,而是使用DOMMouseScroll
,而且火狐必须通过addEventListener()
绑定滚轮事件;-
event.wheelDelta
:鼠标滚轮滚动的方向,只看正负,不管大小,负值表示向下滚动; -
FireFox
也不支持event.wheelDelta
,而是使用event.detail
,正数表示向下滚; - 如果浏览器有滚动条,滚动鼠标滚轮将执行浏览器的默认行为,而不会执行元素的滚轮事件;
-
element.onmousewheel=function(event){
return false; // 阻止浏览器的默认行为,执行元素的滚轮事件;
};
element.addEventListener("DOMMouseScroll", function(event){
event.preventDefault && event.preventDefault(); // 阻止浏览器的默认行为
}, false);
-
return false;
在addEventListener()
注册的事件中,无法阻止浏览器的默认行为,必须使用tevent.preventDefault();
- 鼠标右击事件:
oncontextmenu
- 键盘事件:
onkeydown(按下)、onkeyup(松开)、onkeypress(按下并松开)
- 键盘事件一般绑定给可以获取焦点的元素对象,或者
document
,比如<input />
输入框; - 对于
onkeydown
,如果长时间按下一个按键,那么事件将一直触发,而且第一次和第二次触发的时间间隔会比第二次之后的时间间隔长一些,为了避免误操作; -
event.KeyCode
:获取按键的编码,从而判断按键的类型,如y=89
-
altKey、ctrlKey、shiftKey
:判断Alt、Ctrl、Shift
键是否被按下;
event.keyCode===89 && event.ctrlKey --> Ctrl+y
-
<input />
的onkeydown
事件默认行为就是输入内容,return false;
可以阻止输入。
- 键盘事件一般绑定给可以获取焦点的元素对象,或者
- 阻止默认行为:
return false;
与event.preventDefault();
- 在jQuery中,
return false;
相当于同时调用preventDefault()
和stopPropagation();
-
IE
不支持preventDefault()
,需要使用:window.event.returnValue = false;
- 在原生
JS
中,addEventListener()/attachEvent()
绑定的事件中,不支持return false
阻止默认行为,必须使用preventDefault()、window.event.returnValue=false
- H5规范指出,在
mouseover
等几种特殊事件中,return false;
并不一定能终止事件,所以H5建议尽量不要使用return false
来阻止事件的默认行为。
- 在jQuery中,
BOM
BOM:浏览器对象模型,可以让我们通过JS来操作浏览器;
- BOM对象:
Window、Navigator、Location、History、Screen
-
Window
:代表整个浏览器窗口,同时,window也是网页中的全局对象; -
Navigator
:表示当前浏览器的信息,可以用来识别不同的浏览器; -
Location
:浏览器的地址栏,可以获取地址栏信息,操作浏览器跳转页面; -
History
:表示浏览器的历史纪录,但由于隐私原因,不能获取到具体的历史纪录,只能操作
浏览器向前/后退,而且只在当次访问时有效,关闭之后再打开则无效; -
Screen
:表示拥护的屏幕信息,可以获取显示器的相关信息,常用于移动端; - 这些
BOM
对象在浏览器中都是作为window
对象的属性保存的,又因为window
是全局的对象,可以直接使用这些对象,而不用通过window.navigator
调用;
-
-
Navigator
- 由于历史原因,
navigator
对象中的大部分属性都已经不能识别浏览器了; - 一般只会使用
userAgent
来判断浏览器的信息:navigator.userAgent
-
IE11
中的userAgent
已经去除了微软和IE
的相关标识,不能通过userAgent来准确识别IE
; -
window.ActiveXObject
:IE
特有的函数,根据这些特有的信息获取浏览器的类型;
- 由于历史原因,
if(window.ActiveXObject) --> 微软发现了这种判断方式,所以在IE11返回的是false
但并不意味着IE11中没有该对象:if("ActiveXObject" in window) --> true
-
History
-
length
:浏览器历史列表中的URL
数量; -
back()/forward()
:加载前/下一个,回退/前进一个页面; -
go()
:加载某个具体页面,go(1)
相当于forward()
,go(-1)
相当于back()
;
-
-
Location
-
location
可以获取地址栏的完成信息,也可以直接操作地址栏,同window.location
- 属性:
hash、host、hostname、href、pathname、port、protocol、search
-
-
location.href = "https://www.baidu.com/"
:重定向到一个新的网站,会生成历史纪录 -
location = "/login/login.html"
:重定向到新的页面,当前域名/login/login.html
-
window.location.search
:获取地址的参数部分,?...
-
window.location.hash
:获取页面的锚点,#...
-
-
assign()
:加载新的文档,assign("https://www.baidu.com/")
-
reload()
:刷新,默认刷新带有缓存,reload(true)
:强制清空缓存刷新 -
replace()
:用新的文档替换当前文档,不会生成历史纪录,即不能回退。 -
window.open()
:开启一个新的窗口,加载文档。
定时器
setTimeout()、setInterval()、clearTimeout()、clearInterval()
- 延迟任务:
-
setTimeout(function, time)
:time
毫秒之后执行function
,返回Number
型的数据; -
clearTimeout(timer)
:即使timer
是undefined
,也不会报错,什么也不做;
-
- 定时任务
-
setInterval(function, time)
:每隔time
毫秒执行一次function
; -
clearInterval(timer)
:清除定时器;
-
JSON
-
JSON
:JavaScript Object Notation
,JS对象表示法- JSON和JS对象的格式一样,只不过JSON字符串中的属性名必须加双引号;
var str = '{"name": "Mack", "age": 18}';
- JSON类型:
对象{},数组[]
- JSON中允许的属性值:
字符串、数值、布尔值、null、对象、数组
- JSON和JS对象的格式一样,只不过JSON字符串中的属性名必须加双引号;
-
JSON
字符串与JS对象相互转换:JSON
-
JSON.parse(str)
:JSON字符串转JS对象; -
JSON.stringify(obj)
:JS对象转JSON字符串; -
IE7
不支持JSON,可以使用eval(str)
函数,将一个字符串转为有效的表达式;
-
var obj = eval("(" + str +")"); -->对字符串加"()",告诉浏览器{}不是一个代码块;
// obj = {"name": "Mack", "age": 18}
- 但是,
eval()
的性能比较低,而且存在安全隐患,转换的字符串可能是一段有害的JS代码。