学习目标:
能够使用removeChild()方法删除节点
能够完成动态生成表格案例
能够使用传统方式和监听方式给元素注册事件
能够说出事件流执行的三个阶段
能够在事件处理函数中获取事件对象
能够使用事件对象取消默认行为
能够使用事件对象阻止事件冒泡
能够使用事件对象获取鼠标的位置
能够完成跟随鼠标的天使案例
1.1. 节点操作
1.1.1 删除节点
node.removeChild() 方法从 node节点中删除一个子节点,返回删除的节点。
<button>删除</button> <ul> <li>熊大</li> <li>熊二</li> <li>光头强</li> </ul> <script> // 1.获取元素 var ul = document.querySelector('ul'); var btn = document.querySelector('button'); // 2. 删除元素 node.removeChild(child) // ul.removeChild(ul.children[0]); // 3. 点击按钮依次删除里面的孩子 btn.onclick = function() { if (ul.children.length == 0) { this.disabled = true; } else { ul.removeChild(ul.children[0]); } } </script>
1.1.2 案例:删除留言
阻止a标签链接跳转可以用 javascript:void(0);或者 javascript:;
<textarea name="" id=""></textarea> <button>发布</button> <ul> </ul> <script> // 1. 获取元素 var btn = document.querySelector('button'); var text = document.querySelector('textarea'); var ul = document.querySelector('ul'); // 2. 注册事件 btn.onclick = function() { if (text.value == '') { alert('您没有输入内容'); return false; } else { // console.log(text.value); // (1) 创建元素 var li = document.createElement('li'); // 先有li 才能赋值 li.innerHTML = text.value + "<a href='javascript:;'>删除</a>"; // (2) 添加元素 // ul.appendChild(li); ul.insertBefore(li, ul.children[0]); // (3) 删除元素 删除的是当前链接的li 它的父亲 var as = document.querySelectorAll('a'); for (var i = 0; i < as.length; i++) { as[i].onclick = function() { // 删除的是 li 当前a所在的li this.parentNode; ul.removeChild(this.parentNode); } } } } </script>
1.1.3 复制(克隆)节点
<ul> <li>1111</li> <li>2</li> <li>3</li> </ul> <script> var ul = document.querySelector('ul'); // 1. node.cloneNode(); 括号为空或者里面是false 浅拷贝 只复制标签不复制里面的内容 // 2. node.cloneNode(true); 括号为true 深拷贝 复制标签复制里面的内容 var lili = ul.children[0].cloneNode(true); ul.appendChild(lili); </script>
1.1.4 案例:动态生成表格
<script> // 1.先去准备好学生的数据 var datas = [{ name: '魏璎珞', subject: 'JavaScript', score: 100 }, { name: '弘历', subject: 'JavaScript', score: 98 }, { name: '傅恒', subject: 'JavaScript', score: 99 }, { name: '明玉', subject: 'JavaScript', score: 88 }, { name: '大猪蹄子', subject: 'JavaScript', score: 0 }]; // 2. 往tbody 里面创建行: 有几个人(通过数组的长度)我们就创建几行 var tbody = document.querySelector('tbody'); // 遍历数组 for (var i = 0; i < datas.length; i++) { // 1. 创建 tr行 var tr = document.createElement('tr'); tbody.appendChild(tr); // 2. 行里面创建单元格td 单元格的数量取决于每个对象里面的属性个数 // 使用for in遍历学生对象 for (var k in datas[i]) { // 创建单元格 var td = document.createElement('td'); // 把对象里面的属性值 datas[i][k] 给 td td.innerHTML = datas[i][k]; tr.appendChild(td); } // 3. 创建有删除2个字的单元格 var td = document.createElement('td'); td.innerHTML = '<a href="javascript:;">删除 </a>'; tr.appendChild(td); } // 4. 删除操作 开始 var as = document.querySelectorAll('a'); for (var i = 0; i < as.length; i++) { as[i].onclick = function() { // 点击a 删除 当前a 所在的行(链接的爸爸的爸爸) node.removeChild(child) tbody.removeChild(this.parentNode.parentNode) } } </script>
1.1.5 创建元素的三种方式
三种动态创建元素区别 1.document.write() 2.element.innerHTML 3.document.createElement() // 区别 // 1. document.write 是直接将内容写入页面的内容流,但是文档流执行完毕,则它会导致页面全部重绘 // 2. innerHTML 是将内容写入某个 DOM 节点,不会导致页面全部重绘 // 3. innerHTML 创建多个元素效率更高(不要拼接字符串,采取数组形式拼接),结构稍微复杂 // 4. createElement() 创建多个元素效率稍低一点点,但是结构更清晰 // 总结:不同浏览器下,innerHTML(采用数组形式) 效率要比 creatElement 高
例子
<script> // 三种创建元素方式区别 // 1. document.write() 创建元素 如果页面文档流加载完毕,再调用这句话会导致页面重绘 var btn = document.querySelector('button'); btn.onclick = function() { document.write('<div>123</div>'); } // 2. innerHTML 创建元素 var inner = document.querySelector('.inner'); for (var i = 0; i <= 100; i++) { inner.innerHTML += '<a href="#">百度</a>' } var arr = []; for (var i = 0; i <= 100; i++) { arr.push('<a href="#">百度</a>'); } inner.innerHTML = arr.join(''); // 3. document.createElement() 创建元素 var create = document.querySelector('.create'); for (var i = 0; i <= 100; i++) { var a = document.createElement('a'); create.appendChild(a); } </script>
1.1.6 innerTHML和createElement效率对比
innerHTML字符串拼接方式(效率低)
<script> function fn() { var d1 = +new Date(); var str = ''; for (var i = 0; i < 1000; i++) { document.body.innerHTML += '<div style="width:100px; height:2px; border:1px solid blue;"></div>'; } var d2 = +new Date(); console.log(d2 - d1); } fn(); </script>
createElement方式(效率一般)
<script> function fn() { var d1 = +new Date(); for (var i = 0; i < 1000; i++) { var div = document.createElement('div'); div.style.width = '100px'; div.style.height = '2px'; div.style.border = '1px solid red'; document.body.appendChild(div); } var d2 = +new Date(); console.log(d2 - d1); } fn(); </script>
innerHTML数组方式(效率高)
<script> function fn() { var d1 = +new Date(); var array = []; for (var i = 0; i < 1000; i++) { array.push('<div style="width:100px; height:2px; border:1px solid blue;"></div>'); } document.body.innerHTML = array.join(''); var d2 = +new Date(); console.log(d2 - d1); } fn(); </script>
1.2. DOM的核心总结
关于dom操作,我们主要针对于元素的操作。主要有创建、增、删、改、查、属性操作、事件操作。
1.2.1. 创建
// 1.document.write // 是直接将内容写入页面的内容流,但是文档流执行完毕,则它会导致页面全部重绘 // 2.innerHTML // 是将内容写入某个 DOM 节点,不会导致页面全部重绘 // 3.createElement // 创建多个元素效率稍低一点点,但是结构更清晰
1.2.2. 增加
// 1.appendChild // 将一个节点添加到指定父节点的子节点列表末尾 // 2.insertBefore // 将一个节点添加到父节点的指定子节点前面
1.2.3. 删
// 1.removeChild //删除节点
1.2.4. 改
// 主要修改dom的元素属性,dom元素的内容、属性, 表单的值等 // 修改元素属性: src、href、title等 // 修改普通元素内容: innerHTML 、innerText // 修改表单元素: value、type、disabled等 // 修改元素样式: style、className
1.2.5. 查
// 主要获取查询dom的元素 // 1.DOM提供的API 方法: getElementById、getElementsByTagName 古老用法 不太推荐 // 2.H5提供的新方法: querySelector、querySelectorAll 提倡 // 利用节点操作获取元素: 父(parentNode)、子(children)、兄(previousElementSibling、nextElementSibling) 提倡
1.2.6. 属性操作
// 主要针对于自定义属性 // 1. setAttribute:设置dom的属性值 // 2. getAttribute:得到dom的属性值 // 3. removeAttribute移除属性
1.2.7. 事件操作(重点)
// 给元素注册事件, 采取 事件源.事件类型 = 事件处理程序
1.3. 事件高级
1.3.1. 注册事件(2种方式)
1.3.2 事件监听
addEventListener()事件监听(IE9以后支持)
eventTarget.addEventListener()方法将指定的监听器注册到 eventTarget(目标对象)上,当该对象触发指定的事件时,就会执行事件处理函数。
attacheEvent()事件监听(IE678支持)
eventTarget.attachEvent()方法将指定的监听器注册到 eventTarget(目标对象) 上,当该对象触发指定的事件时,指定的回调函数就会被执行。
<button>传统注册事件</button> <button>方法监听注册事件</button> <button>ie9 attachEvent</button> <script> var btns = document.querySelectorAll('button'); // 1. 传统方式注册事件 btns[0].onclick = function() { alert('hi'); } btns[0].onclick = function() { alert('hao a u'); } // 2. 事件侦听注册事件 addEventListener // (1) 里面的事件类型是字符串 必定加引号 而且不带on // (2) 同一个元素 同一个事件可以添加多个侦听器(事件处理程序) btns[1].addEventListener('click', function() { alert(22); }) btns[1].addEventListener('click', function() { alert(33); }) // 3. attachEvent ie9以前的版本支持 btns[2].attachEvent('onclick', function() { alert(11); }) </script>
事件监听兼容性解决方案
封装一个函数,函数中判断浏览器的类型:
// 兼容性处理的原则: 首先照顾大多数浏览器,再处理特殊浏览器 function addEventListener(element, eventName, fn) { // 判断当前浏览器是否支持 addEventListener 方法 if (element.addEventListener) { element.addEventListener(eventName, fn); // 第三个参数 默认是false } else if (element.attachEvent) { element.attachEvent('on' + eventName, fn); } else { // 相当于 element.onclick = fn; element['on' + eventName] = fn; }
1.3.3. 删除事件(解绑事件)
// 1.传统的注册事件 eventTarget.onclick = null; // 2.方法监听注册方式 1.eventTarget.removeEventListener(type, listener[, useCapture]); 2.eventTarget.detachEvent(eventNameWithOn, callback);
例子
<div>1</div> <div>2</div> <div>3</div> <script> var divs = document.querySelectorAll('div'); divs[0].onclick = function() { alert(11); // 1. 传统方式删除事件 divs[0].onclick = null; } // 2. removeEventListener 删除事件 divs[1].addEventListener('click', fn) // 里面的fn 不需要调用加小括号 function fn() { alert(22); divs[1].removeEventListener('click', fn); } // 3. detachEvent divs[2].attachEvent('onclick', fn1); function fn1() { alert(33); divs[2].detachEvent('onclick', fn1); } </script>
删除事件兼容性解决方案
function removeEventListener(element, eventName, fn) { // 判断当前浏览器是否支持 removeEventListener 方法 if (element.removeEventListener) { element.removeEventListener(eventName, fn); // 第三个参数 默认是false } else if (element.detachEvent) { element.detachEvent('on' + eventName, fn); } else { element['on' + eventName] = null; }