回顾
操作样式:
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 赋值给变量 anotherFoo
let 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(); // window
window.sayHi(); // window
// 做为对象方法调用
user.sayHi(); // user
person.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 元素对应的 DOM
this.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>
//需求:每个按钮,用户点击后,让当前这个按钮背景颜色pink
let bths = document.getElementsByTagName("button");
// 2.每个成员需要添加事件监听
bths[0].addEventListener("click", function () {
//当前dom
this.style.backgroundColor = "pink"
})
bths[1].addEventListener("click", function () {
this.style.backgroundColor = "pink"
})
// 3.伪数组 可以遍历for
for (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 元素的 class
p[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>
<img
src="./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>
<img
src="./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>
<img
src="./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
赋值的自定义属性不存在时,会自动添加 - 自定义属性使用
-
连接时,要采用驼峰命名规则