1.事件
网页中的每个元素都可以产生某些事件。 比如:当用户单击按钮时,就发生一个鼠标单击(onclick)事件。 当用户点击提交按钮时,就发生一个提交数据(onsubmit)事件。 事件是可以被侦测到的行为。 每个元素都可以产生某些可以触发JavaScript函数的事件。
javaScript中的常用事件:
1.1.javaScript中绑定事件方式
在javaScript中,给DOM元素绑定事件有三种方式:侵入式、绑定式、监听函数式。
侵入式事件方式:将javaScript事件直接写在html标签中
<div onclick="add()">点我</div>
<script>
//事件处理函数
function add(){
console.log('点击了div对象');
}
</script>
注意:此种方式的缺点是:javaScript事件与HTML代码混杂在一起。
绑定式事件方式:通过DOM对象,使用javaScript代码绑定一个事件
<div>点我</div>
<script>
let divObj = document.getElementsByTagName('div')[0];
//function()匿名函数就是事件处理函数
divObj.onclick = function(){
console.log('点击了div对象');
}
</script>
注意:此种方式的优点是:
- 行间和事件分离。
- 可以给元素动态添加事件。
监听函数式事件方式:
<div>点我</div>
<script>
let divObj = document.getElementsByTagName('div')[0];
divObj.addEventListener('click',function(){
console.log('点击了div对象');
},false);
</script>
注意:addEventListener函数的三个参数:
- 事件名(没有前缀on)。
- 事件处理函数。
- 布尔类型(一般为false)。true:进行事件捕获; false:不进行事件捕获;
1.2.事件对象-event
event 对象代表事件的状态,比如事件在其中发生的元素、键盘按键的状态、鼠标的位置、鼠标按钮的状态。
1.2.1.鼠标坐标的使用
<head>
<meta charset="utf-8">
<title></title>
<style>
div{
width: 200px;
height: 200px;
background-color: blue;
margin: 100px;
}
</style>
</head>
<body>
<div><div>
<script>
document.getElementsByTagName('div')[0].onmousemove = function(event){
console.log('相对视口坐标:'+event.clientX+','+event.clientY);
console.log('相对触发事件对象坐标:'+event.offsetX+','+event.offsetY);
}
</script>
</body>
1.2.2.keyCode的使用
//获取键盘按键的keyCode
document.onkeydown = function(event){
console.log(event.keyCode);
}
常用按键的keyCode值:回车13, 空格32,上38,下40,左37,右39
1.3.事件冒泡与事件捕获
在页面上的一块可视区域中,其中可能会包括父元素可视区域与子元素可视区域。
此时,如果用户触发了子元素的某个事件,而父元素也具有相同的事件,那么事实上,我们并不能确定:用户到底是想触发子元素事件,还是想触发父元素事件。
解决这个问题的思路是:设计两种事件流:
- 当用户触发了子元素事件时,先触发子元素事件,再触发父元素事件。这就是事件冒泡。(默认)
- 当用户触发了子元素事件时,先触发父元素事件,再触发子元素事件。这就是事件捕获。
下面演示事件冒泡:
<head>
<style>
div{
width: 200px;
height: 200px;
background-color: red;
}
div p{
width: 100px;
height: 100px;
background-color: blue;
}
</style>
</head>
<body>
<div>
<p></p>
</div>
<script>
let divObj = document.getElementsByTagName('div')[0];
let pObj = divObj.getElementsByTagName('p')[0];
divObj.onclick = function(){
alert('父元素的点击事件被触发');
}
pObj.onclick = function(){
alert('子元素的点击事件被触发');
}
</script>
</body>
阻止事件冒泡: event.cancelBubble = true;
pObj.onclick = function(event){
alert('子元素的点击事件被触发');
event.cancelBubble = true;
}
1.4.浏览器默认行为
默认行为:在某些事件中,浏览器内置了一些默认的功能。 如:单击鼠标右键会弹出菜单、提交按钮默认提交动作、按下字母键会输入一个字母等。 如果这些默认行为不能满足我们需要的功能,那么可以阻止默认行为,重写我们希望的行为。 阻止默认行为很简单,在事件处理函数中调用preventDefault方法即可。 阻止默认行为: event.preventDefault();
下面是一个自定义右键菜单案例:
<ul>
<li>右键菜单项1</li>
<li>右键菜单项2</li>
<li>右键菜单项3</li>
</ul>
<script>
let ulObj = document.getElementsByTagName('ul')[0];
ulObj.style.border = 'solid 1px #666';
ulObj.style.width = '100px';
ulObj.style.position = 'absolute';
ulObj.style.display = 'none';
document.oncontextmenu = function(event){
ulObj.style.display = 'block';
ulObj.style.left = event.clientX+'px';
ulObj.style.top = event.clientY+'px';
event.preventDefault();
}
ulObj.onclick = function(){
this.style.display = 'none';
}
</script>
1.5.表单元素事件
1.5.1.表单元素常用事件
1.5.2.表单验证
表单是Web应用中的一个重要组成部分,通过表单,可以让用户与服务器端进行交互。
通常的做法是:用户通过页面表单中的各种控件(文本框、单选按钮、下拉列表等等),填入数据,表单再将这些数据发送给服务器端,进行业务处理。
但是,用户在填入数据的过程中,很有可能会填入错误的数据。此时,就需要在页面上,对用户输入的数据进行合法性验证,以保证用户必须填入正确的数据,进而保证发送给服务器端的数据都是正确的。
常用的表单验证有:
- 非空验证
- 长度验证
- 数字验证
- 日期时间格式验证
- 邮箱地址验证
- 网址验证
- … …
<h3>登陆</h3>
<form>
用户名:<input type="text" id="userName"><br>
密码:<input type="password" id="password"><br>
<input type="button" value="提交" onclick="checkForm()">
</form>
<script>
function checkForm(){
let userName = document.getElementById('userName');
let password = document.getElementById('password');
//用户名非空验证
if(userName.value==''){
alert('用户名不能为空!');
return;
}
//密码非空验证
if(password.value==''){
alert('密码不能为空!');
return;
}
//密码长度必须为六位
if(password.value.length!=6){
alert('密码长度必须为6位!');
return;
}
//密码必须全部为数字
if(isNaN(password.value)){
alert('密码必须全部为数字!');
return;
}
alert('提交');
}
</script>
2.DOM编程实际案例
2.1.时钟
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>时钟</title>
</head>
<body>
<p id="myclock" style="font-size:24px"></p>
<button id="startBtn">开始</button>
<button id="stopBtn">停止</button>
<script>
let myclock = document.getElementById("myclock");
let startBtn = document.getElementById("startBtn");
let stopBtn = document.getElementById("stopBtn");
callback();
let mytimer = setInterval(callback, 1000);
function callback() {
var mydate = new Date();
myclock.innerHTML = mydate.getHours() +
":" + mydate.getMinutes() +
":" + mydate.getSeconds();
}
//启动按钮事件
startBtn.onclick = function() {
if (mytimer == null) {
mytimer = setInterval(callback, 1000);
}
};
//停止按钮事件
stopBtn.onclick = function() {
clearInterval(mytimer);
mytimer = null;
};
</script>
</body>
</html>
2.2.全选
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>全选</title>
</head>
<body>
全选<input class="btn" type="checkbox">
<ul>
<li><input type="checkbox">杜比环绕,家庭影院必备,超真实享受</li>
<li><input type="checkbox">NVDIA 99999GT 2G 1024bit极品显卡,不容错过</li>
<li><input type="checkbox">精品热卖,高清晰,45寸LED电视</li>
<li><input type="checkbox">Sony索尼家用最新款笔记本</li>
<li><input type="checkbox">华为,荣耀3C,超低价,性价比奇高</li>
</ul>
<script>
let btn = document.getElementsByClassName('btn')[0];
let inputArr = document.getElementsByTagName('ul')[0].getElementsByTagName('input');
btn.onclick = function() {
let bool = btn.checked;
for (let i = 0; i < inputArr.length; i++) {
inputArr[i].checked = bool;
}
}
</script>
</body>
</html>
2.3.图片轮播
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>图片轮播</title>
<style>
#lunbo {
width: 1226px;
height: 460px;
position: relative;
margin: 0 auto;
}
#lunbo img {
width: 1226px;
height: 460px;
position: absolute;
left: 0;
top: 0;
display: none;
}
</style>
</head>
<body>
<div id="lunbo">
<img src="img/lunbo1.jpg">
<img src="img/lunbo2.jpg">
<img src="img/lunbo3.jpg">
<img src="img/lunbo4.jpg">
<img src="img/lunbo5.jpg">
<img src="img/lunbo6.jpg">
</div>
<script>
let imgArr = document.getElementById('lunbo').getElementsByTagName('img');
//图片数量
let imgNum = imgArr.length
//用此索引来跟踪图片轮播顺序(第一张图片索引即为0)
let index = 0;
//初始化第一张图片
imgArr[0].style.display = 'block';
//每隔3秒轮播一张图片
setInterval(function(){
index++;
//如果轮播到最后一张图片,那么索引就归零
if (index > imgNum - 1) {
index = 0;
}
//先隐藏所有图片
for (let i=0;i<imgNum; i++) {
imgArr[i].style.display = 'none';
}
//再显示当前图片
imgArr[index].style.display = 'block';
}, 3000);
</script>
</body>
</html>
2.4.图片轮播(过渡效果)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>图片轮播(过度效果)</title>
<style>
#lunbo {
width: 1226px;
height: 460px;
position: relative;
margin: 0 auto;
}
#lunbo img {
width: 1226px;
height: 460px;
position: absolute;
left: 0;
top: 0;
opacity: 0;
/*display: none;*/
}
</style>
</head>
<body>
<div id="lunbo">
<img src="img/lunbo1.jpg">
<img src="img/lunbo2.jpg">
<img src="img/lunbo3.jpg">
<img src="img/lunbo4.jpg">
<img src="img/lunbo5.jpg">
<img src="img/lunbo6.jpg">
</div>
<script>
let imgArr = document.getElementById('lunbo').getElementsByTagName('img');
//图片数量
let imgNum = imgArr.length;
//当前图片索引
let index = 0;
//上一张图片索引
let preIndex = index;
//当前图片初始透明度
let opacityValue = 0;
//上一张图片初始透明度
let preOpacityValue = 1;
//初始化第一张图片
imgArr[index].style.opacity = 1;
setInterval(function() {
//每次切换时,确定当前图片索引与上一张图片索引
preIndex = index;
index++;
//判断是否进行下一轮轮播
if (index > imgNum-1) {
index = 0;
}
//上一张图片隐藏
hideImg();
//当前图片显示
showImg();
}, 3000);
function showImg() {
//设置当前显示图片透明度初始值
opacityValue = 0;
//淡入动画
let time = setInterval(function() {
opacityValue += 0.05;
if (opacityValue >= 1) {
opacityValue = 1;
clearInterval(time);
}
imgArr[index].style.opacity = opacityValue;
}, 40);
}
function hideImg() {
//设置上一张隐藏图片透明度初始值
preOpacityValue = 1;
//淡出动画
let time = setInterval(function() {
preOpacityValue -= 0.05;
if (preOpacityValue <= 0) {
preOpacityValue = 0;
clearInterval(time);
}
imgArr[preIndex].style.opacity = preOpacityValue;
}, 40);
}
</script>
</body>
</html>
2.5.放大镜
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>放大镜</title>
<style>
#fdj {
position: relative;
width: 450px;
height: 450px;
}
#fdj img{
width: 450px;
height: 450px;
}
#fdj .mengban {
position: absolute;
display: none;
width: 225px;
height: 225px;
background-color: yellow;
opacity: 0.4;
cursor: move;
left: 0;
top: 0;
}
#fdj .fdjBox {
position: absolute;
width: 450px;
height: 450px;
top: 0;
left: 460px;
display: none;
}
</style>
</head>
<body>
<!--这里是大图片-->
<div id="fdj">
<img src="img/dazi.jpg">
<div class="mengban"></div>
<div class="fdjBox"></div>
</div>
<script>
<!-- onload能保证图片也加载完毕 -->
window.onload = function() {
let fdj = document.getElementById('fdj');
let mengban = fdj.getElementsByClassName('mengban')[0];
let fdjBox = fdj.getElementsByClassName('fdjBox')[0];
//图片尺寸
let imgWidth = fdj.getElementsByTagName('img')[0].width;
fdj.onmousemove = function(event) {
//这里获取了蒙板的left和top(offsetLeft是fdj距离视口的位置)
let left = event.clientX - this.offsetLeft - imgWidth / 2 / 2;
let top = event.clientY - this.offsetTop - imgWidth / 2 / 2;
//console.log(left + ',' + top);
if (left < 0) {
left = 0;
}
if (left > this.offsetWidth - imgWidth/2) {
left = this.offsetWidth - imgWidth/2;
}
if (top < 0) {
top = 0;
}
if (top > this.offsetHeight - imgWidth/2) {
top = this.offsetHeight - imgWidth/2;
}
mengban.style.left = left + 'px';
mengban.style.top = top + 'px';
mengban.style.display = 'block';
fdjBox.style.backgroundImage = 'url(img/dazi.jpg)';
fdjBox.style.backgroundRepeat = 'no-repeat';
fdjBox.style.backgroundPosition = -left * 2 + 'px' + ' ' + -top * 2 + 'px';
fdjBox.style.display = 'block';
}
fdj.onmouseout = function() {
mengban.style.display = 'none';
fdjBox.style.display = 'none';
}
}
</script>
</body>
</html>
2.6.走马灯
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>走马灯</title>
<style>
#container {
width: 750px;
height: 198px;
margin: 0 auto;
display: flex;
}
#container > img{
width: 55px;
height: 198px;
}
#container div{
position: relative;
width: 640px;
height: 198px;
overflow: hidden;
display: flex;
}
#container div ul {
list-style: none;
margin: 0;
padding: 0;
position: absolute;
width: 640px;
height: 198px;
left: 0px;
top: 0px;
display: flex;
}
#container div ul li {
width: 160px;
height: 198px;
}
</style>
</head>
<body>
<!--图片尺寸:160*198-->
<div id="container">
<img src="img/left.jpg">
<div>
<ul>
<li><a href="#"><img src="img/zmd1.jpg"></a></li>
<li><a href="#"><img src="img/zmd2.jpg"></a></li>
<li><a href="#"><img src="img/zmd3.jpg"></a></li>
<li><a href="#"><img src="img/zmd4.jpg"></a></li>
</ul>
</div>
<img src="img/right.jpg">
</div>
<script>
window.onload = function() {
let container = document.getElementById('container');
let scoll = container.getElementsByTagName("ul")[0];
let imgArr = document.querySelectorAll('#container > img');
let btnLeft = imgArr[0];
let btnRight = imgArr[1];
//滚动速度
let speed = 5;
//滚动方向(初始向右)
let fangxiang = 1;
//获取图片数量
let imgNum = scoll.getElementsByTagName("img").length;
//获取图片宽度
let imgWidth = scoll.getElementsByTagName("img")[0].width;
//获取滚动条宽度
let scollWidth = imgNum * imgWidth;
//给滚动条加一倍的内容
scoll.style.width = scollWidth * 2 + "px";
scoll.innerHTML += scoll.innerHTML;
//滚动条初始位置
scoll.style.left = "-" + scollWidth + "px";
let myTimer = setInterval(gundong, 40);
function gundong() {
if (fangxiang == 1) {
if (scoll.offsetLeft >= 0) {
scoll.style.left = "-" + scollWidth + "px";
}
} else {
if (scoll.offsetLeft <= scollWidth * -1) {
scoll.style.left = 0 + "px";
}
}
scoll.style.left = scoll.offsetLeft + (speed * fangxiang) + "px";
}
btnLeft.onmouseover = function() {
fangxiang = -1;
};
btnRight.onmouseover = function() {
fangxiang = 1;
};
scoll.onmouseover = function() {
clearInterval(myTimer);
}
scoll.onmouseout = function() {
myTimer = setInterval(gundong, 40);
}
}
</script>
</body>
</html>