(0)有些HTML属性名是JavaScript的保留字,转为JavaScript属性时,必须更名。主要是如下两个。javascript
若要在HTML元素上附加数据,供JavaScript脚本使用css
注:data-后面的属性名只能包含小写字母、数字、连词线(-)、点(.)、冒号(:)和下划线(_)html
(1)判断一个节点有无子节点,三种方法java
node.hasChildNodes()
node.firstChild !== null
node.childNodes && node.childNodes.length > 0
例:结合firstChild
属性和nextSibling
属性,遍历当前节点的全部后代节点node
function DOMComb(parent, callback) { if (parent.hasChildNodes()) { for (var node = parent.firstChild; node; node = node.nextSibling) { DOMComb(node, callback); } } callback(parent); } // 用法 DOMComb(document.body, console.log)
(2)removeChild npm
该方法是在当前结点的父节点上调用的。编程
例:移除当前结点的全部子节点数组
var element = document.getElementById('xxx'); while (element.firstChild) { element.removeChild(element.firstChild); }
结点的children属性是一个只读属性,随子节点的变化会实时更新。
在删除多个节点时,务必注意children属性时刻都在变化。浏览器
(3)compareDocumentPosition()缓存
七个比特位的二进制值,表示参数节点与当前节点的关系
000000 0 两个节点相同 000001 1 两个节点不在同一个文档(即有一个节点不在当前文档) 000010 2 参数节点在当前节点的前面 000100 4 参数节点在当前节点的后面 001000 8 参数节点包含当前节点 010000 16 当前节点包含参数节点 100000 32 浏览器内部使用
最终结果须要结合比特位运算。
(4)结点集合
NodeList 实例是一个类数组对象,可转化为真正的数组,支持for和foreach遍历
var children = document.body.childNodes; var nodeArr = Array.prototype.slice.call(children);
NodeList实例多是动态集合,也多是静态集合。
动态集合是一个活的集合,DOM删除或新增一个相关节点,会马上反映在NodeList实例上。
注:目前只有node.childNodes返回的NodeList是动态集合。
其余返回NodeList的方法
HTMLCollection 实例是一个类数组对象,只包含元素(Element)结点,只支持for遍历,动态集合。
以及元素定位方法
document.styleSheets属性返回文档内嵌或引入的样式表集合,类型StyleSheetList。
(5)HTML表单
经常使用标签
文本框:<input type="text">,用于输入文本; 口令框:<input type="password">,用于输入口令; 单选框:<input type="radio">,用于选择一项; 复选框:<input type="checkbox">,用于选择多项; 下拉框:<select>,用于选择一项; 多行文本框:<textarea>,定义多行的文本输入控件 隐藏文本:<input type="hidden">,用户不可见,但表单提交时会把隐藏文本发送到服务器。 文件选择:<input type="file">:HTML表单中用于上传文件
当一个表单包含<input type="file">时,表单的enctype必须为multipart/form-data,method必须为post,浏览器才能正确编码并以multipart/form-data格式发送表单数据。
(6)根据name属性获取标签结点
document.querySelectorAll('*[name="xxx"]'); document.getElementsByName("xxx");
注意,没有name属性的<input>的数据不会被提交。
(7)网页属性
a. 整张网页的总高度/宽度
document.documentElement.scrollHeight/scrollWidth document.body.scrollHeight/scrollWidth
b. 整张网页的水平的和垂直的滚动距离
document.documentElement.scrollLeft document.documentElement.scrollTop
注:该属性均可读写,设置该属性的值,会致使浏览器将当前元素自动滚动到相应的位置。
c. 计算元素左上角相对于整张网页的坐标
function getElementPosition(e) { var x = 0; var y = 0; while (e !== null) { x += e.offsetLeft; y += e.offsetTop; e = e.offsetParent; } return {x: x, y: y}; }
获取document对象的方法
document
或window.document
iframe
框架里面的网页,使用iframe
节点的contentDocument
属性XMLHttpRequest
对象的responseXML
属性ownerDocument
属性document对象一般有2个子结点
(1)document.doctype:指向<DOCTYPE>
节点,一般为<!DOCTYPE html>,与document.firstChild等效
(2)document.documentElement:指向当前文档的根节点,一般为<html>
document.head和document.body属性分别直接指向<head>节点和<body>节点。
状态属性
document.visibilityState
该属性返回文档的可见状态:
应用场景:
document.readyState
该属性返回当前文档的状态:
loading
:加载HTML代码阶段(还没有完成解析)interactive
:加载外部资源阶段complete
:加载完成页面加载过程:
document.readyState
属性等于loading
<script>
元素,而且没有async
或defer
属性,就暂停解析,开始执行脚本,这时document.readyState
属性仍是等于loading
document.readyState
属性变成interactive
document.readyState
属性变成complete
方法
document.createTextNode()
用于生成文本节点(Text实例)。
该方法能够确保返回的节点,被浏览器看成文本渲染,而不是看成HTML代码渲染。所以,能够用来展现用户的输入,避免 XSS 攻击。
var div = document.createElement('div'); div.appendChild( document.createTextNode('<span>Foo & bar</span>') ); console.log(div.innerHTML) 结果:<span>Foo & bar</span>
会对大于号和小于号进行转义,保证即便用户输入的内容包含恶意代码,也能正确显示。
但该方法不对单引号和双引号转义,因此不能用来对HTML属性赋值。
document.createDocumentFragment()
该方法生成一个空的存在于内存中的文档片断对象。
新对象不属于当前文档,经常使用来生成一段较复杂的DOM结构,而后再插入当前文档,避免直接修改当前DOM引起网页的从新渲染。
该方法等同于浏览器原生的DocumentFragment构造函数
var docFrag = new DocumentFragment();
注意,DocumentFragment节点自己不能被插入当前文档,而是其全部子结点插入当前文档中。插入完成后,该DocumentFragment对象变为空结点(textContent属性为空串),能够被再次使用。
若想保留其子结点,能够经过cloneNode()方法
node.appendChild(docFrag.cloneNode(true));
document.createNodeIterator()
该方法返回一个子节点遍历器对象(NodeFilter实例)
var nodeIterator = document.createNodeIterator( document.body, //要遍历的根节点 NodeFilter.SHOW_ELEMENT //要遍历的节点类型 );
注:遍历器返回的第一个节点,老是根节点。
var currentNode = nodeIterator.nextNode(); var previousNode = nodeIterator.previousNode(); currentNode === previousNode //true
document.createTreeWalker()
该方法返回一个DOM的子树遍历器对象(TreeWalker实例)
注:遍历器返回的第一个节点,不是根节点。
var treeWalker = document.createTreeWalker( document.body, //要遍历的根节点 NodeFilter.SHOW_ELEMENT //要遍历的节点类型 );
相同条件下,treeWalker 比 nodeIterator 少一个根节点。
属性
innerHTML VS textContent VS innerText
innerHTML
属性会转义为实体形式 &、<、> 。若想获得原文,建议使用element.textContent
属性。textContent
属性;方法
Element.insertAdjacentHTML()
将一个HTML字符串,解析生成DOM结构(转义字符),插入相对于当前节点的指定位置。
Element.closest()
接受一个CSS选择器做为参数,返回匹配该选择器的、最接近当前节点的一个祖先节点(包括当前节点自己)。
若是没有任何节点匹配 CSS 选择器,则返回null。
Element.getBoundingClientRect()
返回一个rect对象,提供当前元素节点的大小、位置等信息(CSS盒状模型的全部信息)
x:元素左上角相对于视口的横坐标 y:元素左上角相对于视口的纵坐标 /// 元素自己 + padding + border height:元素高度 width:元素宽度 /// 随着页面滚动变化而变更 left:元素左上角相对于视口的横坐标,与x属性相等 right:元素右边界相对于视口的横坐标(等于x + width) top:元素顶部相对于视口的纵坐标,与y属性相等 bottom:元素底部相对于视口的纵坐标(等于y + height)
若要获得绝对值,能够将left
属性加上window.scrollX
,top
属性加上window.scrollY
rect
对象没有自身属性,所有继承于原型属性,因此:Object.keys(rect) // []
另外,Element.getClientRects 方法返回类数组对象,与Element.getBoundingClientRect()相比,该方法:
此外,对于页面元素的焦点问题,考虑如下属性和方法
Element.focus() Element.blur() document.activeElement /// 让xxx元素得到焦点,并滚动到可见区域 function getFocus() { document.getElementById('xxx').focus({preventScroll:false}); }
事件驱动编程模式(event-driven),经过监听函数对事件作出反应。 全部DOM的事件操做(监听和触发),都定义在EventTarget接口
若向监听函数传递参数,可用匿名函数包装监听函数
btn.addEventListener('click', function () { alert(this.nodeName); //监听函数内部的this,指向当前事件所在的那个对象 fun('Hello'); }, false);
其中,false标志冒泡阶段,true标志捕获阶段,默认false。
事件绑定
JS提供三种为事件绑定监听函数的方法:
el.setAttribute('onclick', 'doSomething()'); // 等同于 <Element onclick="doSomething()">
违反了HTML与JavaScript代码相分离的原则。
div.onclick = function (event) { console.log('触发事件'); };
缺点是同一个事件只能定义一个监听函数。
推荐使用
window
、XMLHttpRequest
等)也有这个接口,它等因而整个JavaScript统一的监听函数接口事件传播
propagation,事件传播的最上层对象是window,接着依次是document,html(document.documentElement)和body(document.body)
注意,浏览器老是假定click事件的目标节点,是点击位置嵌套最深的那个节点。
对事件传播的详细讲解过程,参见:JS教程 - 事件模型 的propagation部分。
事件代理
delegation,把监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件。
能够经过事件对象的stopPropagation方法阻止事件的传播
// 事件传播到 node 元素后,就再也不向下传播了 node.addEventListener('click', function (event) { event.stopPropagation(); }, true); ///捕获阶段 // 事件冒泡到 node 元素后,就再也不向上冒泡了 node.addEventListener('click', function (event) { event.stopPropagation(); }, false); ///冒泡阶段
若同时阻止node节点的其余click事件的监听函数,完全阻止这个事件的传播,请移步:stopImmediatePropagation方法。
事件对象
浏览器原生提供一个Event对象,全部的事件都是该对象的实例,或者说继承了Event.prototype对象。
var event = new Event( 'look', { 'bubbles': true, 'cancelable': false });
其中,只读属性bubble的true标志冒泡阶段,false标志捕获阶段,默认false。
由Event构造函数生成的事件,Event.isTrusted属性返回false,标志是脚本产生的,而非真正的用户行为产生的。
除Event外,浏览器原生提供CustomEvent()构造函数,用来生成自定义的事件实例。
Event.eventPhase
返回一个整数常量,表示事件目前所处的阶段,只读属性
Event.target
属性指向的那个节点Event.cancelable
返回一个布尔值,表示事件是否能够取消,只读属性,默认false
推荐用法:调用Event.preventDefault()以前,先预判
function preventEvent(event) { if (event.cancelable) { event.preventDefault(); } else { console.warn('This event can not be canceled.'); } }
Event.target VS Event.currentTarget
事件传播过程当中,不一样节点的监听函数内部的Event.target与Event.currentTarget属性的值是不同的,前者老是不变的,后者则是指向监听函数所在的那个节点对象。
Event.preventDefault()
取消浏览器对当前事件的默认行为,前提是事件对象的cancelable属性为true。
该方法只是取消事件对当前元素的默认影响,不会阻止事件的传播。
Event.composedPath()
返回一个数组,成员是事件的最底层节点和依次冒泡通过的全部上层节点。
在父节点内部进入子节点,不会触发mouseenter事件,可是会触发mouseover事件;
在父节点内部离开子节点,不会触发mouseleave事件,可是会触发mouseout事件;
relatedTarget:节点对象,表示事件的相关节点,默认为null。
mouseenter和mouseover事件时,表示鼠标刚刚离开的那个元素节点;
mouseout和mouseleave事件时,表示鼠标正在进入的那个元素节点;
拓展注意,不一样事件的target属性和relatedTarget属性的不一样:
事件名称 target 属性 relatedTarget 属性 focusin 接受焦点的节点 丧失焦点的节点 focusout 丧失焦点的节点 接受焦点的节点 mouseenter 将要进入的节点 将要离开的节点 mouseleave 将要离开的节点 将要进入的节点 mouseout 将要离开的节点 将要进入的节点 mouseover 将要进入的节点 将要离开的节点 dragenter 将要进入的节点 将要离开的节点 dragexit 将要离开的节点 将要进入的节点
浏览器原生提供WheelEvent()构造函数,用来生成WheelEvent实例。
var wheelEvent = new WheelEvent('wheel', options);
浏览器原生提供KeyboardEvent构造函数,用来新建键盘事件的实例。
属性key表示当前按下的键,默认为空字符串。
注意,若是一直按键不松开,会一直触发事件,直至松开
keydown --> keypress --> keydown --> keypress --> …(重复以上过程) --> keyup
经过KeyboardEvent.repeat属性返回一个布尔值,表明该键是否被按着不放,以便判断是否重复这个键。
描述资源加载/文件上传的进度,主要由 AJAX请求、<img>、<audio>、<video>、<style>、<link> 等外部资源的加载触发。
abort:外部资源停止加载时(好比用户取消)触发。若是发生错误致使停止,不会触发该事件。 error:因为错误致使外部资源没法加载时触发。 load:外部资源加载成功时触发。 loadstart:外部资源开始加载时触发。 loadend:外部资源中止加载时触发,发生顺序排在error、abort、load等事件的后面。 progress:外部资源加载过程当中不断触发。 timeout:加载超时时触发。
推荐方法,避免出现图片在脚本未执行完就加载完毕、监听函数不会执行的状况
function loaded() { // ... } if (image.complete) { loaded(); } else { image.addEventListener('load', loaded); }
注意,因为DOM元素节点没有提供是否加载错误的属性,因此error事件的监听函数最好放在<img>
元素的HTML代码中,这样才能保证发生加载错误时百分之百会执行错误提示。并且,error事件不会冒泡,子元素的error事件,不会触发父元素的error事件监听函数。
浏览器原生提供一个DragEvent()构造函数,用来生成拖拉事件的实例对象。
关于拖拉事件,有如下几个注意点
dragstart
和dragend
事件。dragenter
和dragover
事件的监听函数,用来取出拖拉的数据(即容许放下被拖拉的元素)。因为网页的大部分区域不适合做为放下拖拉元素的目标节点,因此这两个事件的默认设置为当前节点不容许接受被拖拉的元素。若是想要在目标节点上放下的数据,首先必须阻止这两个事件的默认行为。经过以下例子:将一个节点从当前父节点,拖拉到另外一个父节点中,理解拖拉事件
/* HTML 代码以下 <div class="dropzone"> <div id="draggable" draggable="true"> 该节点可拖拉 </div> </div> <div class="dropzone"></div> <div class="dropzone"></div> <div class="dropzone"></div> */ // 被拖拉节点 var dragged; document.addEventListener('dragstart', function (event) { // 保存被拖拉节点 dragged = event.target; // 被拖拉节点的背景色变透明 event.target.style.opacity = 0.5; }, false); document.addEventListener('dragend', function (event) { // 被拖拉节点的背景色恢复正常 event.target.style.opacity = ''; }, false); document.addEventListener('dragover', function (event) { // 阻止事件的默认行为,防止拖拉效果被重置,容许被拖拉的节点放入目标节点 event.preventDefault(); }, false); document.addEventListener('dragenter', function (event) { // 目标节点的背景色变紫色 // 因为该事件会冒泡,因此要过滤节点 if (event.target.className === 'dropzone') { event.target.style.background = 'purple'; } }, false); document.addEventListener('dragleave', function( event ) { // 目标节点的背景色恢复原样 if (event.target.className === 'dropzone') { event.target.style.background = ''; } }, false); document.addEventListener('drop', function( event ) { // 防止事件默认行为(好比某些元素节点上能够打开连接), event.preventDefault(); if (event.target.className === 'dropzone') { // 恢复目标节点背景色 event.target.style.background = ''; // 将被拖拉节点插入目标节点 dragged.parentNode.removeChild(dragged); event.target.appendChild( dragged ); } }, false);
注意,drag、dragstart、dragend是针对被拖拉对象,dragenter、dragover、dragleave、drop是针对目标结点对象。
DataTransfer
全部拖拉事件的实例都有一个DragEvent.dataTransfer属性,用来读写须要拖拉传递的数据。该属性的值是一个DataTransfer接口的实例。
浏览器原生提供一个DataTransfer()构造函数,无参
var dataTrans = new DataTransfer();
拖拉事件开始时,开发者能够提供数据类型和数据值。拖拉过程当中,开发者经过dragenter和dragover事件的监听函数,检查数据类型以肯定是否容许放下(drop)被拖拉的对象。发生drop事件时,监听函数取出拖拉的数据便可。
属性
dropEffect VS effectAllowed
该2个属性是同一件事的两个方面,一般配合使用
source.addEventListener('dragstart', function (e) { e.dataTransfer.effectAllowed = 'move'; }); target.addEventListener('dragover', function (e) { ev.dataTransfer.dropEffect = 'move'; });
types VS items
该2个属性一般在drop事件的监听函数中获取。
注:若想为拖拉事件添加数据,只能在dragstart中设置;若想从拖拉事件中获取数据,只能在drop事件监听函数中。
TouchEvent接口继承Event接口,表示由触摸引起的事件实例
touches
:TouchList
实例,表明全部的当前处于活跃状态(触摸中)的触摸点,默认值是一个空数组[]
。targetTouches
:TouchList
实例,表明全部处在触摸的目标元素节点内部、且仍然处于活动状态的触摸点,默认值是一个空数组[]
。changedTouches
:TouchList
实例,表明本次触摸事件的相关触摸点,默认值是一个空数组[]
。若 ev.touches.length === ev.targetTouches.length,代表全部触摸点均在目标元素结点内。
注:若想在发生触摸事件的同时阻止鼠标事件,使用:event.preventDefault方法。
// input事件(连续触发) 当<input>、<select>、<textarea>的值发生变化, 单复选框改变选项, 打开contenteditable属性的元素结点的值发生变化时触发 // select事件 在<input>、<textarea>里面选中文本时触发 // Change事件(不会连续触发) 当<input>、<select>、<textarea>的值发生变化且只有当所有修改完成时才会触发 [1]. 激活单选框(radio)或复选框(checkbox)时触发。 [2]. 用户提交时触发。好比,从下列列表(select)完成选择,在日期或文件输入框完成选择。 [3]. 当文本框或<textarea>元素的值发生改变,而且丧失焦点时触发。 // invalid 事件 用户提交表单时,若是表单元素的值不知足校验条件时触发 // reset 事件,submit 事件:发生在表单对象<form>上,而不是发生在表单的成员上 reset事件当表单重置(全部表单成员变回默认值)时触发。 submit事件当表单数据向服务器提交时触发。
a. 资源事件
document
对象将要卸载时触发。它的触发顺序排在beforeunload
、pagehide
事件后面。事件发生时,全部资源依然存在,可是对用户来讲都不可见,UI互动所有无效。缓存存在,则事件无效。推荐:兼容性好
window.addEventListener('beforeunload', function(e) { var confirmationMessage = '确认关闭窗口?'; e.returnValue = confirmationMessage; return confirmationMessage; });
b. 焦点事件
在元素节点和document对象上面触发,与得到/失去焦点相关。
focus
:元素节点得到焦点后触发,该事件不会冒泡blur
:元素节点失去焦点后触发,该事件不会冒泡focusin
:元素节点将要得到焦点时触发,发生在focus
事件以前,该事件会冒泡focusout
:元素节点将要失去焦点时触发,发生在blur
事件以前,该事件会冒泡focusin --> focus --> focusout --> blur
这四个事件都继承FocusEvent接口,提供属性:
FocusEvent.target
:事件的目标节点FocusEvent.relatedTarget
:对于focusin
事件,返回失去焦点的节点;对于focusout
事件,返回将要接受焦点的节点;对于focus
和blur
事件,返回null
。对于focus和blur事件,一般将addEventListener
方法的第三个参数须要设为true,由于只能在捕获阶段触发。
form.addEventListener('focus', function (event) { event.target.style.background = 'pink'; }, true); form.addEventListener('blur', function (event) { event.target.style.background = ''; }, true);
c. session历史事件
默认状况下,浏览器会在当前会话(session)缓存页面,当用户点击“前进/后退”按钮时,浏览器就会从缓存中加载页面。
d. 网页状态事件
网页下载并解析完成之后,浏览器就会在document对象上触发,远早于load事件。
注:网页的JavaScript脚本是同步执行的,脚本一旦发生堵塞,将推迟触发DOMContentLoaded事件。
当Document对象和XMLHttpRequest对象的readyState属性发生变化时触发。readyState有3种状态:
e. 窗口事件
主要是scroll事件:在文档或文档元素滚动时触发(用户拖动滚动条)。
目前lodash函数库提供了现成的throttle函数,能够直接使用:将一个函数的调用频率限制在必定阈值内
window.addEventListener('scroll', _.throttle(callback, 1000));
关于函数节流(throttle)和函数去抖(debounce)的问题,具体参见:函数节流与函数去抖 - sqh;
f. 剪贴板事件
cut
:将选中的内容从文档中移除,加入剪贴板时触发copy
:进行复制动做时触发paste
:剪贴板内容粘贴到文档后触发这三个事件都是ClipboardEvent接口的实例。ClipboardEvent的实例属性clipboardData是一个DataTransfer对象,存放剪贴的数据。
关于事件类型的详细信息,参见:JS教程 - 事件种类;
(1)自定义渲染方法
即自定义jQuery插件,涉及:
具体地,编写一个jQuery插件的原则:
$.fn
绑定函数,实现插件的代码逻辑return this;
以支持链式调用$.fn.<pluginName>.defaults
上$.fn.方法名 = function (options) { // 合并默认值和用户设定值: var opts = $.extend({}, $.fn.方法名.defaults, options); // 样式渲染 this.css('backgroundColor', opts.backgroundColor) .css('color', opts.color); // 返回this,支持链式调用 return this; } // 设定默认值: $.fn.方法名.defaults = { color: '#d85030', backgroundColor: '#fff8de' }
支持用户自定义默认值
$.fn.方法名.defaults.color = '#fff'; $.fn.方法名.defaults.backgroundColor = '#000';
也能够传参覆盖默认值。
(2)underscore库
完善的函数式编程接口,如同jQuery会绑定到$上,underscore会绑定到_上。
安装:npm install underscore
具体参见:underscore.js;