文章目录
DOM-Web API
DOM节点操作
节点属性
var box = document.getElementById("box");
// 元素节点
console.dir(box);
//nodeName: "DIV", nodeType: 1, nodeValue: null
// 属性节点获取
var idnode = box.getAttributeNode("id");
console.dir(idnode);
//nodeName: "id", nodeType: 2, nodeValue: "box"
idnode.nodeValue = "demo";
// 文本节点
var childnodes = box.childNodes;
console.log(childnodes);
//nodeName: "#text", nodeType: 3, nodeValue: "div 1"
childnodes[0].nodeValue = "child 1"; //得到的下标是0
- nodeType节点的类型
- 属性值是数字,表示不同的节点类型共12种,只读
- 1元素节点 2属性节点 3文本节点
- nodeName节点的名称(只读)
- nodeValue节点值
- 返回或设置当前节点的值,元素节点的value始终是null
父子节点
-
childNodes
只读属性,获取一个节点所有子节点的实时集合,动态变化
-
childeren
只读,返回一个节点所有的子元素节点结合,动态更新
-
firstChild
只读,返回该节点的第一个子节点,没有则返回null
-
lastChild
只读,返回该节点的最后一个子节点,没有返回null
-
parentNode
返回一个当前节点的父节点
-
parentElement
返回一个当前节点的父元素节点
var box = document.getElementById("box");
console.log(box.childNodes); //NodeList(5) [text, p, text, span, text]获取所有类型的子节点,其中text中保存的是换行
console.log(box.children); //HTMLCollection(2) [p, span]获取所有元素类型的子节点
console.log(box.firstChild); //#text所有类型的第一个
console.log(box.lastElementChild); //<span>span小盒子</span>所有元素类型的最后一个
console.log(box.parentNode); //<body>……</body>
console.log(box.parentElement); //<body>……</body>
兄弟节点
-
nextSibling
只读,返回与该节点同级的下一个节点,无则返null
-
previousSibling
只读,返回与该节点同级的上一个节点,无则返null
-
nextElementSibling
返回的是下/上一个元素节点(IE9以后才兼容)
-
previousElementSibling
var p3 = my$("p3");
console.log(p3.nextSibling); //#text
console.log(p3.nextElementSibling); // <p>这是段落4</p>
console.log(p3.previousSibling); //#text
console.log(p3.previousElementSibling); // <p>这是段落2</p>
节点操作
-
创建节点
-
document.createElement(“div”)创建元素节点
-
document.createAttribute(“id”)创建属性节点
-
document.createTextNode(“hello”)创建文本节点
-
一般将创建的新节点保存在变量中方便使用,创建的新的节点,是存储在内存中的,并没有添加到DOM树上
//创建一个元素节点 var div = document.createElement("div"); console.dir(div); //nodeValue=1 var id = document.createAttribute("class"); console.dir(id); //nodeValue=2 var txt = document.createTextNode("hello"); console.dir(txt); //nodeValue=3
-
-
添加节点
-
parentNode.appendChild(child);将一个节点添加到指定父节点的子节点列表末尾
var p3 = my$("p3"); box.appendChild(div); //文本节点也可以添加到元素内部 div.appendChild(txt); //自己创建的元素节点本身就是一个对象, 可以去添加一些新的属性和方法,这些操作将来在元素加载到DOM树中时,依旧保留 box.appendChild(p3); //DOM中将原有节点也可以使用appendChild属性,执行的操作是剪贴,从原本位置删除,添加到最后,是因为在内存中这个原有节点只有一个,渲染时只能有一个位置
-
-
替换、插入、删除节点
-
parentNode.replaceChild(newchild,oldchild);用指定的节点替换当前节点的一个子节点,并返回被替换掉的节点
// 替换节点 box.replaceChild(div, p3);
-
parentNode.insertBefore(newNode,referenceNode);在参考节点之前插入一个拥有指定父节点的子节点
// 固定插入节点 box.insertBefore(div, p3);
-
parentNode.removeChild(child);移除当前节点的一个子节点,这个子节点必须存在于当前节点中
// 移除节点 box.removeChild(p3);
-
-
克隆节点
-
Node.cloneNode()克隆一个节点,并且可以选择是否克隆这个节点下的所有内容,参数是布尔值,表示是是否采用深度克隆
-
true则该节点的所有后代节点都会被克隆,false则只克隆该节点本身
-
克隆时,标签上的属性和属性值也会被复制,写在标签行内的绑定事件可以被复制,但是通过JS动态绑定的事件不会被复制
// 克隆元素 var newbox = box.cloneNode(false); //浅克隆就只有这个节点 var newbox = box.cloneNode(true); //深克隆包括所有的内容 document.body.appendChild(newbox); //添加到body的末尾
-
-
节点的判断方法
-
Node.hasChildNodes():没有参数,返回一个Boolean布尔值,来表示该元素是否包含有子节点
-
Node.contains(child);返回一个Boolean布尔值,来表示传入的节点是否为该节点的后代节点
// 判断是否有子节点 console.log(box.hasChildNodes()); //true console.log(demo.hasChildNodes()); //false // 判断P3是否是box的子节点 console.log(box.contains(p3)); //true
-
判断是否有子节点方法总结
-
node.firstChild!==null
-
node.childNodes.length>0
-
node.hasChildNodes()
-
如果是元素节点是否存在则使用box.children.length
-
-
案例分析
-
动态创建列表
-
三部曲,创建,添加,增内容
-
如果有多条属性,那么就通过数组长度进行添加
// 创建每一个ul里面的li数据 for (var i = 0; i < names.length; i++) { var li = document.createElement("li"); // 将li添加到ul中去 ul.appendChild(li); // 并且要给每一个li标签给值 li.innerHTML = names[i]; }
-
-
动态创建表格
-
当有多个值,我们就可以使用对象,通过属性和属性值进行内容的增加
-
a标签通过元素节点添加后,需要我们自己设定一些属性,a.href=”JavaScript:void(0)“就可以实现点击不跳转
-
点击删除,就需要我们对其添加点击事件,点击即删除
for (var k in data) { // 创建一个td var td = document.createElement("td"); // 将创建的td增加到tr中去 tr.appendChild(td); // 需要给td里面塞入内容 td.innerHTML = data[k]; } // 除了前面动态获取的td外还要增加一个删除的td td = document.createElement("td"); // 添加到tr中去 tr.appendChild(td); // 最后一个td中的内容是a标签,老步骤,创建添加增内容 var a = document.createElement("a"); td.appendChild(a); a.innerHTML = "删除"; // 增加href属性,要让它不进行跳转则返回0 a.href = "javascript:void(0);" // 给每个a生成添加一个点击事件,一处所在的行 a.onclick = function() { // 通过a的父级找到td,再通过td的父级找到tr tb.removeChild(this.parentNode.parentNode); }
-
-
选择水果
-
children中的元素都是动态添加的,所有存在length值会不断的发生变化,所以我们应该给一个初始值
-
通过观察可以发现,每次移动的值下标都是index=0,所以我们就可以直接让每次移动的数都是0
var n = opts.length; for (var i = 0; i < n; i++) { // 由于children获取到的opts都是动态变化的 // 所以我们每次都从index=0去取 all.appendChild(opts[0]); }
-
DOM事件操作
addEventListener
-
二级事件的添加,调用的是方法
-
element.addEventListener()方法,第一个参数是事件函数的字符串(直接书写"click",不需要加on),第二个参数是事件函数
-
同一个元素可以多次绑定世家监听,同一个事件类型可以注册多个事件函数
-
不支持IE9以下的浏览器
var btn = document.getElementById("btn"); // 使用DOM二级的方法添加多个事件 btn.addEventListener("click", function() { alert(1); }); btn.addEventListener("click", function() { alert(2); });
attachEvent
-
是一种方法,传入的第一个参数是事件类型的字符串(需要加on),第二个参数是事件函数
-
只支持IE10及以下的浏览器,IE8以下可能会出现事件混乱的现象
btn.attachEvent("onclick", function() { alert(1); });
注册事件兼容写法
-
自定义一个注册事件函数
-
参数:事件源、事件类型(不加on)、事件函数
-
浏览器能力检测,将某个方法的调用作为if语句的判断条件,如果浏览器认识该方法返回true,否则返回false
-
IE9以上浏览器使用addEventListener方法,IE9以下浏览器使用attachEvent方法
var btn = document.getElementById("btn"); // 调用函数 addEvent(btn, "click", function() { alert(330); }) // 自己制作一个兼容的绑定事件函数,参数(事件源,事件类型,事件函数) function addEvent(ele, type, fn) { // IE9以上浏览器使用addEventListener方法 //IE9以下浏览器使用attachEvent方法 if (ele.addEventListener) { ele.addEventListener(type, fn); } else if (ele.attachEvent) { ele.attachEvent("on" + type, fn); } }
解除事件
-
0级事件解除,直接赋null值
// DOM 0级事件解除绑定 btn.onclick = null;
-
element.removeEventListener()方法
- 第一个参数是事件类型字符串,第二个参数是事件函数引用名,没办法移除一个匿名函数,在注册事件的时候需要单独声明一个有函数名的事件函数
- 同样兼容性问题,不支持IE9以下浏览器
// 解除二级事件绑定 btn.removeEventListener("click", fun1);
-
element.detachEvent()方法
- 第一个参数是事件类型的字符串(需要添加on),第二个参数是事件函数
- 同样不能移除匿名函数,需要注册事件时单独声明一个有函数名的事件函数
- 只支持IE10及以下的浏览器
btn.detachEvent("onclick", fun1);
-
移除事件的兼容写法
- 方法和添加事件的兼容性写法一致
// 解除事件 removeEvent(btn, "click", fun2); // 自己制作一个兼容的绑定事件函数,参数(事件源,事件类型,事件函数) function removeEvent(ele, type, fn) { // IE9以上浏览器使用addEventListener方法 //IE9以下浏览器使用attachEvent方法 if (ele.removeEventListener) { ele.removeEventListener(type, fn); } else if (ele.detachEvent) { ele.detachEvent("on" + type, fn); } }
DOM事件流
事件流三阶段
事件捕获、事件执行、事件冒泡
- 冒泡是从最小的元素节点开始向上父级祖先级显示
- 捕获是从祖先级元素开始向下一直到最小元素节点
- 当捕获和冒泡同时存在时,先执行捕获,然后再执行冒泡,捕获到最小元素时,根据JS中书写的先后顺序来决定自身是先执行捕获还是先执行冒泡
- 绑定事件最后还有一个参数(true or false),用来决定是捕获还是冒泡,只对addEventListener()有效
冒泡应用
事件委托
-
利用事件冒泡,将子级的公共事件委托给父级添加,在父级内部想办法找到真正触发事件的最底层的事件源
-
借用事件函数内部的一个参数e,e是事件对象,只要触发事件,函数内部都可以得到一个事件对象,对象中存储了关于事件的一系列数据
-
e.target属性记录的即时真正触发事件的事件源
var list = document.getElementById("list"); var lis = list.children; // 给 ul 添加点击事件 list.onclick = function (e) { // e.target 属性记录的就是真正触发事件的事件源 // 排除其他 for (var i = 0 ; i < lis.length ; i++) { lis[i].style.backgroundColor = ""; } //单独设置自己的样式 e.target.style.backgroundColor = "pink"; };
事件对象
-
只要触发事件,就会有一个对象,内部存储了与事件相关的数据
-
e在低版本浏览器中会有兼容问题,低版本浏览器使用的是window.event
-
事件对象常用的属性
-
e.eventPhase查看事件触发时所处的阶段
-
e.target用于获取触发事件的元素
-
e.srcElement获取触发事件的元素
-
e.currentTarget获取绑定事件的事件源元素
-
e.type获取事件的类型
-
e.clientX/e.clientY所有浏览器都支持,鼠标距离浏览器左上角的距离
-
e.pageX/e.pageY ie8不支持,鼠标距离整个HTML页面左上顶点的距离
box1.onclick = function(e) { // e指的是存储事件对象的参数,只要事件被触发,e就会自动接收数据 // 兼容问题 e = e || window.event; // 事件触发时所处的阶段 1:表示捕获 2:目标阶段 3:冒泡阶段 console.log(e.eventPhase); //2 var target = e.target || e.srcElement; console.log(target); //获取真正触发点击的事件 console.log(e.currentTarget); //box1返回的永远是绑定事件源的元素,和this中存储的内容是一样的 console.log(e.type); //click返回获取事件的类型,更多时候可能时给同一个元素对象添加不同的事件类型,对应执行的事件函数内部的代码不同。可以将所有给一个元素绑定的事件的事件函数写在一个函数内,通过函数内部的e.type判断走不同的分支,这样可以避免添加多个函数,占用更多的内存 console.log(e.clientX); //得到的是距离浏览器左上角来参考 console.log(e.pageX); //得到的是距离我们HTML页面的距离,下拉滚动后的获取值仍旧保持不变 }
-
-
取消默认行为的方法
- e.preventDefault()取消默认行为
- e.returnValue取消默认行为,低版本浏览器使用
-
阻止事件传播的方法
- e.stopPropagation()阻止冒泡,标准方式
- e.cancelBubble=true阻止冒泡,IE低版本
offset系列属性
-
offsetParent偏移参考父级,距离自己最近的有定位的父级,如果都没有定位则参考body(html)
-
offsetLeft/offsetTop偏移位置
-
offsetWidth/offsetHeight偏移大小,元素自身border以内的宽度(border+paddin g)
client系列属性
-
客户端大小,只关注自己
-
clientLeft、clientTop、clientWidth、clientHeight
-
一般如果我们不希望有边框的存在,那么就使用client
scroll系列属性
-
关注的是自己,不关心外部的尺寸
-
scrollLeft/scrollTop盒子内部滚动出去的尺寸
-
scrollWidth/scrollHeight盒子内容的宽度和高度
拖拽案例
// 给drop添加一个鼠标按下事件,在内部继续绑定一个鼠标移动事件
drop.onmousedown = function(e) {
// 兼容问题
e = e || window.event;
// 在鼠标按下之后需要记住鼠标距离元素的上部和左部的位置
var l = e.pageX - box.offsetLeft;
var t = e.pageY - box.offsetTop;
// 增加鼠标移动事件
drop.onmousemove = function(e) {
e = e || window.event;
// 在鼠标移动过程中,将鼠标位置-鼠标距离本身的位置=距离HTML偏移的位置
var newleft = e.pageX - l;
var newtop = e.pageY - t;
// 将我们计算后的值赋给样式
box.style.left = newleft + "px";
box.style.top = newtop + "px";
}
}
弹出层案例
- 实际上就使用一个div半透明盒子盖住其他元素,再增加弹出的内容的权重,就可以实现其他内容点击无效
- 绑定事件,对display样式属性值进行修改,block则展现,none则隐藏