Web前端Javascript笔记(5)事件
1. 什么是事件:事件是指发生并得到处理的操作
JavaScript中的事件是由访问web页面的用户引起的一系列操作,例如,用户的点击操作,JavaScript中有两种事件模型:内联模型,脚本模型。
内联模型:是一种传统简单的事件处理方法,在内联模型中,事件处理函数是HTML标签的一个属性,用于处理指定事件。特点:是和html代码混写在一起的。
脚本模型:将事件绑定与HTML代码分离开来:
事件的绑定方式:内联模式,脚本模式
在开发中,推荐使用外联(脚本)模式,这样可以将HTML于CSS完全分离
事件类型:
1. 鼠标事件
click: 单击
dblclick:双击
mouseover:鼠标移入,在经过元素子节点的时候也会触发
mouseout:鼠标移出
mousemove: 鼠标移动 (不停的触发)
mousedown:鼠标按下
mouseup:鼠标抬起
mouseenter: 鼠标移入 ,在经过元素子节点的时候不会触发
mouseleave: 鼠标移除
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script rel="script" src="../JavaScript/tool.js"></script>
<script>
window.onload = function(){
let btn = $("btn1");
btn.ondblclick = function () {
alert("double click");
};
btn.onmouseover = function () {
this.style.background = "#996e27";
};
btn.onmouseout = function () {
this.style.background = "white";
};
let cnt = 0;
let box = $("box");
box.onmousemove = function () {
this.innerHTML = cnt++;
}
}
</script>
<style>
#box{
width: 200px;
height: 200px;
background: red;
}
</style>
</head>
<body>
<button id="btn1">按钮</button>
<div id="box">0</div>
</body>
</html>
效果如下所示:
2.键盘事件(一般绑定在表单元素或者window)
keydown:键盘按下,如果不松开的话,会一直触发事件
keyup:键盘抬起
keypress:键盘按下,只支持字符键
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script rel="script" src="../JavaScript/tool.js"></script>
<script>
window.onload = function(){
let i = 0;
window.onkeydown = function () {
document.title = (i++).toString();
};
window.onkeyup = function () {
document.title = "抬起"
};
window.onkeypress = function (key) {
// 传入的参数:可以得到具体的按键值
alert(key.code);
}
}
</script>
</head>
<body>
</body>
</html>
3.HTML事件
a. window事件
load:当页面加载完毕后会触发的事件
unload:当页面解构的时候会触发的事件,例如刷新页面,或者关闭页面 ,只支持IE浏览器
scroll:页面滚动的时候触发事件
resize:窗口大小发生变化的时候触发的事件
b. 表单事件
blur : 失去焦点
focus :获得焦点
select:当在输入框内选中文本的时候会触发的事件
change: 当对输入框的文本进行修改且失去焦点的时候会触发事件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script rel="script" src="../JavaScript/tool.js"></script>
<script>
window.onload = function(){
let input_tag = $("username");
input_tag.onblur = function(){
alert("失去焦点");
};
input_tag.onfocus = function () {
alert("获得焦点");
};
input_tag.onchange = function () {
alert("内容修改");
};
input_tag.onselect = function () {
alert("内容选中");
};
}
</script>
</head>
<body>
<input id="username" type="text" placeholder="请输入用户名">
</body>
</html>
【注】下面两个自能添加到form元素上
submit: 当点击submit上的按钮时才能出发
reset: 当点击reset上的按钮时才能出发
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script rel="script" src="../JavaScript/tool.js"></script>
<script>
window.onload = function(){
let form = $("userInfo");
let input_box = form.firstElementChild;
form.onsubmit = function () {
if(!input_box.value){
alert("用户名不能为空");
}
else
{
alert("注册成功");
}
};
form.onreset = function () {
input_box.value = "";
alert("重置")
};
}
</script>
</head>
<body>
<form id="userInfo">
<input type="text" placeholder="请输入">
<input type="submit">
<input type="reset">
</form>
</body>
</html>
事件对象:
在上述的事件绑定的过程中,当元素与标签之间的事件绑定一旦完成的时候,系统会自动生成一个事件对象,当事件触发的时候,系统会去调用相应的事件函数,此时,系统会将事件对象当作第一个参数传入。
例如:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script rel="script" src="../JavaScript/tool.js"></script>
<script>
function show(){
alert(arguments.length);
alert(arguments[0]);
}
window.onload = function(){
let button_tag = $("btn");
button_tag.onclick = show;
};
</script>
</head>
<body>
<button id="btn">按钮</button>
</body>
</html>
例如,在触发按钮事件之后,系统会调事件函数show()(show函数只能由系统调用),可以在show()函数中输出函数参数,可以看到,系统给show()函数传入了一个参数:
可以看到传入的是一个MouseEvent事件对象。
可以在函数申明中定义一个形参,用来接收系统传入的参数,但是此方法只有在IE8以上的浏览器中才兼容,还有一种方法,可以在定义的函数中通过window.event拿到系统传入的参数,所以可以写一个兼容不同版本浏览器的函数:
<script>
function show(ev){
let e = ev || window.event;
alert(e);
}
window.onload = function(){
let button_tag = $("btn");
button_tag.onclick = show;
};
</script>
事件对象属性和方法:
a. 鼠标事件对象:
button: 表示按下的是鼠标的哪个键 0 1 2 = 【左,中,右】
获取当前鼠标位置:三种方法:(原点位置不一样)
clientX, clientY 原点位置为可视窗口的左上角,即使页面滚动了,参考原点依然是左上角的可视区域
pageX, pageY 原点位置为页面的左上角,页面滚动,相应的y坐标也会增加
screenX, screenY 原点位置为电脑屏幕的左上角,即使浏览器出了电脑屏幕,坐标的参考原点依然为屏幕左上角
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script rel="script" src="../JavaScript/tool.js"></script>
<script>
window.onload = function () {
document.onmousedown = function (ev) {
// 鼠标按下的事件
let e = ev || window.event; // 获取事件对象
alert(e.button); // 获取鼠标的按键
alert(e.clientX + "," + e.clientY);
alert(e.pageX + "," + e.pageY);
alert(e.screenX + "," +e.screenY);
};
}
</script>
</head>
<body>
</body>
</html>
案例:
可以跟随鼠标移动的提示框
所以需要实现的是:
1. 鼠标移入,展现出提示框
2. 鼠标移动,提示框随着鼠标移动
3. 鼠标移出,提示框消失
步骤:
1. 先给a标签添加鼠标移入和移除事件,再添加鼠标移入事件。
2. 在获取到鼠标的当前坐标之后,需要给坐标添加一定量的偏置,在把偏置后的坐标作为div的位置,因为div的层级高于a标签,所以如果不偏置,鼠标在div上时,就相当于移出了a标签,这样就会反复触发mouseover和mouseout事件。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script rel="script" src="../JavaScript/tool.js"></script>
<script>
window.onload = function () {
let tag_a = document.getElementsByTagName("a"); // 所有的a标签
let content_box = $("msg");
let content_arr = ["Go for html", "go for python", "go for C++"];
for (let i=0; i<tag_a.length; i++)
{
tag_a[i].index = i;
tag_a[i].onmouseover = function () {
content_box.style.display = "block";
content_box.innerHTML = content_arr[i];
};
tag_a[i].onmouseout = function () {
content_box.style.display = "none";
};
tag_a[i].onmousemove = function (position) {
let pos = position || window.event; // 获取事件对象
let cord_x = pos.clientX + 5; // 添加5像素的偏置量
let cord_y = pos.clientY + 5;
content_box.style.left = cord_x + "px";
content_box.style.top = cord_y + "px";
};
}
}
</script>
<style>
a{
font-size: 25px;
color: blue;
display: block;
border: none;
/*width: 200px;*/
/*height: 100px;*/
margin-left: 30px;
margin-top: 100px;
width: 50px;
}
#msg{
width: 200px;
height: 80px;
border: 1px solid black;
display: none;
background: gray;
position: absolute;
}
</style>
</head>
<body>
<a href="#">Html</a>
<a href="#">python</a>
<a href="#">c++</a>
<div id="msg"></div>
</body>
</html>
事件对象属性:
shiftkey : 按下shift键时为true, 否则为false
altkey:按下alt键为true,否则为false
ctrlkey:
metakey:windows下为windows键
键盘事件中的属性:
keyCode也需要兼容
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script rel="script" src="../JavaScript/tool.js"></script>
<script>
window.onload = function () {
window.onkeydown = function (ev) {
let e = ev || window.event;
alert(e);
// 获取键码,需要考虑不同浏览器的兼容问题
let which = e.which || e.keyCode;
alert(which);
}
}
</script>
</head>
<body>
</body>
</html>
对前面的内容发布的程序进行修改,添加快捷键,在输入框中输入内容,按下ctrl+enter键,也可以发布内容:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script rel="script" src="../JavaScript/tool.js"></script>
<script>
window.onload = function () {
let input_tag = $("input_text");
let bottom_section = $("bottom");
$("add").onclick = function ()
{
let input_content = input_tag.value;
if(!input_content){
alert("请输入内容");
}
else{
// 开始创建节点
let node = document.createElement("div");
let text_node = document.createTextNode(input_content);
let btn_node = document.createElement("button");
let btn_text_node = document.createTextNode("x");
btn_node.appendChild(btn_text_node);
node.appendChild(text_node);
node.appendChild(btn_node);
node.style.background = randomColor();
bottom_section.appendChild(node);
input_tag.value = ""; // 清空输入框
updateItemsButtons();
}
};
$("delete").onclick = function () {
let last_node = bottom_section.lastChild;
bottom_section.removeChild(last_node);
updateItemsButtons();
};
$("clone").onclick = function () {
let last_node = bottom_section.lastChild;
let clone_node = last_node.cloneNode(true); // 深拷贝
bottom_section.appendChild(clone_node);
updateItemsButtons();
};
function updateItemsButtons() {
// 对每条记录上的删除按钮绑定函数
let child_nodes = bottom_section.children; // 只获取div元素节点
let btn_arr = [];
for(let i=0; i<child_nodes.length; i++)
{
btn_arr.push(child_nodes[i].firstElementChild);
//console.log(child_nodes[i].children);
}
// 对标签绑定事件函数
for (let i=0; i<btn_arr.length; i++)
{
// console.log(btn_arr[i]);
btn_arr[i].index = i;
btn_arr[i].onclick = function () {
bottom_section.removeChild(child_nodes[this.index]);
}
}
}
input_tag.onkeydown = function (ev)
{
// 给输入框添加快捷键
let e = ev || window.event;
let key_code = e.keyCode || e.which; // 判断回车键
if(e.ctrlKey && key_code===13)
{
$("add").onclick();
}
}
}
</script>
<style>
#container{
width: 200px;
border: 1px solid black;
}
#top{
width: 100%;
height: 30px;
}
#top input{
height: 20px;
line-height: 30px;
margin: 0 auto;
}
#middle{
width: 100%;
height: 50px;
border: none;
display: flex;
flex-direction: row;
justify-content: space-around;
background: #0f6674;
}
#middle button{
/*width: 25%;*/
height: 50%;
align-self: center;
/*margin-top: 10px;*/
}
#bottom{
}
#bottom div{
height: 25px;
position: relative;
}
#bottom div button{
position: absolute;
top: 1px;
right: 2px;
}
</style>
</head>
<body>
<div id="container">
<div id="top">
<input type="text" id="input_text" placeholder="请输入内容">
</div>
<div id="middle">
<button id="add">添加</button>
<button id="delete">删除</button>
<button id="clone">克隆</button>
</div>
<div id="bottom">
<!--<div>content<button>x</button></div>-->
</div>
</div>
</body>
</html>
效果如下所示:
事件冒泡和触发对象:
事件属性target表示触发对象,只有IE8以上的浏览器兼容,需要和window.event.srcElement方法兼容使用
触发对象表示的是这个事件是由谁而触发引起的:,例如下面的div标签:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script rel="script" src="../JavaScript/tool.js"></script>
<script>
window.onload = function () {
$("cox").onclick = function (ev) {
alert(this.innerHTML); // 输出1233
// 获取触发对象
let e = ev || window.event; // 获取事件对象
let target = e.target || window.event.srcElement; // 事件对象的target属性表示触发对象
alert(target.innerHTML);
}
}
</script>
</head>
<body>
<div id="cox">1233</div>
</body>
</html>
上述的两种方法输出的都是1233,但是,实际上this 和 targe实质上是不同的。this指向的是当前的标签,而target指向的是触发事件的标签,这个标签有可能是当前的标签,也可能是当前标签的子标签,例如:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script rel="script" src="../JavaScript/tool.js"></script>
<script>
window.onload = function () {
$("cox").onclick = function (ev) {
alert(this.tagName); // 输出1233
// 获取触发对象
let e = ev || window.event; // 获取事件对象
let target = e.target || window.event.srcElement; // 事件对象的target属性表示触发对象
alert(target.innerHTML);
}
}
</script>
</head>
<body>
<ul id="cox">
<li>11111</li>
<li>22222</li>
</ul>
</body>
</html>
例如,this.tagName输出的是UL标签,因为UL是事件函数的主人,但是这里的target表示的具体点击的<li>标签,代表的是触发时间函数的那个对象。
事件冒泡:
存在于嵌套的标签中,当嵌套的标签内外都绑定了时间函数的时候,内部的事件函数被触发执行完毕后,外部的标签又会被触发。这就是事件冒泡。
例如,对于下面的三个<div>标签:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script rel="script" src="../JavaScript/tool.js"></script>
<script>
window.onload = function () {
let tags = document.getElementsByTagName("div");
for (let i=0; i<tags.length; i++)
{
tags[i].onclick = function () {
alert(this.id);
}
}
}
</script>
<style>
div{
padding: 30px;
}
#div1{
background: red;
width: 200px;
height: 200px;
}
#div2{
background: green;
width: 60%;
height: 60%;
margin: 0 auto;
}
#div3{
background: blue;
width: 60%;
height: 60%;
margin: 0 auto;
}
</style>
</head>
<body>
<div id="div1">
<div id="div2">
<div id="div3"></div>
</div>
</div>
</body>
</html>
当点击div2的时候,会触发div2事件函数,之后又会触发div1事件函数。当点击div3的时候,触发div3事件函数,之后又触发div2事件函数,接着又会触发div1事件函数。
事件冒泡又称为事件流:事件由里向外,逐层触发。很多时候,并不想让浏览器发生事件冒泡,阻止事件冒泡的方法有两种:
cancelBubble = True和 stopPropagation(),这些都是事件对象的属性和方法,所以首先需要拿到事件对象:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script rel="script" src="../JavaScript/tool.js"></script>
<script>
window.onload = function () {
let tags = document.getElementsByTagName("div");
for (let i=0; i<tags.length; i++)
{
tags[i].onclick = function (ev) {
let e = ev || window.event;
//e.cancelBubble = true; // 阻止事件冒泡
// e.stopPropagation();
// 跨浏览器兼容:
stopBubble(e);
alert(this.id);
}
}
// 跨浏览器兼容
function stopBubble(e) {
if(e.stopPropagation)
{
e.stopPropagation();
}
else{
e.cancelBubble = true;
}
}
}
</script>
<style>
div{
padding: 30px;
}
#div1{
background: red;
width: 200px;
height: 200px;
}
#div2{
background: green;
width: 60%;
height: 60%;
margin: 0 auto;
}
#div3{
background: blue;
width: 60%;
height: 60%;
margin: 0 auto;
}
</style>
</head>
<body>
<div id="div1">
<div id="div2">
<div id="div3"></div>
</div>
</div>
</body>
</html>
案例练习:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script rel="script" src="../JavaScript/tool.js"></script>
<script>
window.onload = function () {
let divs = document.getElementsByTagName("div");
document.onmousemove = function (ev)
{
let e = ev || window.event;
for (let i=divs.length-1; i>0; i--)
{
divs[i].style.left = divs[i-1].offsetLeft + "px";
divs[i].style.top = divs[i-1].offsetTop + "px";
}
divs[0].style.left = e.clientX + "px";
divs[0].style.top = e.clientY + "px";
};
}
</script>
<style>
*{
margin: 0;
padding: 0;
}
div{
position: absolute;
width: 10px;
height: 10px;
background: black;
border-radius: 50%;
}
</style>
</head>
<body>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</body>
</html>