JavaScript——(4)
【DOM】
一、DOM基本概念
DOM(Document Object Model,文档对象模型)是 JavaScript 操作 HTML 文档的接口,使文档操作变得非常优雅、简便。
DOM 最大的特点就是将 HTML 文档表示为 “节点树”。
DOM 元素/节点:就是渲染到页面上的,一个个的 HTML 标签体(标签 + 属性 + 内容)。
二、DOM节点树
<!DOCTYPE html> <html> <head><meta charset="UTF-8"><!-- 12 --><title>DOM</title> </head> <body><h1>IMOOC</h1><div><h2>Coder Dream</h2><img src="logo.png"><div class="box">文本内容</div></div> </body> </html>
【DOM】
整个 html 文档就对应一个 document 对象,可以操作 html 文档里面所有的标签及其属性和文本。
三、nodeType
节点的 nodeType 属性可以显示这个节点具体的类型。
document.nodeType; // 9
nodeType值 | 节点类型 |
---|---|
1 | 元素节点,例如 <p> 和 <div> |
3 | 文字节点 |
8 | 注释节点 |
9 | document 节点 |
10 | DTD 节点(文档类型声明) |
四、document
4.1 访问元素节点
所谓 “访问” 元素节点,就是指 “得到”、“获取” 页面上的元素节点。
对节点进行操作,第一步就是要得到它。
访问元素节点主要依靠 document 对象。
4.2 认识 document 对象
document 对象是 DOM 中最重要的东西,几乎所有 DOM 的功能都封装在了 document 对象中。
document 对象也表示整个 HTML 文档,它是 DOM 节点树的根。
document 对象的 nodeType 属性值是 9。
typeof document; // object document.nodeType; // 9
4.3 访问元素节点的常用方法
注意:以下方法的参数都是字符串类型 ''
。
方法 | 功能 | 兼容性 |
---|---|---|
document.getElementById() | 通过 id 得到元素 | IE 6 |
document.getElementsByTagName() | 通过标签名得到元素数组 | IE 6 |
document.getElementsByClassName() | 通过类名得到元素数组 | IE 9 |
document.querySelector() | 通过选择器得到元素(es6新特性) | IE 8 部分兼容、IE 9 完全兼容 |
document.querySelectorAll() | 通过选择器得到元素数组(es6新特性) | IE 8 部分兼容、IE 9 完全兼容 |
Element:元素。
query:查询。
Selector:选择器。
4.4 getElementById()
document.getElementById()
功能是通过 id 得到元素节点。
-
HTML
<div id="box">我是一个盒子</div> <p id="para">我是一个段落</p>
-
JS
var box = document.getElementById('box'); var para = document.getElementById('para');
【注意事项】
如果页面上有相同 id 的元素,则只能得到第一个。
原则上,html 中同一名称的 id 也只能出现一次。
4.5 延迟运行
通常 JS 代码要写到 HTML 结构的最后,否则 JS 无法找到相应的 DOM 节点。
可以使用 window.onload = function(){}
来延迟 JS 的执行,直到 HTML 文档加载完毕后(触发 window.onload 事件),再执行函数里的代码。
一般 script 标签会被放在头部或尾部。
头部就是
<head></head>
里面,尾部一般指</body>
前,但也有放在</body>
之后的(最好不要这样)!
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title> </head><body><div id="box">我是一个盒子</div><p id="para">我是一个段落</p><script>// 获取 DOM 节点var box = document.getElementById('box');var para = document.getElementById('para');// 输出获取到的 DOM 节点console.log(box); // <div id="box">我是一个盒子</div>console.log(para); // <p id="para">我是一个段落</p></script> </body></html><!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><script>// 获取 DOM 节点var box = document.getElementById('box');var para = document.getElementById('para');// 输出获取到的 DOM 节点// 由于 HTML 代码是顺序执行的,当执行到此处的 JS 代码时,后面 body 内的 DOM 节点还没来得及执行console.log(box); // nullconsole.log(para); // null</script> </head><body><div id="box">我是一个盒子</div><p id="para">我是一个段落</p> </body></html>
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><script>// window.onload 事件:当 HTML 文档加载完毕后触发window.onload = function () {// 获取 DOM 节点var box = document.getElementById('box');var para = document.getElementById('para');// 输出获取到的 DOM 节点console.log(box); // <div id="box">我是一个盒子</div>console.log(para); // <p id="para">我是一个段落</p>}</script> </head><body><div id="box">我是一个盒子</div><p id="para">我是一个段落</p> </body></html>
4.6 getElementsByTagName()
getElementsByTagName()
方法的功能是通过标签名得到节点数组。
注意:得到的是一个数组!
<p>我是段落</p> <p>我是段落</p> <p>我是段落</p> <p>我是段落</p>
var ps = document.getElementsByTagName('p');
【注意事项】
数组方便遍历,从而可以批量操控元素节点。
即使页面上只有一个指定标签名的节点,也将得到长度为 1 的数组。
任何一个节点元素也可以调用 getElementsByTagName() 方法,从而得到其内部的某种标签名的元素节点。
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><script>window.onload = function () {var ps = document.getElementsByTagName('p');console.log(ps); // HTMLCollection(6) [p, p, p, p, p, p]}</script> </head><body><div id="box1"><p>我是段落</p><p>我是段落</p><p>我是段落</p></div><div id="box2"><p>我是段落</p><p>我是段落</p><p>我是段落</p></div> </body></html>
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><script>window.onload = function () {// 先得到 box1var box1 = document.getElementById('box1');// 得到 box1 中的 p 标签的数组var ps_inbox1 = box1.getElementsByTagName('p');console.log(ps_inbox1); // HTMLCollection(3) [p, p, p]}</script> </head><body><div id="box1"><p>我是段落</p><p>我是段落</p><p>我是段落</p></div><div id="box2"><p>我是段落</p><p>我是段落</p><p>我是段落</p></div> </body></html>
4.7 getElementsByClassName()
getElementsByClassName()
方法的功能是通过类名得到节点数组。
-
HTML
<div class="spec">我是盒子</div> <div>我是盒子</div> <div class="spec">我是盒子</div> <div class="spec">我是盒子</div>
-
JS
var spec_divs = document.getElementsByClassName('spec');
【注意事项】
getElementsByClassName()
方法从 IE9 开始兼容。
某个节点元素也可以调用 getElementsByClassName() 方法,从而得到其内部的某类名的元素节点。
4.8 querySelector()
querySelector()
方法的功能是通过选择器得到元素。
-
HTML
<div id="box1"><p>我是段落</p><p class="spec">我是段落</p><p>我是段落</p> </div>
-
JS
var the_p = document.querySelector('#box1 .spec');
【注意事项】
querySelector() 方法只能得到页面上一个元素,如果有多个元素符合条件,则只能得到第一个元素。
querySelector() 方法从 IE8 开始兼容,但从 IE9 开始支持 CSS3 的选择器,如:nth-child()
、:[src^='dog']
等 CSS3 选择器形式都支持良好。
注意:不能选择伪类!
4.9 querySelectorAll()
querySelectorAll()
方法的功能是通过选择器得到元素数组。
即使页面上只有一个符合选择器的节点,也将得到长度为 1 的数组。
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title> </head><body><ul id="list1"><li>我是li</li><li>我是li</li><li>我是li</li><li>我是li</li><li>我是li</li></ul><ul id="list2"><li>我是li</li><li>我是li</li><li>我是li</li><li>我是li</li><li>我是li</li></ul><script>var lis_inlist1 = document.querySelectorAll('#list1 li');console.log(lis_inlist1); // NodeList(5) [li, li, li, li, li]</script> </body></html>
5.0 querySelector和getElementById获取元素的不同之处*(理解)
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title> </head><body><button id="btn1">按我创建一个新列表项</button>无序列表<ul id="list1"><li>列表项1</li><li>列表项1</li><li>列表项1</li></ul><button id="btn2">按我创建一个新列表项</button>无序列表<ul class="list2"><li>列表项2</li><li>列表项2</li><li>列表项2</li></ul><script>var list1 = document.getElementById("list1");var list2 = document.querySelector('.list2');var btn1 = document.getElementById('btn1');var btn2 = document.getElementById('btn2');var listE = list1.getElementsByTagName('li');var listS = list2.querySelectorAll('li');btn1.onclick = function () {// 创建新的li元素var oLi = document.createElement('li');// 写内容oLi.innerText = '我是新来的';// 上树list1.appendChild(oLi);console.log("list1有" + listE.length+"个li");console.log("---------------------------------------");};btn2.onclick = function () {// 创建新的li元素var oLi = document.createElement('li');// 写内容oLi.innerText = '我是新来的';// 上树list2.appendChild(oLi);console.log("list2有" + listS.length+"个li");console.log("---------------------------------------");};</script> </body></html>
五、节点的关系
关系 | 考虑所有结点 |
---|---|
子节点 | childNodes |
父节点 | parentNode |
第一个子节点 | firstChild |
最后一个子节点 | lastChild |
前一个兄弟节点 | previousSibling |
后一个兄弟节点 | nextSibling |
【注意:文本节点也属于节点】
DOM 中,文本节点也属于节点,在使用节点的关系时一定要注意。
在标准的 W3C 规范中,空白文本节点也应该算作节点,但是在 IE8 及以前的浏览器中会有一定的兼容问题,它们不把空白文本节点当作节点。
【排除文本节点的干扰】
从 IE9 开始支持一些 “只考虑元素节点” 的属性。
如果考虑兼容性,可以通过后面的函数封装来实现。
关系 | 考虑所有结点 | 只考虑元素节点 |
---|---|---|
子节点 | childNodes | children |
父节点 | parentNode | 同 |
第一个子节点 | firstChild | firstElementChild |
最后一个子节点 | lastChild | lastElementChild |
前一个兄弟节点 | previousSibling | previousElementSibling |
后一个兄弟节点 | nextSibling | nextElementSibling |
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title> </head><body><div id="box"><p>我是段落A</p><p id="para">我是段落B</p><p>我是段落C</p></div><script>var box = document.getElementById('box');var para = document.getElementById('para');// 所有子节点console.log(box.childNodes);// 7个,猜一猜有哪些?// 所有的元素子节点(IE9开始兼容)console.log(box.children); //3个console.log(box.children.para);// 第一个子节点console.log(box.firstChild);console.log(box.firstChild.nodeType);// 第一个元素子节点(IE9开始兼容)console.log(box.firstElementChild);// 最后一个子节点console.log(box.lastChild);console.log(box.lastChild.nodeType);// 最后一个元素子节点(IE9开始兼容)console.log(box.lastElementChild);// 父节点console.log(para.parentNode);// 前一个兄弟节点console.log(para.previousSibling);// 前一个元素兄弟节点(IE9开始兼容)console.log(para.previousElementSibling);// 后一个兄弟节点console.log(para.nextSibling);// 后一个元素兄弟节点(IE9开始兼容)console.log(para.nextElementSibling);</script> </body></html>
-
结果
注意:文本也算作节点(如图选中空白部分)
六、书写常见的节点关系函数*(案例理解)
书写 IE6 也能兼容的 “寻找所有元素子节点” 函数。
书写 IE6 也能兼容的 “寻找前一个元素兄弟节点” 函数。
如何编写函数,获得某元素的所有的兄弟节点。
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title> </head><body><div id="box"><p>我是段落</p><p>我是段落</p><p>我是段落</p><p id="fpara">我是段落fpara</p>我是文本<!-- 我是注释 --><p id="para">我是段落para<span>1</span><span>2</span><span>3</span></p><p>我是段落</p><p>我是段落</p><p>我是段落</p></div><script>var box = document.getElementById('box'); //divvar para = document.getElementById('para'); //pvar fpara = document.getElementById('fpara'); //p// 封装一个函数,这个函数可以返回元素的所有子元素节点(兼容到 IE6),类似 children 的功能function getChildren(node) {// 结果数组var children = [];// 遍历 node 这个节点的所有子节点,判断每一个子节点的 nodeType 属性是不是 1// 如果是 1,就推入结果数组for (var i = 0; i < node.childNodes.length; i++) {if (node.childNodes[i].nodeType == 1) {children.push(node.childNodes[i]);}}return children;}console.log(getChildren(box));console.log(getChildren(para));// 封装一个函数,这个函数可以返回元素的前一个元素兄弟节点(兼容到 IE6),类似 previousElementSibling 的功能function getElementPrevSibling(node) {var o = node;// 使用 while 语句while (o.previousSibling != null) {if (o.previousSibling.nodeType == 1) {// 结束循环,找到了return o.previousSibling;}// 让 o 成为它的前一个节点o = o.previousSibling;}return null;}console.log(getElementPrevSibling(para));console.log(getElementPrevSibling(fpara));// 封装第三个函数,这个函数可以返回元素的所有元素兄弟节点function getAllElementSibling(node) {// 前面的元素兄弟节点var prevs = [];// 后面的元素兄弟节点var nexts = [];var o = node;// 遍历 node 的前面的节点while (o.previousSibling != null) {if (o.previousSibling.nodeType == 1) {prevs.unshift(o.previousSibling);//将新项添加到数组起始位置}o = o.previousSibling;}o = node;// 遍历 node 的后面的节点while (o.nextSibling != null) {if (o.nextSibling.nodeType == 1) {nexts.push(o.nextSibling);//将新项添加到数组末尾位置}o = o.nextSibling;}// 将两个数组进行合并,然后返回return prevs.concat(nexts);}console.log(getAllElementSibling(para));</script> </body></html>
七、节点操作
7.1 如何改变元素节点中的内容
改变元素节点中的内容可以使用两个相关属性。
-
innerHTML
-
innerText
innerHTML
属性能以 HTML 语法设置节点中的内容。
innerText
属性只能以纯文本的形式设置节点中的内容。
-
innerHTML
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title> </head><body><div id="box"></div><script>var oBox = document.getElementById('box');oBox.innerHTML = '周吉瑞';</script> </body></html>
-
innerHTML
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title> </head><body><div id="box"></div><script>var oBox = document.getElementById('box');// 注意:此处的 HTML 字符串不允许换行!oBox.innerHTML = '<ul><li>牛奶</li><li>咖啡</li></ul>';</script> </body></html>
-
innerText
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title> </head><body><div id="box"></div><script>var oBox = document.getElementById('box');oBox.innerText = '周吉瑞';</script> </body></html>
-
innerText
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title> </head><body><div id="box"></div><script>var oBox = document.getElementById('box');oBox.innerText = '<ul><li>牛奶</li><li>咖啡</li></ul>';</script> </body></html>
7.2 如何改变元素节点的CSS样式
改变元素节点的 CSS 样式需要使用这样的语句:
-
oBox.style.backgroundColor = 'red';
-
oBox.style.backgroundImage = 'url(images/1.jpg)';
-
oBox.style.fontSize = '32px';
【注意事项】
-
CSS 属性要写成 “驼峰” 形式
-
CSS 属性值要设置成完整形式
-
注意写单位
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>.box {width: 200px;height: 200px;border: 1px solid #000;}</style> </head><body><div class="box" id="box">你好</div><script>var oBox = document.getElementById('box');oBox.style.backgroundColor = 'rgb(100, 200, 123)';oBox.style.backgroundColor = '#f80';oBox.style.backgroundImage = 'url(https://www.imooc.com/static/img/index/logo-recommended.png)';oBox.style.backgroundSize = 'contain';oBox.style.fontSize = '50px';</script> </body></html>
JS 修改的 CSS 样式,属于行内式,优先级最高!所以可以覆盖原有的样式。
7.3 如何改变元素节点的HTML属性
标准 W3C 属性,如 src
、href
、title
、alt
等等,只需要直接打点进行更改即可。
oImg.src = 'images/2.jpg';
【案例】
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title> </head><body><img src="images/1.jpg" id="pic"><a href="http://www.baidu.com" id="link">去百度</a><script>var oPic = document.getElementById('pic');var oLink = document.getElementById('link');oPic.src = 'images/2.jpg';oLink.href = 'http://www.imooc.com';oLink.innerText = '去慕课网';</script> </body></html>
对于不符合 W3C 标准的属性,要使用 setAttribute()
和 getAttribute()
来设置、读取。
oBox.setAttribute('data-n', 10); var n = oBox.getAttribute('data-n'); alert(n);
HTML 的自定义属性,主要用途就是与 JS 配合方便实现一些效果。
【案例】
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title> </head><body><div id="box"></div><script>var box = document.getElementById('box');box.setAttribute('data-n', 10);var n = box.getAttribute('data-n');alert(n);</script> </body></html>
八、节点的创建、移动、删除和克隆
8.1 节点的创建
document.createElement()
方法用于创建一个指定 tag name 的 HTML 元素。
var oDiv = document.createElement('div');
8.2 "孤儿节点"
新创建出的节点是 “孤儿节点”,这意味着它并没有被挂载到 DOM 树上,我们无法看见它。
必须继续使用 appendChild()
或 insertBefore()
方法将孤儿节点插入到 DOM 树上。
8.2.1 appendChild()
任何已经在 DOM 树上的节点,都可以调用 appendChild() 方法,它可以将孤儿节点挂载到它的内部,成为它的最后一个子节点。
父节点.appendChild(孤儿节点);
【小案例】
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title> </head><body><div id="box"><p>我是原本的段落0</p><p>我是原本的段落1</p><p>我是原本的段落2</p></div><script>var oBox = document.getElementById('box');// 创建孤儿节点var oP = document.createElement('p');// 设置内部文字oP.innerText = '我是新来的';// 上树oBox.appendChild(oP);</script> </body></html>
8.2.2 insertBefore()
任何已经在 DOM 树上的节点,都可以调用 insertBefore() 方法,它可以将孤儿节点挂载到它的内部,成为它的 “标杆子节点” 之前的节点。
父节点.insertBefore(孤儿节点, 标杆节点);
【小案例】
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title> </head><body><div id="box"><p>我是原本的段落0</p><p>我是原本的段落1</p><p>我是原本的段落2</p></div><script>var oBox = document.getElementById('box');// 获取元素数组var oPs = oBox.getElementsByTagName('p');// 创建孤儿节点var oP = document.createElement('p');// 设置内部文字oP.innerText = '我是新来的';// 上树oBox.insertBefore(oP, oPs[1]);</script> </body></html>
8.3 节点创建小案例
【
动态创建一个20行12列的表格
每一行是一个人的信息
】
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>td {width: 20px;height: 20px;border: 1px solid #000;}</style> </head><body><table id="mytable"></table><script>// 请动态创建出一个 20 行 12 列的表格var mytable = document.getElementById('mytable');for (var i = 0; i < 20; i++) {// 创建了新的 tr 标签var tr = document.createElement('tr');for (var j = 0; j < 12; j++) {// 创建了新的 td 标签var td = document.createElement('td');// 让 tr 追加 td 标签tr.appendChild(td);}// 让 mytable 追加 tr 标签mytable.appendChild(tr);}</script> </body></html>
【九九乘法表】
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>td {width: 80px;height: 30px;padding-left: 10px;border: 1px solid #000;}</style> </head><body><table id="mytable"></table><script>// 请创建九九乘法表var mytable = document.getElementById('mytable');for (var i = 1; i <= 9; i++) {// 创建了新的 tr 标签var tr = document.createElement('tr');for (var j = 1; j <= i; j++) {// 创建了新的 td 标签var td = document.createElement('td');// 设置 td 内部的文字td.innerText = i + '×' + j + '=' + (i * j);// 让tr追加 td 标签tr.appendChild(td);}// 让 mytable 追加 tr 标签mytable.appendChild(tr);}</script> </body></html>
8.4 移动节点
如果将已经挂载到 DOM 树上的节点成为 appendChild()
或者 insertBefore()
的参数,这个节点将会被移动。
新父节点.appendChild(已经有父亲的节点);
新父节点.insertBefore(已经有父亲的节点, 标杆子节点);
这意味着一个节点不能同时位于 DOM 树的两个位置。
【小案例】
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title> </head><body><div id="box1"><p id="para">我是段落</p></div><div id="box2"><p>我是box2的原有p标签</p><p>我是box2的原有p标签</p><p>我是box2的原有p标签</p><p>我是box2的原有p标签</p></div><script>var box2 = document.getElementById('box2');var para = document.getElementById('para');var ps_inbox2 = box2.getElementsByTagName('p');box2.insertBefore(para, ps_inbox2[2]);</script> </body></html>
8.5 删除节点
removeChild()
方法从 DOM 中删除一个子节点。
父节点.removeChild(要删除子节点);
节点不能主动删除自己,必须由父节点删除它。
【小案例】
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title> </head><body><div id="box"><p>我是p节点0</p><p>我是p节点1</p><p>我是p节点2</p></div><script>var box = document.getElementById('box');var the_first_p = box.getElementsByTagName('p')[0];box.removeChild(the_first_p);</script> </body></html>
8.6 克隆节点
cloneNode()
方法可以克隆节点,克隆出的节点是 “孤儿节点”。
必须继续使用 appendChild()
或 insertBefore()
方法将孤儿节点插入到 DOM 树上。
var 孤儿节点 = 老节点.cloneNode(); var 孤儿节点 = 老节点.cloneNode(true);
参数是一个布尔值,表示是否采用深度克隆:如果为 true,则该节点的所有后代节点也会被克隆,如果为 false,则只克隆该节点本身。
【小案例】
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title> </head> <body><div id="box1"><ul><li>牛奶</li><li>咖啡</li><li>可乐</li></ul></div><div id="box2"></div><script>var box1 = document.getElementById('box1');var box2 = document.getElementById('box2');var theul = box1.getElementsByTagName('ul')[0];// 克隆节点var new_ul = theul.cloneNode(true);box2.appendChild(new_ul);</script> </body> </html>
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title> </head> <body><div id="box1"><ul><li>牛奶</li><li>咖啡</li><li>可乐</li></ul></div><div id="box2"></div><script>var box1 = document.getElementById('box1');var box2 = document.getElementById('box2');var theul = box1.getElementsByTagName('ul')[0];// 克隆节点var new_ul = theul.cloneNode(false);box2.appendChild(new_ul);</script> </body> </html>
cloneNode()
方法是 JavaScript 中用于克隆 DOM 节点的一种方法。当文档中说“cloneNode()
方法只克隆该节点本身”时,它指的是该方法会创建一个新的节点对象,这个新对象与原始节点具有相同的节点类型、节点名称和节点属性(但不包括事件监听器和由 JavaScript 动态添加的属性,除非使用深克隆),但是它不会克隆原始节点的任何子节点或后代节点。
简而言之,“只克隆该节点本身”意味着克隆操作不会递归地克隆节点树下的所有子节点。
这里有一个例子来帮助说明这个概念:
假设你有以下的 HTML 结构:
htmlCopy Code<div id="parent"><child>This is a child node.</child> </div>
如果你使用以下 JavaScript 代码来克隆 #parent
节点,但只克隆节点本身:
javascriptCopy Codevar parent = document.getElementById('parent'); var clonedParent = parent.cloneNode(false); // false 表示浅克隆
在这个例子中,clonedParent
将是一个新的 <div>
节点,它的 ID、类名和其他属性(如果有的话)将与原始 #parent
节点相同,但是它不会包含原始 #parent
节点下的 <child>
子节点。
九、事件监听
DOM 允许我们书写 JavaScript 代码以让 HTML 元素作出反应。
什么是 “事件”:用户与网页的交互动作。
9.1 什么是事件监听
“监听” 顾名思义,就是让计算机随时能够发现这个事件发生了,从而执行程序员预先编写好的一些程序。
设置事件监听的方法主要有 onxxx
和 addEventListener()
两种,二者的区别将在 “事件传播” 一课中介绍。
原始的事件处理方法:“直接通过事件绑定函数”
比如:
HTML:
<button onclick="add();">点击</button>
JS:
function add() { alert("相加"); }
以上方式不推荐使用!!!
9.2 最简单的设置事件监听的方法
最简单的给元素设置事件监听的方法就是设置它们的 onxxx
属性,像这样:
//匿名函数 oBox.onclick = function() {// 点击盒子时,将执行这里的语句 }
//具名函数 function fun() {... }oBox.onclick = fun;
【小案例】
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>div {width: 200px;height: 200px;background-color: #ccc;}</style> </head><body><div id="box"></div><script>var oBox = document.getElementById('box');// 给box这个盒子添加点击事件监听oBox.onclick = function () {alert('你好,我是点击事件函数');};</script> </body></html>
9.3 常见的鼠标事件监听
事件名 | 事件描述 |
---|---|
onclick | 当鼠标单击某个对象 |
ondblclick | 当鼠标双击某个对象 |
onmousedown | 当某个鼠标按键在某个对象上被按下 |
onmouseup | 当某个鼠标按键在某个对象上被松开 |
onmousemove | 当某个鼠标按键在某个对象上被移动 |
onmouseenter | 当鼠标进入某个对象(相似事件 onmouseover ) |
onmouseleave | 当鼠标离开某个对象(相似事件 onmouseout ) |
9.4 常见的键盘事件监听
事件名 | 事件描述 |
---|---|
onkeypress | 当某个键盘的键被按下(系统按钮如箭头键和功能键无法得到识别) |
onkeydown | 当某个键盘的键被按下(系统按钮可以识别,并且会先于 onkeypress 发生) |
onkeyup | 当某个键盘的键被松开 |
9.5 常见的表单事件监听
事件名 | 事件描述 |
---|---|
onchange | 当用户改变完成域的内容 |
onfocus | 当某元素获得焦点(比如 tab 键或鼠标点击) |
onblur | 当某元素失去焦点 |
onsubmit | 当表单被提交 |
onreset | 当表单被重置 |
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title> </head><body><form id="myform"><p>姓名:<input type="text" name="nameField"></p><p>年龄:<input type="text" name="ageField"></p><p><input type="submit"></p></form><script>var myform = document.getElementById('myform');// 表单对象可以通过 “打点” name 属性,得到里面的子元素。var nameField = myform.nameField;var ageField = myform.ageField;nameField.onchange = function () {console.log('你已经修改完了姓名');};nameField.oninput = function () {console.log('你正在修改姓名');};nameField.onfocus = function () {console.log('姓名框已经得到了焦点');}nameField.onblur = function () {console.log('姓名框已经失去了焦点');}myform.onsubmit = function () {alert('你正在尝试提交表单');/* return true; 可以省略,默认执行表单提交 *//* return false; 不执行表单提交,比如用户信息填写不全就不应该提交表单 */}</script> </body></html>
表单对象可以通过 “打点” name 属性,得到里面的子元素。
9.6 常见的页面事件监听
事件名 | 事件描述 |
---|---|
onload | 当页面或图像被完成加载 |
onunload | 当用户退出页面 |
更多有关窗口或页面的事件在 BOM 课程中介绍。
十、事件传播
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>#box1 {width: 202px;height: 202px;border: 1px solid #000;padding: 50px;}#box2 {width: 100px;height: 100px;border: 1px solid #000;padding: 50px;}#box3 {width: 100px;height: 100px;border: 1px solid #000;}</style> </head><body><div id="box1"><div id="box2"><div id="box3"></div></div></div><script>var oBox1 = document.getElementById('box1');var oBox2 = document.getElementById('box2');var oBox3 = document.getElementById('box3');oBox2.onclick = function () {console.log('我是 box2 的 onclick');};oBox3.onclick = function () {console.log('我是 box3 的 onclick');};oBox1.onclick = function () {console.log('我是 box1 的 onclick');};</script> </body></html>
10.1 捕获阶段和冒泡阶段
10.2 onxxx写法只能监听冒泡阶段
10.3 addEventListener()方法
oBox.addEventListener('click', function(){}, true);
Event:事件
【小案例】
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>#box1 {width: 202px;height: 202px;border: 1px solid #000;padding: 50px;}#box2 {width: 100px;height: 100px;border: 1px solid #000;padding: 50px;}#box3 {width: 100px;height: 100px;border: 1px solid #000;}</style> </head><body><div id="box1"><div id="box2"><div id="box3"></div></div></div><script>var oBox1 = document.getElementById('box1');var oBox2 = document.getElementById('box2');var oBox3 = document.getElementById('box3');oBox1.onclick = function () {console.log('我是box1的onclick');};oBox2.onclick = function () {console.log('我是box2的onclick');};oBox3.onclick = function () {console.log('我是box3的onclick');};oBox3.addEventListener('click', function () {console.log('我是box3的捕获阶段');}, true);oBox2.addEventListener('click', function () {console.log('我是box2的捕获阶段');}, true);oBox1.addEventListener('click', function () {console.log('我是box1的捕获阶段');}, true);oBox1.addEventListener('click', function () {console.log('我是box1的冒泡阶段');}, false);oBox2.addEventListener('click', function () {console.log('我是box2的冒泡阶段');}, false);oBox3.addEventListener('click', function () {console.log('我是box3的冒泡阶段');}, false);</script> </body></html>
结果:若点击box2,
我是box1的捕获阶段
我是box2的捕获阶段
我是box2的onclick
我是box2的冒泡阶段
我是box1的onclick
我是box1的冒泡阶段
-
如果给元素设置相同的两个或多个同名事件,则 onclick 写法后面写的会覆盖先写的;而 addEventListener 会按顺序执行(原因是 onclick 函数赋值多次会发生覆盖)
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>#box1 {width: 202px;height: 202px;border: 1px solid #000;padding: 50px;}#box2 {width: 100px;height: 100px;border: 1px solid #000;padding: 50px;}#box3 {width: 100px;height: 100px;border: 1px solid #000;}</style> </head><body><div id="box1"><div id="box2"><div id="box3"></div></div></div><script>var oBox1 = document.getElementById('box1');var oBox2 = document.getElementById('box2');var oBox3 = document.getElementById('box3');oBox2.onclick = function () {alert('A');};oBox2.onclick = function () {alert('B');};oBox2.addEventListener('click', function () {alert('C');}, false);oBox2.addEventListener('click', function () {alert('D');}, false);</script> </body></html>
10.4 removeEventListener()方法
当我们 addEventListener() 后,该监听事件就会一直生效,直到关闭页面或是移除该对应的监听!
removeEventListener() 方法用来移除监听事件(只能移除具名函数的监听,且方法名称后面不能带)
var body = document.querySelector('body'), var clickTarget = document.getElementById('click-target'), var mouseOverTarget = document.getElementById('mouse-over-target'), var toggle = false;// 具名函数 function makeBackgroundYellow() {'use strict';if (toggle) {body.style.backgroundColor = 'white';} else {body.style.backgroundColor = 'yellow';}toggle = !toggle; }// 注册监听 clickTarget.addEventListener('click',makeBackgroundYellow,false );// 注册监听 mouseOverTarget.addEventListener('mouseover', function () {'use strict';// 移除监听clickTarget.removeEventListener('click',makeBackgroundYellow,// 可以指定是移除冒泡类型的,还是捕获类型的!false); });
10.5 特别注意
addEventListener() 一但注册某个事件,那么这个事件是会一直生效的,就算是该注册事件写在某个函数中,那个函数调用已经结束了,但是该事件还是会存在!因为事件的注册是直接绑定到相应的元素上的,并且是异步的,除非页面被关闭,或者是移除该监听!
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title> </head><body><button id="btn">点击</button><script>var btn = document.getElementById('btn');function demo() {console.log('btn');}function test() {btn.addEventListener('click', demo, false);return 'over';}console.log(test());</script> </body></html>执行结果: over (点击按钮) btn
特别注意:事件传播过程中如果没有控制,那么事件捕获最先从 document 对象开始,事件冒泡最晚到达 document 对象!
十一、事件对象
11.1 什么是事件对象
事件处理函数提供一个形式参数,它是一个对象,封装了本次事件的细节。
这个参数通常用单词 event
或字母 e
来表示。
oBox.onmousemove = function(e) {// 对象 e 就是这次事件的“事件对象” }
这个对象 e 接受的值由浏览器或操作系统传递。
11.2 鼠标位置
属性 | 属性描述 |
---|---|
clientX | 鼠标指针相对于浏览器的水平坐标 |
clientY | 鼠标指针相对于浏览器的垂直坐标 |
pageX | 鼠标指针相对于整张网页的水平坐标 |
pageY | 鼠标指针相对于整张网页的垂直坐标 |
offsetX | 鼠标指针相对于事件源元素的水平坐标 |
offsetY | 鼠标指针相对于事件源元素的垂直坐标 |
-
浏览器
-
整张网页
-
事件源
【小案例】
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>* {margin: 0;padding: 0;}#box {width: 200px;height: 200px;background-color: #333;margin: 100px;margin-top: 150px;}body {height: 2000px;}#info {font-size: 30px;margin: 60px;}</style> </head><body><div id="box"></div><div id="info"></div><script>var oBox = document.getElementById('box');var oInfo = document.getElementById('info');oBox.onmousemove = function (e) {oInfo.innerHTML = 'offsetX/Y:' + e.offsetX + ',' + e.offsetY + '<br>'+ 'clientX/Y:' + e.clientX + ',' + e.clientY + '<br>'+ 'pageX/Y:' + e.pageX + ',' + e.pageY;};</script> </body></html>
【注意事项】
对于 offsetX 和 offsetY 而言,总是以最内层元素为事件源。
所以应避免事件源盒子内部有小盒子的存在。
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>* {margin: 0;padding: 0;}#box {overflow: hidden;width: 200px;height: 200px;background-color: #333;margin: 100px;margin-top: 150px;}body {height: 2000px;}#info {font-size: 30px;margin: 60px;}p {width: 100px;height: 100px;background-color: pink;margin: 50px;}</style> </head><body><div id="box"><p></p></div><div id="info"></div><script>var oBox = document.getElementById('box');var oInfo = document.getElementById('info');oBox.onmousemove = function (e) {oInfo.innerHTML = 'offsetX/Y:' + e.offsetX + ',' + e.offsetY + '<br>';};</script> </body></html>
11.3 e.charCode和e.keyCode属性
e.charCode
属性通常用于 onkeypress
事件中,表示用户输入的字符的 “字符码”。
e.keyCode
属性通常用于 onkeydown
事件和 onkeyup
中,表示用户按下的按键的 “键码”。
11.3.1 charCode字符码
字符 | ascii字符码 |
---|---|
0 ~ 9 | 48 ~ 57 |
A ~ Z | 65 ~ 90 |
a ~ z | 97 ~ 122 |
11.3.2 keyCode键码
按键 | 键码 |
---|---|
0 ~ 9 | 48 ~ 57(同 charCode 键码完全相同) |
A ~ Z a ~ z | 65 ~ 90 (字母不分大小写) |
方向键 ← ↑ → ↓ | 37、38、39、40 |
退格键 Backspace | 8 |
Tab | 9 |
回车键 enter | 13 |
Shift | 16 |
Ctrl | 17 |
Alt | 18 |
大小键 CapsLK | 20 |
Esc | 27 |
空格键 space | 32 |
删除键 Delete | 46 |
开始键 Start | 91 |
F1 ~ F12 | 112 ~ 123 |
以上只是部分!
11.3.3 案例
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title> </head><body><input type="text" id="field1"><h1 id="info1"></h1><input type="text" id="field2"><h1 id="info2"></h1><script>var oField1 = document.getElementById('field1');var oInfo1 = document.getElementById('info1');var oField2 = document.getElementById('field2');var oInfo2 = document.getElementById('info2');oField1.onkeypress = function (e) {oInfo1.innerText = '你输入的字符的字符码是' + e.charCode;};oField2.onkeydown = function (e) {oInfo2.innerText = '你按下的按键的键码是' + e.keyCode;};</script> </body></html>
【小案例 - 盒子移动】
制作一个特效:按方向键可以控制页面上的盒子移动。
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>#box {position: absolute;top: 200px;left: 200px;width: 100px;height: 100px;background-color: orange;}#info {position: fixed;}</style> </head><body><div id="box"></div><h1 id="info"></h1><script>var oBox = document.getElementById('box');var oInfo = document.getElementById('info');// 全局变量 t、l,分别表示盒子的 top 属性值和 left 属性值var t = 200;var l = 200;// 监听 document 对象的键盘按下事件监听,表示当用户在整个网页上按下按键的时候document.onkeydown = function (e) {oInfo.innerText = '你按下的按键的键码是' + e.keyCode;switch (e.keyCode) {case 37:l -= 3;break;case 38:t -= 3;break;case 39:l += 3;break;case 40:t += 3;break;}// 更改样式oBox.style.left = l + 'px';oBox.style.top = t + 'px';};</script> </body></html>
11.4 e.preventDefault()方法
e.preventDefault()
方法用来阻止事件产生的 “默认动作”。
一些特殊的业务需求,需要阻止事件的 “默认动作”。
【小案例1】
制作一个文本框,只能让用户在其中输入小写字母和数字,其他字符输入没有效果。
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title> </head><body><p>只能输入小写字母和数字:<input type="text" id="field"></p><script>var oField = document.getElementById('field');oField.onkeypress = function (e) {console.log(e.charCode);// 根据用户输入的字符的字符码(e.charCode)// 数字 0~9,字符码 48~57// 小写字母 a~z,字符码 97~122if (!(e.charCode >= 48 && e.charCode <= 57 || e.charCode >= 97 && e.charCode <= 122)) {// 阻止浏览器的默认行为e.preventDefault();}};</script> </body></html>
【小案例2】
制作鼠标滚轮事件:当鼠标在盒子中向下滚动时,数字加 1;反之,数字减 1。
鼠标滚轮事件是 onmousewheel
,它的事件对象 e 提供 deltaY
属性表示鼠标滚动方向,向下滚动是返回正值,向上滚动时返回负值。
-
没有阻止事件的 “默认动作” 时
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>#box {width: 200px;height: 200px;background-color: #333;}body {height: 2000px;}</style> </head><body><div id="box"></div><h1 id="info">0</h1><script>var oBox = document.getElementById('box');var oInfo = document.getElementById('info');// 全局变量就是 info 中显示的数字var a = 0;// 给 box 盒子添加鼠标滚轮事件监听oBox.onmousewheel = function (e) {if (e.deltaY > 0) {a++;} else {a--;}oInfo.innerText = a;}</script> </body></html>
-
阻止事件的 “默认动作” 后
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>#box {width: 200px;height: 200px;background-color: #333;}body {height: 2000px;}</style> </head><body><div id="box"></div><h1 id="info">0</h1><script>var oBox = document.getElementById('box');var oInfo = document.getElementById('info');// 全局变量就是 info 中显示的数字var a = 0;// 给 box 盒子添加鼠标滚轮事件监听oBox.onmousewheel = function (e) {// 阻止默认事件:就是说当用户在盒子里面滚动鼠标滚轮的时候,此时不会引发页面的滚动条的滚动e.preventDefault();if (e.deltaY > 0) {a++;} else {a--;}oInfo.innerText = a;}</script> </body></html>
【小案例3】
制作鼠标右键点击事件:当鼠标右键被点击时,改变背景颜色。
oncontextmenu
:在用户点击鼠标右键打开上下文菜单时触发。
-
没有阻止事件的 “默认动作” 时
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title> </head><body><script>var oBody = document.getElementsByTagName('body')[0];// 给 document 添加鼠标右键事件监听var flag = 0;document.oncontextmenu = function (e) {if (flag == 0) {oBody.style.backgroundColor = 'black';flag = 1;;} else {oBody.style.backgroundColor = 'white';flag = 0;}}</script> </body></html>
-
阻止事件的 “默认动作” 后
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title> </head><body><script>var oBody = document.getElementsByTagName('body')[0];// 给 document 添加鼠标右键事件监听var flag = 0;document.oncontextmenu = function (e) {// 阻止默认事件:就是说当用户右键的时候,此时不会弹出页面的右键菜单e.preventDefault();if (flag == 0) {oBody.style.backgroundColor = 'black';flag = 1;;} else {oBody.style.backgroundColor = 'white';flag = 0;}}</script> </body></html>
11.5 e.stopPropagation()方法
e.stopPropagation()
方法用来阻止事件继续传播。
在一些场合,非常有必要切断事件继续传播,否则会造成页面特效显示出 bug。
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>div {width: 200px;height: 200px;background-color: #333;}</style> </head><body><div id="box"><button id="btn">按我</button></div><script>var oBox = document.getElementById('box');var oBtn = document.getElementById('btn');oBox.onclick = function () {console.log('我是盒子');};oBtn.onclick = function () {console.log('我是按钮');};</script> </body></html>
【阻止冒泡】
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>div{width: 200px;height: 200px;background-color: #333;}</style> </head><body><div id="box"><button id="btn">按我</button></div><script>var oBox = document.getElementById('box');var oBtn = document.getElementById('btn');oBox.onclick = function () {console.log('我是盒子');};oBtn.onclick = function (e) {// 阻止事件继续传播e.stopPropagation();console.log('我是按钮');};</script> </body></html>
【阻止传播】
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>div {width: 200px;height: 200px;background-color: #333;}</style> </head><body><div id="box"><button id="btn">按我</button></div><script>var oBox = document.getElementById('box');var oBtn = document.getElementById('btn');oBox.addEventListener('click', function (e) {// 阻止事件继续传播e.stopPropagation();console.log('我是盒子');}, true);oBtn.addEventListener('click', function () {console.log('我是按钮');}, true);</script> </body></html>
【小案例】
制作一个弹出层:点击按钮显示弹出层,点击网页任意地方,弹出层关闭。
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>.modal {width: 400px;height: 140px;background-color: #333;position: absolute;top: 50%;left: 50%;margin-top: -70px;margin-left: -200px;display: none;}</style> </head><body><button id="btn">按我弹出弹出层</button><div class="modal" id="modal"></div><script>var oBtn = document.getElementById('btn');var oModal = document.getElementById('modal');// 点击按钮的时候,弹出层显示oBtn.onclick = function (e) {// 阻止事件继续传播到document身上e.stopPropagation();oModal.style.display = 'block';};// 点击页面任何部分的时候,弹出层关闭document.onclick = function () {oModal.style.display = 'none';};// 点击弹出层内部的时候,不能关闭弹出层的,所以应该阻止事件继续传播oModal.onclick = function (e) {// 阻止事件继续传播到document身上e.stopPropagation();};</script> </body></html>
阻止前:不显示内容
阻止后:正常显示
十二、事件委托
12.1 批量添加事件监听
题目:页面上有一个无序列表 <ul>
,它内部共有 20 个 <li>
元素,请批量给它们添加事件监听,实现效果:点击哪个 <li>
元素,哪个 <li>
元素就变红。
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title> </head><body><ul id="list"><li>列表项</li><li>列表项</li><li>列表项</li><li>列表项</li><li>列表项</li><li>列表项</li><li>列表项</li><li>列表项</li><li>列表项</li><li>列表项</li><li>列表项</li><li>列表项</li><li>列表项</li><li>列表项</li><li>列表项</li><li>列表项</li><li>列表项</li><li>列表项</li><li>列表项</li><li>列表项</li></ul><script>var oList = document.getElementById('list');var lis = oList.getElementsByTagName('li');// 书写循环语句,批量给元素添加监听for (var i = 0; i < lis.length; i++) {lis[i].onclick = function () {// 在这个函数中,this 表示点击的这个元素,this 涉及函数上下文的相关知识,我们在“面向对象”课程中介绍this.style.color = 'red';};}</script> </body></html>
12.2 批量添加事件监听的性能问题
每一个事件监听注册都会消耗一定的系统内存,而批量添加事件会导致监听数量太多,内存消耗会非常大。
实际上,每个 <li>
的事件处理函数都是不同的函数,这些函数本身也会占用内存。
12.3 新增元素动态绑定事件
题目:页面上有一个无序列表 <ul>
,它内部没有 <li>
元素,请制作一个按钮,点击这个按钮就能增加一个 <li>
元素。并且要求每个增加的 <li>
元素也要有点击事件监听,实现效果:点击哪个 <li>
元素,哪个 <li>
元素就变红。
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title> </head><body><button id="btn">按我添加新的li列表项</button><ul id="list"></ul><script>var oBtn = document.getElementById('btn');var oList = document.getElementById('list');var lis = oList.getElementsByTagName('li');// 按钮的点击事件oBtn.onclick = function () {// 创建一个新的 li 列表项,孤儿节点var oLi = document.createElement('li');oLi.innerHTML = '我是列表项';// 上树oList.appendChild(oLi);// 给新创建的这个 li 节点添加 onclick 事件监听oLi.onclick = function () {this.style.color = 'red';};};</script> </body></html>
12.4 动态绑定事件的问题
新增元素必须分别添加事件监听,不能自动获得事件监听。
大量事件监听、大量事件处理函数都会产生大量的内存消耗。
12.5 事件委托
利用事件冒泡机制,将后代元素事件委托给祖先元素。
12.6 e.target和e.currentTarget属性
事件委托通常需要结合使用 e.target 属性。
属性 | 属性描述 |
---|---|
target | 触发此事件的最早元素,即 “事件源元素” |
currentTarget | 事件处理程序附加到的元素 |
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title> </head><body><button id="btn">按我创建一个新列表项</button><ul id="list"><li>列表项</li><li>列表项</li><li>列表项</li></ul><script>var oList = document.getElementById('list');var oBtn = document.getElementById('btn');oList.onclick = function (e) {// e.target 表示用户真正点击的那个元素,即 “事件源元素”e.target.style.color = 'red';};oBtn.onclick = function () {// 创建新的li元素var oLi = document.createElement('li');// 写内容oLi.innerText = '我是新来的';// 上树oList.appendChild(oLi);};</script> </body></html>
12.7 事件委托的使用场景
当有大量类似元素需要批量添加事件监听时,使用事件委托可以减少内存开销。
当有动态元素节点上树时,使用事件委托可以让新上树的元素具有事件监听。
12.8 使用事件委托时需要注意的事项
(1)onmouseenter
和 onmouseover
都表示 “鼠标进入”,它们有什么区别呢?
答:onmouseenter
不冒泡,onmouseover
冒泡。
-
使用事件委托时要注意:不能委托不冒泡的事件给祖先元素。
【onmouseenter】
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title> </head><body><button id="btn">按我创建一个新列表项</button><ul id="list"><li>列表项</li><li>列表项</li><li>列表项</li></ul><script>var oList = document.getElementById('list');var oBtn = document.getElementById('btn');// onmouseenter这个属性天生就是“不冒泡”的,相当于你事件处理函数附加给了那个DOM节点// 就是哪个DOM节点自己触发的事件,没有冒泡过程// 再因为继承性,所以所有 li 会一起变色(CSS 中的继承:子标签会继承父标签的某些样式,// 如:文本颜色和字号,简单的理解就是:子承父业。)oList.onmouseenter = function (e) {// e.target表示用户真正点击的那个元素e.target.style.color = 'red';};// oList.onmouseover = function (e) {// // e.target表示用户真正点击的那个元素,即:那个 li// e.target.style.color = 'red';// };oBtn.onclick = function () {// 创建新的li元素var oLi = document.createElement('li');// 写内容oLi.innerText = '我是新来的';// 上树oList.appendChild(oLi);};</script> </body></html>
【onmouseover】
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title> </head><body><button id="btn">按我创建一个新列表项</button><ul id="list"><li>列表项</li><li>列表项</li><li>列表项</li></ul><script>var oList = document.getElementById('list');var oBtn = document.getElementById('btn');// onmouseenter这个属性天生就是“不冒泡”的,相当于你事件处理函数附加给了那个DOM节点// 就是哪个DOM节点自己触发的事件,没有冒泡过程// 再因为继承性,所以所有 li 会一起变色// oList.onmouseenter = function (e) {// // e.target表示用户真正点击的那个元素// e.target.style.color = 'red';// };oList.onmouseover = function (e) {// e.target表示用户真正点击的那个元素,即:那个 lie.target.style.color = 'red';};oBtn.onclick = function () {// 创建新的li元素var oLi = document.createElement('li');// 写内容oLi.innerText = '我是新来的';// 上树oList.appendChild(oLi);};</script> </body></html>
(2)最内层元素不能再有额外的内层元素了,比如:
这会导致点击 li 时效果正常,但是点击 span 时,只有 span 会变色。
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title> </head><body><button id="btn">按我创建一个新列表项</button><ul id="list"><li><span>我是span</span>列表项</li><li><span>我是span</span>列表项</li><li><span>我是span</span>列表项</li><li><span>我是span</span>列表项</li><li><span>我是span</span>列表项</li></ul><script>var oList = document.getElementById('list');var oBtn = document.getElementById('btn');oList.onmouseover = function (e) {// e.target表示用户真正点击的那个元素,即:那个 lie.target.style.color = 'red';};oBtn.onclick = function () {// 创建新的li元素var oLi = document.createElement('li');// 写内容oLi.innerText = '我是新来的';// 上树oList.appendChild(oLi);};</script> </body></html>
十三、定时器和延时器
13.1 定时器
setInterval()
函数可以重复调用一个函数,在每次调用之间有固定的时间间隔。
Interval:间隔
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title> </head><body><script>var a = 0;setInterval(function () {console.log(++a);}, 1000);</script> </body></html>
13.2 函数的参数
setInterval()
函数可以接收第 3、4、…… 个参数,它们将按顺序传入函数。
13.3 具名函数也可以传入setInterval
具名函数也可以传入 setInterval
。
具名函数:有名称的函数。
匿名函数:无名称的函数。
13.4 清除定时器
clearInterval()
函数可以清除一个定时器。
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title> </head><body><h1 id="info">0</h1><button id="btn1">开始</button><button id="btn2">暂停</button><script>var oInfo = document.getElementById('info');var oBtn1 = document.getElementById('btn1');var oBtn2 = document.getElementById('btn2');var a = 0;// 全局变量var timer;oBtn1.onclick = function () {// 更改全局变量 timer 的值为一个定时器实体timer = setInterval(function () {oInfo.innerText = ++a;}, 1000);};oBtn2.onclick = function () {clearInterval(timer);};</script> </body></html>
但是,此时有一个 BUG,那就是当重复点击时,会发生定时器叠加。
定时器叠加:同一时间有多个定时器在同时工作。
改进:
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title> </head><body><h1 id="info">0</h1><button id="btn1">开始</button><button id="btn2">暂停</button><script>var oInfo = document.getElementById('info');var oBtn1 = document.getElementById('btn1');var oBtn2 = document.getElementById('btn2');var a = 0;// 全局变量var timer;oBtn1.onclick = function () {// 为了防止定时器叠加,我们应该在设置定时器之前先清除定时器clearInterval(timer);// 更改全局变量timer的值为一个定时器实体timer = setInterval(function () {oInfo.innerText = ++a;}, 1000);};oBtn2.onclick = function () {clearInterval(timer);};</script> </body></html>
13.5 延时器
setTimeout()
函数可以设置一个延时器,当指定时间到了之后,会执行函数一次,不再重复执行。
13.6 清除延时器
clearTimeout()
函数可以清除延时器,和 clearInterval()
非常类似。
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title> </head><body><button id="btn1">2秒后弹出你好</button><button id="btn2">取消弹出</button><script>var btn1 = document.getElementById('btn1');var btn2 = document.getElementById('btn2');var timer;btn1.onclick = function () {timer = setTimeout(function () {alert('你好');}, 2000);}btn2.onclick = function () {clearTimeout(timer);}</script> </body></html>
13.7 初步认识异步语句
setInterval()
和 setTimeout()
是两个异步语句。
异步(asynchronous):不会阻塞 CPU 继续执行其他语句,当异步完成时,会执行 “回调函数”(callback)。
13.8 使用定时器实现动画*(课后练习)
动画是网页上非常常见的业务需求。
使用定时器实现动画就是利用 “视觉暂留” 原理。
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>#box {position: absolute;top: 100px;left: 100px;width: 100px;height: 100px;background-color: orange;}</style> </head><body><button id="btn">开始运动</button><div id="box"></div><script>// 得到元素var btn = document.getElementById('btn');var box = document.getElementById('box');// 全局变量盒子的left值var left = 100;// 按钮监听btn.onclick = function () {var timer = setInterval(function () {// 改变全局变量left += 10;if (left >= 1000) {clearInterval(timer);}// 设置left属性box.style.left = left + 'px';}, 20);};</script> </body></html>
【BOM】
一、BOM是什么
BOM(Browser Object Model,浏览器对象模型)是 JS 与 浏览器窗口交互的接口。
一些与浏览器改变尺寸、滚动条滚动相关的特效,都要借助 BOM 技术。
二、window对象
window 对象是当前 JS 脚本运行所处的窗口,而这个窗口中包含 DOM 结构,window.document
属性就是 document
对象。
在有标签功能的浏览器中,每个标签都拥有自己的 window
对象;也就是说,同一个窗口的标签页之间不会共享一个 window 对象。
三、全局变量是window的属性
全局变量会成为 window 对象的属性。
var a = 10; console.log(window.a == a); // true
这就意味着,多个 js 文件之间是共享全局作用域的,即:js 文件没有作用域隔离功能。
//test.js 文件 var a = 10;<!DOCTYPE html> <html lang="en"> <head><script src="./test.js"></script> </head> <body><script>//在测试页面中引入test.js后,展示a的值alert(a);</script> </body> </html>
效果:
四、内置函数普遍是window的方法
如 setInterval()
、alert()
等内置函数,普遍是 window 的方法。
console.log(window.alert == alert); // true console.log(window.setInterval == setInterval); // true
五、窗口尺寸相关属性
属性 | 意义 |
---|---|
innerHeight | 浏览器窗口的内容区域的高度,包含水平滚动条(如果有的话) |
innerWidth | 浏览器窗口的内容区域的宽度,包含垂直滚动条(如果有的话) |
outerHeight | 浏览器窗口的外部高度 |
outerWidth | 浏览器窗口的外部宽度 |
获得不包含滚动条的窗口宽度,要用:
document.documentElement.clientWidth
浏览器的外宽指的是浏览器窗口边框的宽度。
当浏览器窗口全屏时:浏览器的外宽 == 浏览器内宽(包含滚动条)
当浏览器窗口不全屏时:浏览器的外宽 > 浏览器内宽(包含滚动条)
六、resize事件
在窗口大小改变之后,就会触发 resize
事件,可以使用 window.onresize
或者 window.addEventListener('resize')
来绑定事件处理函数。
七、已卷动高度
window.scrollY
属性表示在垂直方向已滚动的像素值。
document.documentElement.scrollTop
属性也表示窗口卷动高度。
// 可以利用此种方式获得窗口卷动的高度 var scrollTop = window.scrollY || document.documentElement.scrollTop;
-
document.documentElement.scrollTop 是可以手动给定值的,以达到跳动到任何指定滚动高度处
-
window.scrollY 是只读的,不可以手动给值
<!DOCTYPE html> <html lang="en"><head><style>div{width: 200px;height: 200px;background-color: pink;}</style> </head><body><div></div><div></div><div></div><script>//在测试页面中引入test.js后,展示a的值console.log(window.scrollY);</script> </body></html>
效果:
八、scroll事件
在窗口被卷动之后,就会触发 scroll 事件,可以使用:
window.onscroll
或者 window.addEventListener('scroll')
来绑定事件处理函数。
<!DOCTYPE html> <html lang="en"><head><style>div{width: 200px;height: 200px;background-color: pink;}</style> </head><body><div></div><div></div><div></div><script>//在测试页面中引入test.js后,展示a的值window.οnscrοll=function(){console.log(window.scrollY);}</script> </body></html>
效果:
九、Navigator对象
window.navigator
属性可以检索 navigator 对象,它内部含有用户此次活动的浏览器的相关属性和标识。
属性 | 意义 |
---|---|
appName | 浏览器官方名称 |
appVersion | 浏览器版本 |
userAgent | 浏览器用户代理(含有内核信息和封装壳信息) |
platform | 用户操作系统 |
【案例】
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title> </head> <body><script>console.log('浏览器品牌', navigator.appName);console.log('浏览器版本', navigator.appVersion);console.log('用户代理', navigator.userAgent);console.log('操作系统', navigator.platform);</script> </body> </html>
十、识别用户浏览器品牌
识别用户浏览器品牌通常使用 navigator.userAgent
属性。
var sUsrAg = navigator.userAgent; //indexOf用于检查一个字符串中是否包含"Firefox"这个子字符串。 //如果包含,indexOf方法会返回第一次出现的位置的索引,否则返回-1 if (sUsrAg.indexOf("Firefox") > -1) { } else if (sUsrAg.indexOf("Opera") > -1) { } else if (sUsrAg.indexOf("Edge") > -1) { } else if (sUsrAg.indexOf("Chrome") > -1) { } else if (sUsrAg.indexOf("Safari") > -1) { } else { }
十一、History对象
window.history
对象提供了操作浏览器会话历史的接口。
常用操作就是模拟浏览器回退按钮。
history.back(); // 等同于点击浏览器的回退按钮 history.go(-1); // 等同于 history.back();
【案例】
-
temp.html
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title> </head><body><h1>我是temp网页</h1><a href="history方法.html">去看history方法页面</a> </body></html>
-
history.html
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title> </head><body><h1>我是history方法网页</h1><button id="btn">回退</button><!-- 链接可以使用内嵌 javascript 脚本的方式 --><a href="javascript:history.back();">链接:回退</a><script>var btn = document.getElementById('btn');btn.onclick = function () {// history.back();history.go(-1);};</script> </body></html>
十二、Location对象
window.location
标识当前所在网址,可以通过给这个属性赋值命令浏览器进行页面跳转。
window.locaiton = 'http://www.imooc.com'; window.location.href = 'http://www.imooc.com';
十三、重新加载当前页面
可以调用 location 的 reload
方法以重新加载当前页面,参数 true 表示强制从服务器强制加载。
window.location.reload(true);
【案例】
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title> </head><body><button id="btn1">点我去看慕课</button><button id="btn2">刷新</button><script>var btn1 = document.getElementById('btn1');var btn2 = document.getElementById('btn2');btn1.onclick = function () {window.location = 'http://www.imooc.com';};btn2.onclick = function () {window.location.reload(true);};</script> </body></html>
十四、GET请求查询参数
window.location.search
属性即为当前浏览器的 GET 请求查询参数。
比如网址:慕课网-程序员的梦工厂
console.log(window.location.search); // "?a=1&b=2"
关于 GET 及 POST 的详细内容在 Ajax 中介绍。
十五、BOM特效开发
15.1 返回顶部按钮制作*(课后练习)
返回顶部的原理:改变 document.documentElement.scrollTop
属性,通过定时器逐步改变此值,则将用动画形式返回顶部。
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>body {height: 5000px;background-image: linear-gradient(to bottom, rgb(255, 0, 149), rgb(7, 185, 255), rgb(0, 255, 76));}.backtotop {width: 60px;height: 60px;background-color: rgba(255, 255, 255, .6);position: fixed;bottom: 100px;right: 100px;/* 小手状 */cursor: pointer;}</style> </head><body><div class="backtotop" id="backtotopBtn">返回顶部</div><script>var backtotopBtn = document.getElementById('backtotopBtn');var timer;backtotopBtn.onclick = function () {// 设表先关clearInterval(timer);// 设置定时器timer = setInterval(function () {// 不断让scrollTop减少document.documentElement.scrollTop -= 200;// 定时器肯定要停if (document.documentElement.scrollTop <= 0) {clearInterval(timer);}}, 20);};</script> </body></html>
15.2 楼层导航小效果*(选学)
DOM 元素都有 offsetTop
属性,表示此元素到定位祖先元素的垂直距离。
定位祖先元素:在祖先中,离自己最近的且拥有定位属性的元素。
即:offsetTop 属性可以得到该元素与离自己最近且拥有定位的祖先元素顶部的距离值。
假如,没有祖先有定位,那么直接得到该元素距离页面顶部的距离值。
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>* {margin: 0;padding: 0;}.content-part {width: 1000px;margin: 0px auto;margin-bottom: 30px;background-color: #ccc;font-size: 50px;}.floornav {position: fixed;right: 40px;top: 50%;margin-top: -100px;width: 120px;height: 200px;background-color: orange;}.floornav ul {list-style: none;}.floornav ul li {width: 120px;height: 40px;line-height: 40px;text-align: center;font-size: 26px;/* 小手指针 */cursor: pointer;}.floornav ul li.current {background: purple;color: white;}</style> </head><body><nav class="floornav"><ul id="list"><li data-n="科技" class="current">科技</li><li data-n="体育">体育</li><li data-n="新闻">新闻</li><li data-n="娱乐">娱乐</li><li data-n="视频">视频</li></ul></nav><section class="content-part" style="height:674px;" data-n="科技">科技栏目</section><section class="content-part" style="height:567px;" data-n="体育">体育栏目</section><section class="content-part" style="height:739px;" data-n="新闻">新闻栏目</section><section class="content-part" style="height:574px;" data-n="娱乐">娱乐栏目</section><section class="content-part" style="height:1294px;" data-n="视频">视频栏目</section><script>// 使用事件委托给li添加监听var list = document.getElementById('list');var contentParts = document.querySelectorAll('.content-part');var lis = document.querySelectorAll('#list li');list.onclick = function (e) {if (e.target.tagName.toLowerCase() == 'li') {// getAttribute表示得到标签身上的某个属性值var n = e.target.getAttribute('data-n');// 可以用属性选择器(就是方括号选择器)来寻找带有相同data-n的content-partvar contentPart = document.querySelector('.content-part[data-n=' + n + ']');// 让页面的卷动自动成为这个盒子的offsetTop值document.documentElement.scrollTop = contentPart.offsetTop;}}// 在页面加载好之后,将所有的content-part盒子的offsetTop值推入数组var offsetTopArr = [];// 遍历所有的contentPart,将它们的净位置推入数组for (var i = 0; i < contentParts.length; i++) {offsetTopArr.push(contentParts[i].offsetTop);}// 为了最后一项可以方便比较,我们可以推入一个无穷大offsetTopArr.push(Infinity);console.log(offsetTopArr);// 当前所在楼层var nowfloor = -1;// 窗口的卷动window.onscroll = function () {// 得到当前的窗口卷动值var scrollTop = document.documentElement.scrollTop;// 遍历offsetTopArr数组,看看当前的scrollTop值在哪两个楼层之间for (var i = 0; i < offsetTopArr.length; i++) {if (scrollTop >= offsetTopArr[i] && scrollTop < offsetTopArr[i + 1]) {break;}}// 退出循环的时候,i是几,就表示当前楼层是几// 如果当前所在楼层,不是i,表示环楼了if (nowfloor != i) {console.log(i);// 让全局变量改变为这个楼层号nowfloor = i;// 设置下标为i的项有curfor (var j = 0; j < lis.length; j++) {if (j == i) {lis[j].className = 'current';} else {lis[j].className = '';}}}};</script> </body></html>
相关文章:

JavaScript——(4)
【DOM】 一、DOM基本概念 DOM(Document Object Model,文档对象模型)是 JavaScript 操作 HTML 文档的接口,使文档操作变得非常优雅、简便。 DOM 最大的特点就是将 HTML 文档表示为 “节点树”。 DOM 元素/节点:就是…...

每日一练 | DHCP Relay(DHCP 中继)
01 真题题目 DHCP Relay 又称为 DHCP 中继,下列关于 DHCP Relay 的说法正确的是(多选): A. DHCP 协议多采用广播报文,如果出现多个子网则无法穿越,所以需要 DHCP Relay 设备。 B. DHCP Relay 一定是一台交…...

`psdparse`:解锁Photoshop PSD文件的Python密钥
文章目录 psdparse:解锁Photoshop PSD文件的Python密钥背景:为何选择psdparse?psdparse是什么?如何安装psdparse?简单函数使用方法应用场景常见Bug及解决方案总结 psdparse:解锁Photoshop PSD文件的Python密…...

考研要求掌握的C语言程度(插入排序)
插入排序是啥类型的排序 插入类型的 插入排序经常用在啥类型场景下 用在有序序列下的基础上插入新数据 时间复杂度分析 如果是有序的基础下,最好的时间复杂度是O(n); 普通情况下是O(n^2) 插入排序的原理是啥&am…...

mybatis源码解析-sql执行流程
1 执行器的创建 1. SimpleExecutor 描述:最基本的执行器,每次查询都会创建新的语句对象,并且不会缓存任何结果。 特点: 每次查询都会创建新的 PreparedStatement 对象。 不支持一级缓存。 适用于简单的查询操作,不…...

Golang | Leetcode Golang题解之第538题把二叉搜索树转换为累加树
题目: 题解: func getSuccessor(node *TreeNode) *TreeNode {succ : node.Rightfor succ.Left ! nil && succ.Left ! node {succ succ.Left}return succ }func convertBST(root *TreeNode) *TreeNode {sum : 0node : rootfor node ! nil {if n…...

【linux】HTTPS 协议原理
1. 了解 HTTPS 协议原理 (一)认识 HTTPS HTTPS 也是一种应用层协议,是在 HTTP 协议的基础上引入了一个加密层 因为 HTTP协议的内容都是按照文本的方式进行传输的,这个过程中,可能会出现一些篡改的情况 (…...

安利一款开源企业级的报表系统SpringReport
SpringReport是一款企业级的报表系统,支持在线设计报表,并绑定动态数据源,无需写代码即可快速生成想要的报表,可以支持excel报表和word报表两种格式,同时还可以支持excel多人协同编辑,后续考虑实现大屏设计…...

数据安全-接口数据混合加密笔记
接口数据传输安全设计方案 采用非对称加密对称加密混合方式,接口混合加、解密过程梳理: 后端准备sm2公钥和私钥后端将SM2公钥传输到前端前端生成SM4密钥前端使用SM2公钥加密SM4秘钥,获得密文使用SM4秘钥加密数据将密文和加密数据传输至后端…...

JeecgBoot入门
最近在了解低代码平台,其中关注到gitee上开源项目JeecgBoot,JeecgBoot官方也有比较完整的入门教学文档,这里我们将耕者官方教程学习,并将其记录下来。 一、项目简介 JeecgBoot 是一款基于代码生成器的低代码开发平台拥有零代码能力…...

用 Vue.js 打造炫酷的动态数字画廊:展示学生作品的创意之旅
✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏…...

【YOLO学习】YOLOv8改进举例
文章目录 1. ODConv1.1 修改1.2 原yaml文件1.3 修改yaml文件样式11.4 修改yaml文件样式2 2. DAT3. 在train下修改模型 1. ODConv 1.1 修改 1. 在ultralytics/nn/models里创建ODConv.py文件。 2. 在ultralytics/nn/task.py中导入from .modules.ODConv import C2f_ODConv,ODConv…...

文心一言 VS 讯飞星火 VS chatgpt (383)-- 算法导论24.5 3题
三、对引理 24.10 的证明进行改善,使其可以处理最短路径权重为 ∞ ∞ ∞ 和 − ∞ -∞ −∞ 的情况。引理 24.10(三角不等式)的内容是:设 G ( V , E ) G(V,E) G(V,E) 为一个带权重的有向图,其权重函数由 w : E → R w:E→R w:E→R 给出&…...

【AIGC】如何通过ChatGPT轻松制作个性化GPTs应用
博客主页: [小ᶻZ࿆] 本文专栏: AIGC | GPTs应用实例 文章目录 💯前言💯什么是GPTsGPTs的工作原理GPTs的优势GPTs的应用前景总结 💯创建GPTS应用的基本流程进入GPTs创建界面方式一:按照引导完成生成创建GPTs方式二…...

gulp入门教程2:gulp发展历史
早期阶段(2013年-2014年) 诞生背景:随着前端开发复杂度的增加,开发者们开始寻求自动化工具来简化构建流程。2013年,由Fractal Innovations的Eric Schoffstall首次发布。它借鉴了Unix管道的流式处理思想,通…...

【实验八】前馈神经网络(4)优化问题
1 参数初始化 模型构建 模型训练 优化 完整代码 2 梯度消失问题 模型构建 模型训练 完整代码 3 死亡Relu问题 模型构建 模型训练 优化 完整代码 1 参数初始化 实现一个神经网络前,需要先初始化模型参数。如果对每一层的权重和偏置都用0初始化࿰…...

【深度学习】论文笔记:空间变换网络(Spatial Transformer Networks)
博主简介:努力学习的22级计算机科学与技术本科生一枚🌸博主主页: Yaoyao2024往期回顾: 【机器学习】有监督学习由浅入深讲解分类算法Fisher算法讲解每日一言🌼: 今天不想跑,所以才去跑,这才是长…...

Charles抓包_Android
1.下载地址 2.破解方法 3.安卓调试办法 查看官方文档,Android N之后抓包要声明App可用User目录下的CA证书 3.1.在Proxy下进行以下设置(路径Proxy->Proxy Settings) 3.1.1.不抓包Windows,即不勾选此项,免得打输出不…...

【MATLAB源码-第204期】基于matlab的语音降噪算法对比仿真,谱减法、维纳滤波法、自适应滤波法;参数可调。
操作环境: MATLAB 2022a 1、算法描述 语音降噪技术的目的是改善语音信号的质量,通过减少或消除背景噪声,使得语音更清晰,便于听者理解或进一步的语音处理任务,如语音识别和语音通讯。在许多实际应用中,如…...

Scala的包及其导入
//1.单个导入 //import com.sala02.A //import com.sala02.B //2.导入多个类 //import com.sala02.{A,B} //3.导入一个包下的所有类:包名._ //import com.sala02._ //4.导入一个包中的类,给他改个名字 //格式:import 包名.{原来的名字 > 新…...

deepfm模型实现招聘职位推荐算法
项目源码获取方式见文章末尾! 600多个深度学习项目资料,快来加入社群一起学习吧。 《------往期经典推荐------》 项目名称 1.【基于CNN-RNN的影像报告生成】 2.【卫星图像道路检测DeepLabV3Plus模型】 3.【GAN模型实现二次元头像生成】 4.【CNN模型实现…...

编程之路:蓝桥杯备赛指南
文章目录 一、蓝桥杯的起源与发展二、比赛的目的与意义三、比赛内容与形式四、比赛前的准备五、获奖与激励六、蓝桥杯的影响力七、蓝桥杯比赛注意事项详解使用Dev-C的注意事项 一、蓝桥杯的起源与发展 蓝桥杯全国软件和信息技术专业人才大赛,简称蓝桥杯,…...

Android 15 在状态栏时间中显示秒数
这是更新后的博客草稿,关于在Android 15状态栏中显示秒数的实现: 在Android 15状态栏中显示秒数 在Android 15中,您可以通过两种方式在状态栏中显示秒数:使用ADB命令或修改系统源代码。下面详细介绍这两种方法。 方法一:通过ADB实现 您可以使用ADB(Android调试桥)命令…...

Flutter 鸿蒙next版本:自定义对话框与表单验证的动态反馈与错误处理
在现代移动应用开发中,用户体验是至关重要的一环。Flutter和鸿蒙操作系统(HarmonyOS)的结合,为开发者提供了一个强大的平台,以创建跨平台、高性能的应用程序。本文将探讨如何在Flutter与鸿蒙next版本中创建自定义对话框…...

Unreal Engine5中使用 Lyra框架
UE5系列文章目录 文章目录 UE5系列文章目录前言一、Lyra和AIS框架的区别二、下载官方Lyra游戏示例三、Lyra在动画蓝图中的使用 前言 Unreal Engine 5(UE5)提供了多种用于游戏开发的模板和框架,其中Lyra和AlS是两个不同的示例项目,…...

Spring Security-02-Spring Security认证方式-HTTP基本认证、Form表单认证、HTTP摘要认证、前后端分离安全处理方案
Lison <dreamlison163.com>, v1.0.0, 2024.06.01 Spring Security-02-Spring Security认证方式-HTTP基本认证、Form表单认证、HTTP摘要认证、前后端分离安全处理方案 文章目录 Spring Security-02-Spring Security认证方式-HTTP基本认证、Form表单认证、HTTP摘要认证、…...

【scikit-learn 1.2版本后】sklearn.datasets中load_boston报错 使用 fetch_openml 函数来加载波士顿房价
ImportError: load_boston has been removed from scikit-learn since version 1.2. 由于 load_boston 已经在 scikit-learn 1.2 版本中被移除,需要使用 fetch_openml 函数来加载波士顿房价数据集。 # 导入sklearn数据集模块 from sklearn import datasets # 导入波…...

vxe-table v4.8+ 与 v3.10+ 导出 xlsx、支持导出合并、设置样式、宽高、边框、字体、背景、超链接、图片的详细介绍,一篇就够了
Vxe UI vue vxe-table v4.8 与 v3.10 导出 xlsx、支持导出合并、设置样式、宽高、边框、字体、背景、超链接、图片等、所有常用的 Excel 格式都能自定义,使用非常简单,纯前端实现复杂的导出。 安装插件 npm install vxe-pc-ui4.2.39 vxe-table4.8.0 vx…...

江协科技STM32学习- P36 SPI通信外设
🚀write in front🚀 🔎大家好,我是黄桃罐头,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流 🎁欢迎各位→点赞👍 收藏⭐️ 留言📝…...

【大数据】ClickHouse常见的表引擎及建表语法
ClickHouse 中最强大的表引擎当属 MergeTree (合并树)引擎及该系列(*MergeTree)中的其他引擎。接下来我们就仔细了解下MergeTree 及该系列的其他引擎的使用场景及建表语法。 MergeTree MergeTree 系列的引擎被设计用于插入极大量…...