一. 函数
函数名实际上是一个指向函数对象的指针
- 声明函数的几种方式
自定义函数(函数声明)
function fun() {
//函数的实现
}
fun(); //调用函数
函数直接量声明(函数表达式)
var fun = function() {
//函数实现
}
fun(); //调用函数
使用对象声明函数
var fun = new Function("函数的实现");
fun(); //调用函数
- 代码运行时,解析器会率先读取函数声明,并使其在执行任何代码之前可用,至于函数表达式,必须等到解析器执行到它所在的代码行,才会真正被解释执行
- 执行环境与作用域链
执行环境定义了变量或者函数有权访问的其他数据,每个执行环境都有一个与之相关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中
每个函数都有自己的执行环境,全局执行环境是最外围的一个执行环境,当执行某个函数时,函数的环境就会被推入一个环境栈中,函数执行完后,环境就会出栈
当代码在一个环境中执行时,会创建变量对象的一个作用域链,并赋值给执行环境的一个特殊的内部属性(即[[Scope]])
作用域链的本质是一个指向变量对象的指针列表
作用域链的用途是保证对执行环境有权访问的变量和函数的有序访问,作用域链的前端始终是当前执行环境的变量对象,下一个变量对象来自包含环境,末端始终是全局执行环境的变量对象
- 其他
在函数内部使用this关键字表示函数的调用者
使用函数名.length可获得函数形参的个数,函数名.caller指向调用该函数的函数,如果是在全局调用,则为null
函数内部arguments是一个存放函数实参的数组,arguments.length可以获取实参的个数
函数内部arguments.callee代表函数本身
二. DOM
DOM:document object model 文档对象模型
- 节点(node)
标签是节点,元素是节点,属性是节点,文字是节点,一切皆节点
节点类型 | nodeType | nodeName | nodeValue | 创建方法 |
---|---|---|---|---|
文档(Document) | 9 | #document | null | |
元素节点(Element) | 1 | 元素标签名称 | null | createElement |
文本节点(Text) | 3 | #text | 文本的内容 | createTextNode |
注释节点(Comment) | 8 | #comment | 注释的内容 | createComment |
文档类型(DocumentType) | 10 | docType名称 | null | 不能动态创建,通过document.doctype获取 |
特性节点(Attr) | 2 | 特性的名称 | 特性的值 | createAttribute |
文档片段(DocumentFragment) | 11 | #document-fragment | null | createDocumentFragment |
获取元素节点
getElementById:通过id获取对应的元素,是唯一的
getElementsByTagName:通过标签名获取所有同种标签
getElementsByClassName:通过类名获取所有同类元素
querySelector:通过css选择符,获取匹配的第一个元素
querySelectorAll:通过css选择符,获取匹配的所有元素
matchesSelector:判断调用元素是否与传入的css选择符匹配其他获取节点的方式
<div id="box">
<div>1</div>
<div id="box1">
<span>1</span>
<span>2</span>
<span>3</span>
</div>
<div>3</div>
<div>4</div>
<div>5</div>
</div>
box1.parentNode:父节点box
box1.childElementCount:返回子元素的个数
box1.nextSibling:下一个兄弟节点,box1与3号div之间的换行
box1.nextElementSibling:下一个兄弟元素节点,3号div
box1.previousSibling:上一个兄弟节点,box1与1号div之间的换行
box1.previousElementSibling:上一个兄弟元素节点,1号div
box1.firstChild:第一个子节点,1号span前面的换行
box1.firstElementChild:第一个子元素节点,1号span
box1.lastChild:最后一个子节点,3号span后面的换行
box1.lastElementChild:最后一个子元素节点,3号span
box1.childNodes:所有的子节点,4个换行加3个span(共7个),可以通过nodeType来判断是否为元素节点,元素节点为1
box1.children:获取所有的子元素节点,3个span
- 节点操作
创建节点 createElement()
var box1 = document.createElement('div');
添加节点,添加的都是子节点
appendChild('节点') 添加节点到元素的最后面
insertBefore('新节点', '参考节点') 添加节点到参考节点的前面
insertBefore('新节点', null)等价于appendChild()
var box = document.getElementById('box');
box.appendChild(box1);
删除节点 removeChild()
box.removeChild(box1);
克隆节点 cloneNode()
box.cloneNode(); //只克隆box节点
box.cloneNode(true); //克隆box及内部所有节点
某个节点是否是另一个节点的后代contains()
box.contains(p) // 节点p是否是节点box的后代
- 节点特性
获取特性 getAttribute(特性名)
var box = document.getElementById('box');
var className = box.getAttribute('class');
设置特性 setAttribute(特性名,特性值)
box.setAttribute('class', 'demo');
删除特性 removeAttribute(特性名)
box.removeAttribute('title'); //box的title特性被删除
通过attributes属性遍历元素的所有特性
for (let attr of box.attributes) {
console.log(attr.nodeName)
console.log(attr.nodeValue)
}
- 文本节点操作
- appendData:将text添加到节点的末尾
- deleteData(offset, count):从offset位置开始删除count个字符
- insetData(offset, text):在offset位置插入text
- replaceData(offset, count, text):用text替换从offset位置开始到offset+count为止处的文本
- splitText(offset):从offset位置将当前的文本节点分成两个文本节点
let div = document.createElement('div')
let text = document.createTextNode('hello world!')
div.appendChild(text)
document.body.appendChild(div)
console.log(div.childNodes.length) // 1
console.log(div.firstChild.nodeValue) // hello world!
div.firstChild.splitText(5)
console.log(div.childNodes.length) // 2
console.log(div.firstChild.nodeValue) // hello
- substringData(offset, count):提取从offset位置开始到offset+count为止处的字符串
- normalize()
一般情况下, 每个元素只有一个文本子节点,某些情况下可能包含多个文本子节点,可以使用normalize()方法将所有的文本节点合并成一个
let div = document.createElement('div')
let text1 = document.createTextNode('hello ')
div.appendChild(text1)
let text2 = document.createTextNode('world!')
div.appendChild(text2)
document.body.appendChild(div)
console.log(div.childNodes.length) // 2
div.normalize()
console.log(div.childNodes.length) // 1
console.log(div.firstChild.nodeValue) // hello world!
- documentFragment文档片段
给一个已经存在的ul元素中添加3个li元素,如果逐个添加,会导致浏览器反复渲染,因此可以使用文档片段一次性添加
let ul = document.getElementById('list') // 文档中有一个id为‘list’的ul元素
let fragment = document.createDocumentFragment()
for (let i = 0; i < 3; i++) {
let li = document.createElement('li')
li.innerHTML = `item${i}`
fragment.appendChild(li)
}
ul.appendChild(fragment)
通过classList属性操作类名
add(value):添加类名
contains(value):类名列表是否包含该类名
remove(value):从类名列表中删除指定类名
toggle(value):如果类名列表中有该类名,则删除,否则添加焦点管理
通过document.activeElement属性可以获取DOM中当前获得焦点的元素
通过document.hasFocus()方法可以用于确定文档是否获得了焦点插入标记
innerHTML:读模式下返回调用元素所有的子节点,写模式下其值会被解析为DOM子树,替换调用元素原来的所有子节点
outerHTML:读模式下返回调用元素本身及所有的子节点,写模式下其值会创建新的DOM子树并替换整个调用元素
insertAdjacentHTML():插入标记,接受两个参数,插入的位置和要插入的HTML文本,第一个参数必须是下列值之一
beforebegin:在当前元素之前插入一个紧邻的同辈元素
afterbegin:在当前元素前端插入一个子元素
beforeend:在当前元素末端插入一个子元素
afterend:在当前元素之后插入一个紧邻的同辈元素
innerText:读模式下返回调用元素中包含的所有文本内容,写模式下会将其值以文本的形式替换调用元素的所有子元素
<div id='content'>
<p>This is a <strong>paragraph</strong> with a list following it.</p>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<ul/>
</div>
// 对于这个例子中的div元素而言,其innerText属性返回下列字符串,由于浏览器的不同,也可能不包含原始HTML代码中的缩进
This is a paragraph with a list following it.
Item 1
Item 2
Item 3
outerText:读模式下与innerText的结果相同,但在写模式下会替换整个调用元素
三. DOM遍历
使用NodeIterator和TreeWalker可以对DOM结构执行深度优先(从上至下,从左往右)的遍历操作
- NodeIterator
使用document.createNodeIterator()方法创建,接受4个参数
- root:想要作为遍历起点的节点
- whatToShow:遍历节点的过滤类型,常用的有以下几种
1.NodeFilter.SHOW_ALL:显示所有类型的节点
2.NodeFilter.SHOW_ELEMENT:显示元素节点
3.NodeFilter.SHOW_TEXT:显示文本节点
4.NodeFilter.SHOW_ATTRIBUTE:显示属性节点 - filter:节点过滤的函数,如果应该访问给定的节点,则返回NodeFilter.FILTER_ACCEPT,否则返回NodeFilter.FILTER_SKIP。没有过滤函数传null
- entityReferenceExpansion:是否扩展实体引用,在HTML页面中没有用
NodeIterator类型的主要方法是nextNode()(不过滤的情况下,该方法返回的是起点节点)和previousNode()
<div id='div1'>
<p>Hello world!</p>
<ul>
<li>List Item 1</li>
<li>List Item 2</li>
<li>List Item 3</li>
</ul>
</div>
// 遍历li元素
let div = document.getElementById('div1')
let filter = function(node) {
return node.tagName.toLowerCase() === 'li' ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP
}
let iterator = document.createNodeIterator(div, NodeFilter.SHOW_ELEMENT, filter)
let node = iterator.nextNode()
while (node !== null) {
alert(node.tagName)
node = iterator.nextNode()
}
- TreeWalker
使用document.createTreeWalker()方法创建,接受与createNodeIterator相同的4个参数,从起点节点的第一个子节点开始。除了包括nextNode()(不过滤的情况下,该方法返回的是起点节点的第一个子节点)和previousNode()方法外,还提供下列方法
- parentNode():遍历到当前节点的父节点
- firstChild():遍历到当前节点的第一个子节点
- lastChild():遍历到当前节点的最后一个子节点
- nextSibling():遍历到当前节点的下一个同辈节点
- previousSibling():遍历到当前节点的上一个同辈节点
参数filter函数返回的值有所不同,除了NodeFilter.FILTER_ACCEPT与NodeFilter.FILTER_SKIP外,还可以使用NodeFilter.FILTER_REJECT。区别是FILTER_SKIP跳过相应节点继续前进到下一个节点,FILTER_REJECT会跳过相应节点及子节点
上面的例子中,如果使用TreeWalker遍历,且filter返回值改为NodeFilter.FILTER_REJECT,则不会有任何结果,因为ul及其子节点都会被跳过
该类型还有一个属性为currentNode,表示遍历到的当前元素,修改该值,可以修改遍历的起点
四. offset
通过offset可以获取元素尺寸,offset属性是只读的,只能获取值,不能赋值
offsetWidth,offsetHeight
offsetWidth:元素的宽度,offsetHeight:元素的高度
offsetWidth = width + padding + border
offsetWidth = height + padding + borderoffsetTop,offsetLeft
offsetTop:元素到已定位父级元素上边的距离
offsetleft:元素到已定位父级元素左边的距离
从父级的padding开始算,border不算,也就是到父级元素边框的距离
如果父级都没有定位,则以顶级元素(一般为html)为准offsetParent
返回最近的已定位的父级元素
与parentNode的区别:parentNode获取的是父元素,无论是否定位,offsetParent是获取已定位的父级元素,如果都没有定位,则结果为bodyoffsetTop与style.top的区别
offsetTop只读,style.top可读写
offsetTop是数值(50),style.top是带有单位的字符串("50px")
任何元素都有offsetTop,而只有定位的盒子才有style.top
style.top只能得到行内样式,js设置的样式都是行内样式
五. scroll
当内容超出元素,且元素overflow为scroll时,元素可滚动
通过scroll可以获取到元素滚动的尺寸
scrollTop,scrollLeft
scrollTop:向上滚动的距离
scrollLeft:向左滚动的距离获取网页scrollTop的方法
谷歌及未声明DTD的浏览器:document.body.scrollTop,document.body.scrollLeft
火狐及其他浏览器:document.documentElement.scrollTop,document.documentElement.scrollLeft
ie9以上及最新浏览器:window.pageYOffset,window.pageXOffset
兼容性写法
var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
scrollTo(x, y)
滚动内容到指定的位置scrollWidth,scrollHeight
如果盒子的内容没有超过盒子,则为盒子的宽高(不包括border),否则为内容的宽高(包括padding)
六. client
通过client可以获取元素的可视区域
clientWidth,clientHeight
元素可视区域的宽度,包括padding,不包括border
可理解为不含border的offsetWidth与offsetHeightclientTop,clientLeft
clientTop:上边框的宽度
clientLeft:左边框的宽度client与offset、scroll的区别
七. 其他
HTML基本结构访问方法
文档:document
body:document.body
title:document.title
head:document.head
html:document.documentElement检测窗口区域
window.innerWidth,window.innerHeight:窗口的宽高
document.documentElement.clientWidth:窗口的宽高,不包括滚动条宽高
document.body.clientWidth:body的宽高,包括padding,不包括border
window.screen.width,window.screen.height:屏幕的分辨率事件冒泡
当一个元素上的事件被触发的时候,该元素的所有祖先元素都会触发此事件
不是所有的事件都能冒泡,以下事件不能冒泡:blur、focus、load、unload
阻止冒泡的方法:
一般浏览器event.stopPropagation()
ie浏览器event.cancelBubble = true选中文字
获取选中的文字:
一般浏览器:window.getSelection().toString()
ie:document.selection.createRange().text
取消选中:
一般浏览器:window.getSelection().removeAllRanges()
ie浏览器:document.selection.empty()各种坐标
pageX、pageY:相对于顶级元素
clientX、clientY:相对于浏览器窗口
screenX、screenY:相对于屏幕
offsetX、offsetY:相对于触发事件的元素
layerX、layerY:如果触发事件的元素有定位或者overflow不为visible,则相对于该元素,否则相对于已定位或overflow不为visible的父元素,若没有,相对于顶级元素