JS事件
event事件对象
在触发DOM上某个事件时,会产生一个事件对象event,这个对象包含着所有事件相 关的信息,包含导致事件的元素,事件的类型以及其他的与特定事件相关的信息。
它是事件处理函数的第一个(隐藏)的参数,可以通过arguments[0]来获取。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<button id="btn">GET</button>
</body>
<script>
btn.onclick=function(){
console.log(arguments[0])
}
</script>
</html>
此时会打印出一系列的鼠标事件
btn.onclick=function(event){
var event = event || window.event
console.log(event)
}
效果等同上方,IE下取事件是在window下的,此处是个兼容
event.button
如果当前event是鼠标事件,则会有一个button属性,它是一个数字
0代表鼠标按下了左键 1代表按下了滚轮 || 2代表按下了右键(不介绍低版本IE)
<script>
document.onmousedown=function(ev){
var ev=ev||window.event;
alert(ev.button);//012
}
</script>
在页面中点击即可,作为了解一下
鼠标事件中获取鼠标的位置属性介绍(clientX、pageX、offsetX、screenX)
clientX,clientY:鼠标相对于可视区的位置。
pageX,pageY:鼠标相对于文档的位置
offsetX,offsetY:鼠标相对于操作元素(鼠标点击元素)到盒子边缘(左上)的位置.
screenX,screenY:鼠标相对于显示屏的位置.
document.onmousedown=function(ev){
var ev=ev||window.event;
console.log('可视区的位置X:'+ev.clientX);
console.log('可视区的位置Y:'+ev.clientY);
console.log('文档的位置X:'+ev.pageX);
console.log('文档的位置Y:'+ev.pageY);
console.log('对于操作元素的位置X:'+ev.offsetX);
console.log('对于操作元素的位置Y:'+ev.offsetY);
console.log('显示屏的位置X:'+ev.screenX);
console.log('显示屏的位置Y:'+ev.screenY);
}
这个还是得自己多测试加强记忆,写个小demo
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
.box{
width: 100px;
height: 100px;
background: red;
position: absolute;
cursor: move;
}
</style>
</head>
<body>
<div class="box"></div>
<script type="text/javascript">
var oBox=document.querySelector('.box');
document.onmousemove=function(ev){
var ev=ev||window.event;
oBox.style.cssText='left:'+(ev.clientX-oBox.offsetWidth/2)+'px;top:'+(ev.clientY-oBox.offsetHeight/2)+'px;';
}
</script>
</body>
</html>
自行复制浏览一下即可
键盘事件
onkeydown + onkeyup =onpress(按下+弹起=点击)
每一个键盘字母都对应自己的keyCode码,可以测试一下
document.onkeydown=function(ev){
var ev=ev||window.event;
alert(ev.keyCode);//获取键码
}
写个小demo,控制盒子移动(w,s,a,d)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
div{
width: 200px;
height: 200px;background: red;
position: absolute;
left:400px;top:100px;
}
</style>
</head>
<body>
<div></div>
<script type="text/javascript">
var oDiv=document.querySelector('div');
document.onkeydown=function(ev){
var ev=ev||window.event;
if(ev.keyCode==87){
oDiv.style.top=oDiv.offsetTop-10+'px';
}else if(ev.keyCode==83){
oDiv.style.top=oDiv.offsetTop+10+'px';
}else if(ev.keyCode==65){
oDiv.style.left=oDiv.offsetLeft-10+'px';
}else if(ev.keyCode==68){
oDiv.style.left=oDiv.offsetLeft+10+'px';
}
}
</script>
</body>
</html>
组合键
ctrlKey、altKey、shiftKey
document.onkeydown=function(ev){
var ev=ev||window.event
if(ev.keyCode==13&& ev.ctrlKey){ //摁下ctrl与回车 才执行
alert(1)
}
if(ev.keyCode==13&& ev.altKey){ //摁下alt 与回车 才执行
alert(2)
}
}
先按组合键测试哦
js事件流
事件流描述的是从页面中接收事件的顺序,事件可以分为冒泡事件与非冒泡事件
事件的冒泡
IE 的事件流叫做事件冒泡,即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档) 。
取消冒泡:具体元素对象(冒泡元素)的事件不会冒泡到父级(外层)。
非标准(ie8及以下): ev.cancelBubble=true;
标准:ev.stopPropagation();
注意的点是,冒泡的顺序,逐级向上传播到较为不具体的节点,写个demo可测试
<!DOCTYPE html>
<html id="html1">
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
#small{
width: 200px;
height:200px;
border-radius: 50%;
background: red;
}
#middle{
width: 200px;
height:200px;
border-radius: 50%;
background: green;
padding: 100px;
}
#big{
width: 400px;
height:400px;
border-radius: 50%;
background: blue;
padding: 100px;
margin:0 auto;
}
</style>
</head>
<body id="body1">
<div id="big">
<div id="middle">
<div id="small"></div>
</div>
</div>
<script type="text/javascript">
//事件流:从页面中接收事件的顺序
var small=document.querySelector('#small');
var middle=document.querySelector('#middle');
var big=document.querySelector('#big');
function fn(){
alert(this.id);
}
small.onclick=fn;
middle.onclick=fn;
big.onclick=fn;
document.body.onclick=fn;
document.documentElement.onclick=fn;
</script>
</body>
</html>
一共五个事件,如果我点击红圈,也就是先弹small,然后逐级向上释放,接着谈绿色middle,蓝色big,然后是body,最后是html
如果我点击绿圈,红色就不触发,绿色的父级逐渐触发,这个就是事件的冒泡,平时我们点击元素的时候相当于也点击了body,document,只是我们没有给父元素设置事件而已
冒泡的应用
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<button>显示</button>
<div style="width: 150px;height: 250px;background: red;display: none;"></div>
<script type="text/javascript">
var oBtn=document.querySelector('button');
var oDiv=document.querySelector('div');
oBtn.onclick=function(ev){
var ev=ev||window.event;
oDiv.style.display='block';
//ev.stopPropagation();//标准浏览器取消冒泡
}
document.onclick=function(){
oDiv.style.display='none';
}
</script>
</body>
</html>
我这里没有取消冒泡,在点击按钮的时候,事件会冒泡到document让其隐藏,所以点击按钮无法显示,关闭冒泡之后就可以显示元素了,我们平时写事件的时候需要注意一下
阻止默认事件
浏览器有许多默认事件,比如浏览器的右键出现一组选项框,比如我们表单元素中的submit的默认提交事件以及reset的重置事件,还有a标签的跳转事件,很多
document.oncontextmenu=function(ev){ //右键事件
return false
}
取消默认事件很简单,使用return false
ev.preventDefault(); 标准浏览器阻止默认事件,DOM事件使用此方法取消默认事件。
ev.returnValue = false; 非标准浏览器(IE8)阻止默认事件
document.oncontextmenu=function(ev){ //右键事件
alert(1)
ev.preventDefault()
// return false
}
因为JS是单线程语言,如果我们在不取消其默认事件的前提下,给右键点击增加一个事件,弹窗来一个,会先出弹窗再显示选项框,由此可见自定义事件优先于默认事件,基于这个原理我们在自定义事件后方返回函数false不让其往下运行即可
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style type="text/css">
.box{
width: 200px;
height: 300px;
background: red;
position: absolute;
display: none;
}
</style>
</head>
<body>
<div class="box"></div>
</body>
<script>
var oBox=document.querySelector('.box');
document.oncontextmenu=function(ev){ //右键事件
var ev=ev||window.event;
oBox.style.display='block';
oBox.style.left=ev.clientX+'px';
oBox.style.top=ev.clientY+'px';
return false
}
document.onclick=function(){
oBox.style.display='none';
}
</script>
</html>
可复制 浏览一下
其他事件也可以由此出发,取消其默认行为
<body>
<a href="http://www.baidu.com" onclick="return false">百度</a>
<form action="http://www.baidu.com">
<input type="submit" onclick="return false" />
</form>
</body>
DOM2级事件
<script>
document.onclick=function(){//一个元素上面绑定一个事件
alert(123);
}
document.onclick=function(){//多个事件就会出现覆盖。
alert(456);
}
//document.onclick=null //取消事件
</script>
上面的js很明显,只弹出456,同元素同事件会覆盖,很容易理解,那如果我们要点击出现两个事件怎么办呢
DOM事件绑定:一个元素上面绑定多个事件。
基本格式
元素对象.addEventListener(事件类型,函数,是否捕获);标准浏览器
事件类型:不能添加on,click/mouseover...
函数:普通函数名称或者函数体。
是否捕获:false:冒泡(默认) true:捕获
第三个参数,是否捕获冒泡先不介绍,先无视
IE事件绑定和DOM事件绑定(标准浏览器)的区别
ie浏览器:attachEvent(事件类型,函数);
事件类型:添加on onclick
函数:普通函数名称或者函数体。
1.参数不一样
2.执行顺序不一样
3.事件类型不一样
4.this指向不一样
第三个参数默认为false冒泡
<script>
function a(){
alert('a');
}
function b(){
alert('b');
}
function c(){
alert('c');
}
document.addEventListener('click',a); //没有on
document.addEventListener('click',b);
document.addEventListener('click',c);
/*document.attachEvent('onclick',a); IE事件 可无视 很烦
document.attachEvent('onclick',b);
document.attachEvent('onclick',c);*/
</script>
此时点击document 顺序弹出abc
removeEventListener()/detachEvent() 移除事件绑定的参数和添加事件绑定是一致的。后面是IE移除
document.removeEventListener('click',a)
此时就不弹a了
简易事件封装
function addEvent(obj,event,fn){
if(obj.addEventListener){//判断条件采用属性判断,如果存在属性就不是IE
obj.addEventListener(event,fn,false);
}else{
obj.attachEvent('on'+event,fn);
}
}
//事件移除的封装
function removeEvent(obj,event,fn){
if(obj.removeEventListener){
obj.removeEventListener(event,fn,false);
}else{
obj.detachEvent('on'+event,fn);
}
}
addEvent(document,'click',a);
addEvent(document,'click',b);//绑定
removeEvent(document,'click',b)//移除
addEvent(document,'click',c);
事件流的捕获
<!DOCTYPE html>
<html id="html1">
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
#small{
width: 200px;
height:200px;
border-radius: 50%;
background: red;
}
#middle{
width: 200px;
height:200px;
border-radius: 50%;
background: green;
padding: 100px;
}
#big{
width: 400px;
height:400px;
border-radius: 50%;
background: blue;
padding: 100px;
margin:0 auto;
}
</style>
</head>
<body id="body1">
<div id="big">
<div id="middle">
<div id="small"></div>
</div>
</div>
<script type="text/javascript">
var small=document.querySelector('#small');
var middle=document.querySelector('#middle');
var big=document.querySelector('#big');
function fn(){
alert(this.id);
}
/*small.onclick=fn;
middle.onclick=fn;
big.onclick=fn;
document.body.onclick=fn;
document.documentElement.onclick=fn;*/
function addEvent(obj,event,fn,bool){
if(obj.addEventListener){
obj.addEventListener(event,fn,bool);
}else{
obj.attachEvent('on'+event,fn);
}
}
addEvent(small,'click',fn,true);
addEvent(middle,'click',fn,true);
addEvent(big,'click',fn,true);
addEvent(document.body,'click',fn,true);
addEvent(document.documentElement,'click',fn,true);
</script>
</body>
</html>
依旧是之前三个圆,注意上方的最后一个参数是true,之前说过DOM事件的绑定第三个参数是个布尔值,我这里封装了一下方法,多了一个元素参数,此时我们点哪个都是最后一个才弹
比如我们点最小的红圈,先弹html 然后body 然后依次递减,但是我这个布尔值是可以更改的,如果为fasle则是冒泡,我修改其中一两个看看效果
addEvent(small,'click',fn,false);//冒泡
addEvent(middle,'click',fn,true);//捕获
addEvent(big,'click',fn,false);//冒泡
addEvent(document.body,'click',fn,true);//捕获
addEvent(document.documentElement,'click',fn,false);//冒泡
此时我要点最小的红圈,弹的顺序是
body--middle--small--big--html
如果我点big 篮圈,弹的顺序是
body--big--html
如果我点的是绿圈,弹的顺序是
body--middle--big--html
事件流的顺序:捕获---目标---冒泡,多套几个圈 多测几次就可以更深入理解了
事件委托的应用
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<input type="text" id="text" /><input type="button" value="发布" id="btn" />
<ul id="ul1">
<li>55555555</li>
<p>pppppppppp</p>
</ul>
<script type="text/javascript">
var oT=document.getElementById('text');
var oBtn=document.getElementById('btn');
var oUl=document.getElementById('ul1');
oBtn.addEventListener('click',function(){
var cLi=document.createElement('li');
cLi.innerHTML=oT.value;
oUl.appendChild(cLi);
oT.value='';
},false);
//事件委托的应用
oUl.onclick=function(ev){
var ev=ev||window.event;
//target:获取目标元素,点击的元素对象。
var ele=ev.target||ev.srcElement;//获取当前点击目标元素
alert(ele.nodeName);//获取当前元素的名称(大写的)
if(ele.nodeName=='LI'){//一定要判断当前点击的元素,就是我们需要控制的元素。
alert(ele.innerHTML);
}
}
</script>
</body>
</html>
注意我点的是UL,从外面找里面找到元素,如果我们在写逻辑的时候发现这个元素很难找的时候,就可以使用这种方法
拖拽效果
这个效果其实在别的文章中写过,简易的再写一次,多敲一遍总是好的
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
*{
margin: 0;
padding: 0
}
div{
width: 100px;
height: 100px;
background: red;
position: absolute;
left: 0;
top: 0
}
</style>
</head>
<body>
<div id="div"></div>
</body>
<script>
div.onmousedown=function(ev){
var ev=ev||window.event
//鼠标按下的时候获取短线
var shortx=ev.offsetX;
var shorty=ev.offsetY;
document.onmousemove=function(ev){ //这里为什么使用document 根据冒泡原理应该很好理解了吧
var ev=ev||window.event;//在移动的时候重新获取,不断变化,用移动时的鼠标位置。
div.style.left=ev.clientX-shortx+'px';
div.style.top=ev.clientY-shorty+'px';
}
div.onmouseup=function(){
document.onmousemove=null
div.onmouseup=null
}
}
</script>
</html>
最简单的一个拖拽,需要注意的是onmouseup要写在onmousedown里面,如果写外面就执行一次,之后将无法取消move事件,如果我们不想让他超出浏览器,写个判断
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
*{
margin: 0;
padding: 0
}
div{
width: 100px;
height: 100px;
background: red;
position: absolute;
left: 0;
top: 0
}
</style>
</head>
<body>
<div id="div"></div>
</body>
<script>
div.onmousedown=function(ev){
var ev=ev||window.event
//鼠标按下的时候获取短线
var shortx=ev.offsetX;
var shorty=ev.offsetY;
document.onmousemove=function(ev){ //这里为什么使用document 根据冒泡原理应该很好理解了吧
var ev=ev||window.event;//在移动的时候重新获取,不断变化,用移动时的鼠标位置。
var l=ev.clientX-shortx;//水平 鼠标的x坐标减去鼠标到div左边的距离就是div的left值
var t=ev.clientY-shorty;//垂直
if(l<=0){
l=0;
}else if(l>=document.documentElement.clientWidth-div.offsetWidth){
l=document.documentElement.clientWidth-div.offsetWidth;
}
if(t<0){
t=0;
}else if(t>=document.documentElement.clientHeight-div.offsetHeight){
t=document.documentElement.clientHeight-div.offsetHeight
}
div.style.left=l+'px';
div.style.top=t+'px';
}
div.onmouseup=function(){
document.onmousemove=null
div.onmouseup=null
}
}
</script>
</html>
这个逻辑应该不难
然鹅有些元素是不允许拖拽的,比如img,其实使用return false就可以,我们试着封装一个函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
*{
margin: 0;
padding: 0
}
img{
position: absolute;
left: 0;
top: 0
}
</style>
</head>
<body>
<img id="img" src="http://img2.imgtn.bdimg.com/it/u=2830140111,3261939339&fm=26&gp=0.jpg" />
</body>
<script>
function drag(el){
el.onmousedown=function(ev){
var ev=ev||window.event;
shortx=ev.offsetX;
shorty=ev.offsetY;
document.onmousemove=function(ev){
var ev=ev||window.event;//重新获取,不断变化,用移动时的鼠标位置。
var l=ev.clientX-shortx;//水平
var t=ev.clientY-shorty;//垂直
el.style.left=l+'px';
el.style.top=t+'px';
}
el.onmouseup=function(){
document.onmousemove=null;
el.onmouseup=null
}
return false
}
}
drag(img)
</script>
</html>
这样我们只需要传递元素即可了
碰撞检测
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
.box1{
width: 200px;
height: 200px;
background: red;
position: absolute;
z-index: 2;
}
.box2{
width: 200px;
height: 200px;
background: blue;
position: absolute;
left:800px;
top:200px;
}
</style>
</head>
<body>
<div class="box1">1</div>
<div class="box2">2</div>
<script type="text/javascript">
var oBox1=document.querySelector('.box1');
var oBox2=document.querySelector('.box2');
var shortx=0;
var shorty=0;
oBox1.onmousedown=function(ev){
//鼠标按下求短线。
var ev=ev||window.event;
shortx=ev.offsetX;
shorty=ev.offsetY;
document.onmousemove=function(ev){
var ev=ev||window.event;//重新获取,不断变化,用移动时的鼠标位置。
var l=ev.clientX-shortx;//水平
var t=ev.clientY-shorty;//垂直
oBox1.style.left=l+'px';
oBox1.style.top=t+'px';
if( !((oBox1.offsetLeft+oBox1.offsetWidth)<oBox2.offsetLeft || oBox1.offsetLeft>oBox2.offsetLeft+oBox2.offsetWidth || (oBox1.offsetTop+oBox1.offsetHeight)<oBox2.offsetTop || oBox1.offsetTop>oBox2.offsetTop+oBox2.offsetHeight) ){
oBox2.style.background='green';
}else{
oBox2.style.background='blue';
}
}
document.onmouseup=function(){//松开鼠标,不再移动了
document.onmousemove=null;
document.onmouseup=null;
}
return false;//取消默认事件
}
</script>
</body>
</html>
这个代码就不解释了,看不懂多看几遍 主要是判断的地方