回顾
操作样式:
div: dom.style.css属性名(遇到连字符,转化为驼峰命名)行内样式;
操作文本:
- innerText:单纯操作文本,不会解析HTML结构字符串
 - innerHTML:解析HTML结构字符串
 - document.write(“解析HTML结构字符串”)
 
作用:从body尾部添加结构;
时间对象:ES语法提供方法; nodejs不能用document、能用时间对象;(了解)
得到时间对象:
- let time = new Date(当前系统时间对象
 - let time = new Date(“2012-4-5 12:53:45”)指定的时间对象
 
方法
- 常用:getFu11Year O;getMonth();getDateO; ….
 - 时间戳:
 
Web APIs - 第2天
理解高阶函数的本质并知道常见的高阶函数的使用,学会通过为DOM注册事件来实现可交互的网页特效。
- 理解高函数的本质,知识常见高阶函数的使用
 - 知道什么是回调函数,能够在事件中应用回调函数
 - 能够判断函数运行的环境并确字 this 所指代的对象
 - 理解事件的作用,知道应用事件的 3 个步骤
 - 理解什么是伪数组,通过遍历批量处理 DOM 节点
 
一、高阶函数
理解高阶函数的本质,知道常见的高阶函数的使用。
高阶函数可以被简单理解为函数的高级应用,JavaScript 中函数可以被当成【值】来对待,基于这个特性实现函数的高级应用。
【值】就是 JavaScript 中的数据,如数值、字符串、布尔、对象等。
1.1 函数表达式
将函数赋值给变量,即函数表达式。
函数分为具名函数和匿名函数,具名函数是指函数要有具体的名称,匿名函数是指没有名字的函数。
<script>// 1. 具名函数function foo() {console.log('foo 函数被执行...');}// 将函数 foo 赋值给变量 anotherFoolet anotherFoo = foo;anotherFoo(); // 相当在于调用 foo 函数// 2. 匿名函数let bar = function () {console.log('声明函数时没有名字...');}// 调用函数bar();</script>
函数表达式和普通函数并无本质上的区别:
<script>// 函数表达式与普通函数本质上是一样的let counter = function (x, y) {return x + y;}// 调用函数let result = counter(5, 10);console.log(result);</script>
但有一个细节需要必须要知道,普通函数的声明和调用并无顺序限制。
<script>// 声明函数前调用sayHi('小明');// 普通函数function sayHi(name) {return `嗨~ ${name}`;}</script>
结论:
- 函数表达式与普通函数的使用完全一致
 - 普通函数的声明与调用无顺序限制,推荐做法先声明再调用
 - 函数表达式必须要先声明再调用
 
1.3 回调函数
如果将函数 A 做为参数传递给函数 B 时,我们称函数 A 为回调函数。
<script>// 声明 foo 函数function foo(arg) {console.log(arg);}// 普通的值做为参数foo(10);foo('hello world!');foo(['html', 'css', 'javascript']);function bar() {console.log('函数也能当参数...');}// 函数也可以做为参数!!!!foo(bar);</script>
函数 bar 做参数传给了 foo 函数,bar 就是所谓的回调函数了!!!
我们回顾一下间歇函数 setInterval
<script>function fn() {console.log('我是回调函数...');}// 调用定时器setInterval(fn, 1000);</script>
fn 函数做为参数传给了 setInterval ,这便是回调函数的实际应用了,结合刚刚学习的函数表达式上述代码还有另一种更常见写法。
<script>// 调用定时器,匿名函数做为参数setInterval(function () {console.log('我是回调函数...');}, 1000);</script>
结论:
- 回调函数本质还是函数,只不过把它当成参数使用
 - 使用匿名函数做为回调函数比较常见
 
二、环境对象
能够分析判断函数运行在不同环境中 this 所指代的对象。
环境对象指的是函数内部特殊的变量 this ,它代表着当前函数运行时所处的环境。
<script>// 声明函数function sayHi() {// this 是一个变量console.log(this);}// 声明一个对象let user = {name: '张三',sayHi: sayHi // 此处把 sayHi 函数,赋值给 sayHi 属性}let person = {name: '李四',sayHi: sayHi}// 直接调用sayHi(); // windowwindow.sayHi(); // window// 做为对象方法调用user.sayHi(); // userperson.sayHi(); // person</script>
结论:
this本质上是一个变量,数据类型为对象- 函数的调用方式不同 
this变量的值也不同 - 【谁调用 
this就是谁】是判断this值的粗略规则 - 函数直接调用时实际上 
window.sayHi()所以this的值为window 
三、DOM
学习会为 DOM 注册事件,实现简单可交互的网页特交。
3.1 事件
事件是编程语言中的术语,它是用来描述程序的行为或状态的,一旦行为或状态发生改变,便立即调用一个函数。
例如:用户使用【鼠标点击】网页中的一个按钮、用户使用【鼠标拖拽】网页中的一张图片
3.2 事件监听
结合 DOM 使用事件时,需要为 DOM 对象添加事件监听,等待事件发生(触发)时,便立即调用一个函数。
addEventListener 是 DOM 对象专门用来添加事件监听的方法,它的两个参数分别为【事件类型】和【事件回调】。
设置事件监听
- DOM.on事件类名=function(){}
 - onclick DOM节点上固定好属性名 onclick 配置哨兵
 
<script>//需求:用户点击按钮,弹窗显示文字//步骤:1.获取dom节点let bth = document.getElementById('bth')//2.语法知识:设置时间监听的(配置哨兵)// addEventListener方法//add:添加// Event:事件// Listener:监听者// 参数1:事件类型,字符串,click点击:单击// 参数2:当用户发生这个事件的时候,需要执行的函数/* bth: addEventListener("click", function () {console.log(1)}) *///设置事件监听// DOM.on事件类名=function(){}// onclick DOM节点上固定好属性名 onclick 配置哨兵bth.onclick = function () {console.log(2)}//事件是什么?/* 如何给DOM节点添加事件监听DOM.addEventListener("事件类型",执行函数)DOM.on事件类型=执行函数 */</script>
完成事件监听分成3个步骤:
- 获取 DOM 元素
 - 通过 
addEventListener方法为 DOM 节点添加事件监听 - 等待事件触发,如用户点击了某个按钮时便会触发 
click事件类型 - 事件触发后,相对应的回调函数会被执行
 
大白话描述:所谓的事件无非就是找个机会(事件触发)调用一个函数(回调函数)。
案例:开关灯案例
<style>#box {width: 600px;height: 400px;border: 1px solid #000;margin: 100px auto;background-color: #666;}</style></head><body><div id="box"><button id="open">开灯</button><button id="close">关灯</button></div><script>//需求:当用户点击关灯的时候,页面背景色变黑//1.获取DOM节点let close = document.getElementById("close")let open = document.getElementById("open")let body = document.body//2.添加事件监听//关灯close.addEventListener("click", function () {body.style.backgroundColor = "black";})//开灯open.addEventListener("click", function () {body.style.backgroundColor = "orange";})</script>
事件类型
click 译成中文是【点击】的意思,它的含义是监听(等着)用户鼠标的单击操作,除了【单击】还有【双击】dblclick
<button id="bth">按钮</button><input type="text" id="ipt"><script>//1.获取DOM// let bth = document.getElementById("bth")// 2.添加事件监听bth.addEventListener("dblclick", function () {alert(1)});//输入框:事件类型 获取聚焦 focus 失去焦点blur 一般输入框|文本域// 添加事件监听,可以添加多个的// 事件类型如果写错了,没有任何反应;经验值let ipt = document.getElementById("ipt")ipt.addEventListener("focus", function () {console.log(1)})ipt.addEventListener("blur", function () {console.log(2)})</script>
结论:【事件类型】决定了事件被触发的方式,如 click 代表鼠标单击,dblclick 代表鼠标双击。
事件回调
addEventListener 的第2个参数是函数,这个函数会在事件被触发时立即被调用,在这个函数中可以编写任意逻辑的代码,如改变 DOM 文本颜色、文本内容等。
<script>// 双击事件类型btn.addEventListener('dblclick', function () {console.log('等待事件被触发...');let text = document.getElementById('text');// 改变 p 标签的文字颜色text.style.color = 'red';// 改变 p 标签的文本内容text.style.fontSize = '20px';})</script>
结论:【回调函数】决定了事件触发后应该执行的逻辑。
任何函数内部都有特殊的变量 this ,那么事件回调函数中的 this 代指的是哪个对象呢?
<script>// 双击事件类型btn.addEventListener('dblclick', function () {console.log('等待事件被触发...');let text = document.getElementById('text');// 改变 p 标签的文字颜色text.style.color = 'red';// 改变 p 标签的文本内容text.style.fontSize = '20px';// 指向当前被添加事件监听的 DOM 对象console.log(this); // button 元素对应的 DOMthis.innerText = '文字颜色已改变';})</script>
结论:事件回调函数内部特殊变量 this 指向当前被添加事件监听的 DOM 对象。
控制搜索区
<style>* {margin: 0;padding: 0;}.box {position: absolute;top: 100px;left: 300px;}input {box-sizing: border-box;width: 300px;height: 56px;background-image: url('./images/search.png');padding: 4px 6px;border: 0 none;/* outline: 0 none; */font-size: 24px;}.list {border: 1px solid #ccc;position: absolute;top: 54px;left: 2px;display: none;}</style></head><body><div class="box"><input type="text" id="search"><div class="list" id="list"><img src="./images/mi.png" alt=""></div></div></body><script>let search = document.getElementById("search")let list = document.getElementById("list")search.addEventListener("focus", function () {list.style.display = "block"})search.addEventListener("blur", function () {list.style.display = "none"})</script>
3.3 查找节点
JavaScript 中提供了多种获取元素节点的方法,除了 document.getElementById 外,还有使用更多的方法查找节点。
伪数组
伪数组在形式上具有数组的特征,能够像数组一样使用,然而本质上并不是数组,故称其为伪数组,伪数组无法使用真数组的方法,但是可以像真数组那样通过索引值去访问数组中的单元,也具有 length 属性能够计算伪数组单位的个数。
document.getElementsByClassName根据类名查找节点,获得的节点是以伪数组形式存在,其用法如下代码所示:
<script>// 获取类名为 box 的所有元素let boxes = document.getElementsByClassName('box');// 页面中类名为 box 的盒子有3个,boxes 中包含了多个 DOM 对象console.log(boxes);// boxes 在形式上看是一个数组,且具有数组的特征,能够像数组一样使用// 然而本质上并不是数组,故称其为伪数组。// 通过索引值,分别访问伪数组中的 DOM 对象boxes[0].style.color = 'red';boxes[1].style.backgroundColor = 'pink';boxes[2].innerText = 'Third box';</script>
document.getElementsByTagName根据标签名查找节点,实际应用较少,获得的节点是以伪数组形式存在,其用法如下代码所示:
<script>// 获取标签名为 div 的所有元素let boxes = document.getElementsByTagName('div');// 页面中标签名为 div 的盒子有3个,boxes 中也包含了多个 DOM 对象console.log(boxes);// boxes 在形式上看是一个数组,且具有数组的特征,能够像数组一样使用// 然而本质上并不是数组,故称其为伪数组。// 通过索引值,分别访问伪数组中的 DOM 对象boxes[0].style.color = 'red';boxes[1].style.backgroundColor = 'pink';boxes[2].innerText = 'Third box';</script>
document.getElementsByName根据标签的name属性查找节点,实际应用较少,获得的节点以伪数组形式存在,其用法如下代码所示:
<script>// 获取 name 属性值为 username 的元素let input = document.getElementsByName('username');// 只有1个 DOM 对象,也以伪数组存在console.log(input);// 修改边框颜色input[0].style.border = '1px solid red';</script>
结论:
document.getElementsByClassName根据类名获取 DOM 节点document.getElementsByTagName根据标签名获取 DOM 节点document.getElementsByName根据 name 属性获取 DOM 节点
注:上述方法查找节点时即使只有一个节点,也是以【伪数组】形式存在
遍历节点
遍历伪数组实现节点的批量操作。
<title>遍历节点</title></head><body><h3>遍历节点</h3><p>遍历伪数组实现节点的批量操作。</p><ul><li>体育新闻</li><li>娱乐新闻</li><li>科技新闻</li><li>财经新闻</li></ul><script>// 1. 获取所有需要添加事件监听的元素let lis = document.getElementsByTagName('li');// 2. 为伪数组中每一个 DOM 对象添加事件监听// 笨方法,当然不推荐!!!// lis[0].addEventListener('click', function () {});// lis[1].addEventListener('click', function () {});// lis[2].addEventListener('click', function () {});// 2. 遍历数组,精简代码!// 遍历伪数组中所有 DOM 对象for(let i = 0; i < lis.length; i++) {// console.log(lis[i]);let li = lis[i];// 为所有 li 添加单击事件监听li.addEventListener('click', function () {console.log('点击了...');// 改变被点击 li 元素的背景色this.style.backgroundColor = 'red';})}</script></body></html>
双重遍历,控制只有一个 li 元素设置了背景色
<script>// 1. 获取所有需要添加事件监听的元素let lis = document.getElementsByTagName('li');// 2. 遍历数组,精简代码!// 遍历伪数组中所有 DOM 对象for(let i = 0; i < lis.length; i++) {// console.log(lis[i]);let li = lis[i];// 为所有 li 添加单击事件监听li.addEventListener('click', function () {// 用户点击时,再次遍历伪数组for(let j = 0; j < lis.length; j++) {// 恢复所有 li 元素的背景色lis[j].style.backgroundColor = '';}// 改变被点击 li 元素的背景色this.style.backgroundColor = 'red';})}</script>
需求:每个按钮,用户点击后,让当前这个按钮背景颜色pink(blue)
<button>bth1</button><button>bth2</button><button>bth3</button><button>bth4</button><button>bth5</button><script>//需求:每个按钮,用户点击后,让当前这个按钮背景颜色pinklet bths = document.getElementsByTagName("button");// 2.每个成员需要添加事件监听bths[0].addEventListener("click", function () {//当前domthis.style.backgroundColor = "pink"})bths[1].addEventListener("click", function () {this.style.backgroundColor = "pink"})// 3.伪数组 可以遍历forfor (let i = 0; i <= bths.length; i++) {bths[i].addEventListener("click", function () {this.style.backgroundColor = 'blue'})}</script>
获取节点-Tab栏样式
<button>bth1</button><button>bth2</button><button>bth3</button><button>bth4</button><button>bth5</button><script>//需求:每一个按钮,用户点击后,让当前这个按钮背景色red//同时 ,其他按钮恢复到灰色let bth = document.querySelectorAll('button')for (let i = 0; i < bth.length; i++) {bth[i].addEventListener("click", function () {//其他按钮恢复灰色;让所有按钮恢复灰色for (let j = 0; j < bth.length; j++) {bth[j].style.backgroundColor = "#ccc"}this.style.backgroundColor = "pink"})}</script>
3.4 节点样式
动态更新 DOM 元素的样式可以有多种方式:
cssText
<body><h3>节点样式</h3><p>可以通过多种方式操作 DOM 节点的样式</p><button class="btn1">通过 cssText 操作样式</button><hr><script>// 即使只有一个节点,也是数组形式let p = document.getElementsByTagName('p');// 通过 style 操作样式let btn1 = document.getElementsByClassName('btn1');btn1[0].addEventListener('click', function () {// 一次只能操作 1 个 CSS 样式属性// p[0].style.color = 'red';// p[0].style.backgroundColor = 'pink';// 一次可以操作任意多个 CSS 样式属性p[0].style.cssText = `color: red; background-color: pink;`})</script></body>
结论:通过 style 操作 CSS 样式属性时, 借助 cssText 实现多个样式属式的同时操作。
className
<body><h3>节点样式</h3><p>可以通过多种方式操作 DOM 节点的样式</p><button class="btn2">通过 className 操作样式</button><hr><script>// 即使只有一个节点,也是数组形式let p = document.getElementsByTagName('p');// 通过 className 操作样式let btn2 = document.getElementsByClassName('btn2');btn2[0].addEventListener('click', function () {// 直接修改 DOM 元素的 classp[0].className = 'info text';})</script></body>
结论:
- 直接修改 DOM 元素的 
class属性,实现样式的操作 class在 JavaScript 中是关键字,故使用className避免冲突- 允许同时操作多个类名,中问使用空格进行分隔
 
注:通过 style 无法直接获取外联式引入的 CSS 样式,使用 window.getComputedStyle 可以获取得。
classList(后续讲解)
…
3.5 自定义属性(后续讲解)
在 HTML 中除了标签的【标准属性】外,还允许开发者【自定义属性】,自定义的属性一般用来满足开发者的逻辑需求,并不会对视觉样式产生直接的影响。如 img 标签的标准属性有 src、alt ,a 标签的标准属性有 href。
data-*
为了区分 HTML 的标准属性,要求所有的自定义属性均为 data- 做为固定的前缀,形如 data-src、data-my-info 。
<body><h3>自定义属性</h3><p>通过 data- 为 HTML 标签设置自定义属性,通过 dataset 获取 DOM 的自定义属性</p><hr><imgsrc="./javascript.gif"alt="图片加载失败"width="500"data-info="这里是自定义属性的值"data-extra="任意多个自定义属性"data-abc-bcd = '只需要以 data- 开头'></body>
上述代码中 info、extra、abc-bcd 即自定义属性,data- 是语法前缀。
dataset
自定义属性的作用是帮助完成逻辑,所以获取自定义属性尤为为重要。
<body><h3>自定义属性</h3><p>通过 data- 为 HTML 标签设置自定义属性,通过 dataset 获取 DOM 的自定义属性</p><hr><imgsrc="./javascript.gif"alt="图片加载失败"width="500"data-info="这里是自定义属性的值"data-extra="任意多个自定义属性"data-abc-bcd = '只需要以 data- 开头'><br><button class="btn1">获取自定义属性</button><script>// 获取图片元素let img = document.getElementsByTagName('img')[0];// HTML 标签的标准属性console.log(img.src);console.log(img.alt);let btn1 = document.getElementsByClassName('btn1')[0];// 1. 通过 dataset 获取所有的自定义属性btn1.addEventListener('click', function () {console.log(img.dataset); // 所有自定义属性的对象集合})</script></body>
结论:通过 DOM 节点的 dataset 属性可以获取所有的自定义属性。
<body><h3>自定义属性</h3><p>通过 data- 为 HTML 标签设置自定义属性,通过 dataset 获取 DOM 的自定义属性</p><hr><imgsrc="./javascript.gif"alt="图片加载失败"width="500"data-info="这里是自定义属性的值"data-extra="任意多个自定义属性"data-abc-bcd = '只需要以 data- 开头'><br><button class="btn1">获取自定义属性</button><button class="btn2">修改自定义属性</button><button class="btn3">添加自定义属性</button><script>// 获取图片元素let img = document.getElementsByTagName('img')[0];let btn2 = document.getElementsByClassName('btn2')[0];// 2. 通过 dataset 修改自定义属性btn2.addEventListener('click', function () {img.dataset.extra = '自定义属性的个数没有限制';img.dataset.abcBcd = 'abc-bcd 要使用驼峰命名';})let btn3 = document.getElementsByClassName('btn3')[0];// 3. 通过 dataset 添加自定义属性btn3.addEventListener('click', function () {img.dataset.another = '另一个自定义属性';img.dataset.myAage = '19';})</script></body>
自定义属性
<style>div {width: 300px;height: 300px;border: 1px solid #000;}</style></head><body><div></div><button id="btn1" data-color="red">btn1</button><button id="btn2" data-color="blue">btn2</button><button id="btn3" data-color="pink">btn3</button><button id="btn4" data-color="orange">btn4</button><button id="btn5" data-color="black">btn5</button><script>//需求:点击第一个按钮,div背景色 蓝色//步骤let div = document.querySelector("div")//意义:如果发现某个dom节点和某个数据值由明确--对应关系的手,设置值自定义属性let btn = document.querySelectorAll("button")for (let i = 0; i < btn.length; i++) {btn[i].addEventListener("click", function () {div.style.backgroundColor = this.dataset.color;})}</script>
结论:
- 通过 dataset 即可以获取自定义属性,也可以重新为自定义属性赋值
 - 通过 
dataset赋值的自定义属性不存在时,会自动添加 - 自定义属性使用 
-连接时,要采用驼峰命名规则 
