Front end foundation course 10
上节课的作业
同学们交的作业完成的质量都挺不错的,这里对后两道题给一个例子。
上节课的 DEMO
本次的 demo 是为了复习和巩固 HTML 和 CSS 的基础知识,所以我们来一起仿造一个静态页面。
上节课因为课上练习的时间比较长,所以 demo 就没做。 不过我觉得这个练习还是很有意义的,所以这次课我们先继续完成上节课的 demo。
DOM 基础 Part 2
DOM 事件
我们之前已经学了如何通过 JS 操作 DOM 节点。但在实际的开发中,并不是页面就是按照我们写好的流程跑一边就结束了。 大多数时候我们是在对用户的行为进行响应,以达到服务用户的目的。那么如何监听并响应用户的行为,就和我们这节课要讲的 DOM 事件相关。
学习目标
- 知道什么是事件以及大致有哪些事件
- 会用 JS 进行事件监听和响应
- 知道事件冒泡、捕获
什么是事件
生活中我们执行的一些动作(如:洗衣服,做饭)我们会称之为一件事情。 那么同理,用户在网页中执行的一些动作,就是我们这里讲到的事件。 如:点击按钮、移动鼠标、加载图片、刷新网页、滚动页面等。
什么是事件绑定
生活中当我们摔倒会下意识的伸手扶地保护自己,或者当收到惊吓会下意识的尖叫,其实这就类似于计算机中的事件绑定。 计算机中事件绑定即指在发生某个事件的时候,自动触发相应的处理机制。如当用户滚动页面到底部会出现回到顶部的按钮。
如何实现事件绑定
给节点绑定事件大致上可以通过两种方式,一种是修改事件属性,一种是使用事件接口。
事件属性
每个 DOM 节点都会有一些事件相关的属性,它们通常以 'on' 开头,属性值为空。 可以通过修改这些属性的值来指定事件的处理代码。例如:
<a id="alert-btn">点我试试</a>
<script>
var btn = document.getElementById('alert-btn');
btn.onclick = function () {
alert('你还真点啊');
};
</script>
事件接口
设想一下如果需要对一个节点绑定多个事件应该怎么处理呢?
通过上面的方法可能会很麻烦,但可以通过节点的 addEventListener
和 removeEventLister
方法来方便的实现。
例如上面的代码也可以这样实现:
<a id="alert-btn">点我试试</a>
<script>
var btn = document.getElementById('alert-btn');
btn.addEventListener('click', function () {
alert('你还真点啊');
});
</script>
IE 低版本需要使用 attachEvent
和 detachEvent
。
常用事件
- click 鼠标点击
- dbclick 鼠标双击
- mousemove 鼠标移动
- mouseenter 鼠标移入
- mouseleave 鼠标移出
- keydown 键盘按下
- keyup 键盘松开
- keypress 键盘按键
- scroll 文档滚动
- load 加载完成
更完整的事件列表可以看这里。
事件参数
事件处理函数的第一个参数为事件对象,其中包含了事件触发的元素、位置、事件类型等非常多有用的信息,供需要的时候使用。 通过下面的方式可以输出事件对象以查看其中的内容:
btn.addEventListener('click', function (e) {
console.log(e);
});
关于冒泡和捕获
在事件传递的过程中,分为冒泡和捕获两个过程。这里给大家做简单的描述,更多内容感兴趣的同学可自行扩展学习。
捕获
捕获过程即事件从最外层的元素开始触发,然后逐渐触发到当前元素。
例如对于如下的 DOM 结构:
<body>
<div class="father">
<div class="child"></div>
</div>
</body>
如果 child 元素触发事件,那么捕获的过程为:body -> div.father -> div.child 。
冒泡
冒泡与捕获相反,从当前元素开始触发,逐渐向外扩展直到最外层元素或者被终止。
例如对于上面的 DOM 结构,如果 child 元素触发事件,那么冒泡的过程为:div.child -> div.father -> body 。
如何使用
在支持的浏览器中,可以通过参数来控制发生的过程究竟是在捕获还是在冒泡,如下:
element.addEventListener('click', function () {}, false);
其中第三个参数为 false
表示发生在冒泡阶段(默认),为 true
表示发生在捕获阶段。
事件代理
设想一下这种场景,有一个列表,其中点击列表项需要触发一个事件,假如说这个列表有 1000 项,那是不是需要绑定 1000 次事件? 如果这还不够麻烦的话,那如果列表内容也是可变的,每次添加新的还需要再绑定事件,删除已有的也需要删除相应的事件,那么我添加 1000 项再删除 1000 次呢?
我们现在已经知道了事件存在冒泡的机制,那么对于类似的场景,我们可以通过事件代理来处理。
直接在外层的父节点上绑定事件监听,再通过 target
属性获取到事件触发的元素即可。
<ul id="list">
<li>test1</li>
<li>test2</li>
<li>test3</li>
<li>test4</li>
<li>test5</li>
<li>test6</li>
</ul>
<script>
var ul = document.getElementById('list');
ul.addEventListener('click', function (e) {
console.log('事件代理成功,触发事件的元素为:');
console.log(e.target);
}, false);
</script>
阻止行为
在事件处理函数中,可以通过 e.stopPropagation()
来阻止事件冒泡,通过 e.preventDefault()
来阻止默认行为的触发。
例如:
html
Homework
- 写一个计时器页面,拥有开始和停止按钮。按下开始按钮后开始计时,按下停止按钮后输出中间间隔的时间。
- 写一个 todo 列表页面,包含一个列表、一个输入框、一个添加按钮。点击添加按钮可以把输入框的内容添加进列表。
- 写一个抽奖页面,包含抽奖按钮、结果列表。点击抽奖按钮随机产生抽奖结果,并将结果添加进列表中,要求中奖几率为20%。
- 第二题的扩展,增加清除按钮,点击后可清空列表。
- 第二题的扩展,增加完成功能,即点击某个列表项后,改项目变为完成状态,颜色变灰,并添加删除线。
- 上次作业计时器页面的扩展,增加控制按钮:进入页面时时间静止,按钮为开始;点击后时间开始动,按钮为停止;再次点击后时间停止,按钮为开始。如此循环。
- 写一个归类列表页面,包含一个输入框、两个按钮和两个列表。输入内容后,(内容非空时)点击按钮1内容进入列表1,点击按钮2内容进入列表2。
预告
下节课开始进入一些综合实战的部分。
Fighting!
2015.01.11