在Web中, 事件在浏览器窗口中被触发,执行事先绑定的事件处理器(也就是事件触发时会运行的代码块),对事件作出响应。
用户在浏览器的任何一个操做都会去触发一个事件,JavaScript采用异步事件驱动编程模型,当文档、浏览器、元素或与之相关对象发生特定事情时,浏览器会产生事件。css
事件是某个行为或者触发,好比点击、鼠标移动、提交表单,滚动菜单等等html
事件流描述的是从页面中接收事件的顺序,好比有两个嵌套的div,点击了内层的div,这时候是内层的div先触发click事件仍是外层先触发?node
若是事件不传播,咱们没法肯定咱们点击的对象是什么?编程
事件开始时由最具体的元素接收,而后逐级向上传播到较为不具体的元素。好比点击div时,首先是div先监听到了点击事件,而后向上传播到body/html/documentsegmentfault
和事件冒泡相反,事件最开始由最外层不太具体的节点先监听到,而后向下传递到最具体的元素。
好比点击div事件,先是document监听到,而后分发到html/body/div数组
DOM2级事件规定事件流包括三个阶段,首先发生的是事件捕获,为截取事件提供机会,而后是实际目标接收事件,最后是冒泡阶段浏览器
demoapp
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>JS Bin</title> <style> .box1{ border:1px solid black; padding:10px; } </style> </head> <body> <div class="container box1"> container <div class="box box1"> box <div class="target box1">target</div> </div> </div> </body> <script> var container= document.querySelector('.container') var box= document.querySelector('.box') var target=document.querySelector('.target') target.addEventListener('click',function(){ console.log('target in 捕获') },true) box.addEventListener('click',function(){ console.log('box in 捕获') },true) container.addEventListener('click',function(){ console.log('container in 捕获') },true) target.addEventListener('click',function(){ console.log('target in 冒泡') },false) box.addEventListener('click',function(){ console.log('box in 冒泡') },false) container.addEventListener('click',function(){ console.log('container in 冒泡') },false) </script> </html>
执行结果:dom
![图片上传中...]异步
事件处理程序:事件触发后,执行响应对应事件的程序。
事件处理程序是预先设定的,咱们须要提早定义好某些事件发生了该怎么处理,这个过程叫作绑定事件处理程序
2.1原理:
JavaScript指定事件处理程序就是把一个函数赋值给一个元素的事件处理程序属性(如onclick)
2.2绑定的过程:
选中元素,选中事件处理程序属性如onclick,给属性赋值一个处理函数。
<input id="btnClick" type="button" value="Click Here" /> <script > var btnClick = document.getElementById('btnClick'); btnClick.onclick = function showMessage() { alert(this.id); }; </script>
2.3不足:
不能给同一个元素的同一个事件处理程序属性绑定多个事件处理函数,会产生覆盖的。
3.1简介
DOM2事件处理程序能够解决不能绑定多个事件处理函数的问题
DOM2级事件定义了两个方法用于处理指定和删除事件处理程序的操做:
3.2 addEventListener使用
addEventListener有三个参数
3.3举个栗子
<input id="btnClick" type="button" value="Click Here" /> <script > var btnClick = document.getElementById('btnClick'); btnClick.addEventListener('click', function() { alert(this.id); }, false); </script>
总结:addEventListener 和制定事件处理程序的不一样,一个是对属性赋值,另一个addEventListener是执行一个函数,能够屡次执行
3.4 removeEventListener解绑事件
经过addEventListener添加的事件处理程序只能经过removeEventListener移除,移除时参数与添加的时候相同
添加的匿名函数没法移除
<input id="btnClick" type="button" value="Click Here" /> <script > var btnClick = document.getElementById('btnClick') var handler=function() { console.log("hhhhhhhhh") } btnClick.addEventListener('click', handler, false) btnClick.removeEventListener('click', handler, false) </script>
在触发DOM上的某个事件的时候会产生一个事件对象event,这个对象包含着全部与事件有关的信息,包括产生事件的元素、事件类型等相关信息。
event对象包含与建立它的特定事件有关的属性和方法,触发事件的类型不一样,可用的属性和方法也不一样,可是全部事件都会包含
2.1bubbles:
默认为false,表示事件对象是否冒泡。
若是该属性为false,div.addEventListener方法在冒泡阶段监听不会触发。只能写成div.addEventListener('click', callback, true)在“捕获阶段”监听这个事件。
2.2cancelable:
默认为false,表示事件是否能够被取消.只有为true的时候,才能用Event.preventDefault()取消这个事件。
2.3preventDefault
阻止默认事件
<a href="http://baid.com">baidu</a> <script> document.querySelector('a').onclick= function(e){ e.preventDefault() console.log(this.href) if(/baidu.com/.test(this.href)){ location.href = this.href } } </script>
<form action="/login"> <input type="text" name="username"> <input type="submit"> </form> <script> document.querySelector('form').addEventListener('submit',function(e){ e.preventDefault() if(document.querySelector('input[name=username]').value==='sjz'){ this.submit() } }) </script>
2.4target和currenttarget
在事件处理程序内部,this始终等同于currentTarget,currentTarget为绑定事件的元素,而target是为触发事件的实际目标。
当存在嵌套的时候,二者不同,具体详情能够见这篇文章连接描述,或者中文版event.target 和 event.currentTarget。我这里不作赘述
2.5stopPropagation()
阻止事件在 DOM 中继续传播,防止再触发定义在别的节点上的监听函数,可是不包括在当前节点上其余的事件监听函数。
举个栗子
<style> .container, .box, .target{ border: 1px solid; padding: 10px; } </style> <button id="btn">click</button> <div class="container"> container <div class="box"> box <div class="target">target</div> </div> </div> <script> function $(selector){ return document.querySelector(selector) } var btn = $('#btn') btn.onclick = function (e){ console.log(e) } btn.addEventListener('click', function(evt){ console.log(this) console.log(btn) console.log(evt.target) }) $('.container').addEventListener('click', function(e){ console.log('contianer click.. in 捕获阶段') }, true) $('.box').addEventListener('click', function(e){ //e.stopPropagation() console.log('box click.. in 捕获阶段') }, true) $('.target').addEventListener('click', function(e){ console.log('target click.. in 捕获阶段') }, true) $('.container').addEventListener('click', function(e){ console.log('contianer click.. in 冒泡阶段') }, false) $('.box').addEventListener('click', function(e){ //e.stopPropagation() console.log('box click.. in 冒泡阶段') }, false) $('.target').addEventListener('click', function(e){ console.log('target click.. in 冒泡阶段') }, false) </script>
结果
没有给捕获阶段的box加e.stopPropagation()的结果
给捕获阶段的box加e.stopPropagation()以后的结果
哈哈哈写事件代理前,找到了这篇事件代理的文章用例子解释事件模型和事件代理,这里写事件模型的历史也写得至关棒,因此先就转载过来了。
利用事件模型的传播性质,将子元素的监听函数绑定到父元素上,经过事件传播去执行监听函数。
需求:给container里面全部box都绑定点击事件,点击时输出box的值
2.1方式一:foreach
原理:选中.box全部元素,获得一个类数组对象,遍历这个类数组对象,给.box元素一一绑click事件。
代码:
<div class="container"> <div class="box">box1</div> <div class="box">box2</div> <div class="box">box3</div> </div> <script> function $(selector){ return document.querySelector(selector) } function $$(selector){ return document.querySelectorAll(selector) } // $$('.box').forEach(function(node){ // node.onclick = function(){ // console.log(this.innerText) // } // })
结果
缺点:执行foreach选中的box时固定的,若是咱们后续再加上几个box,后加的box就没有绑定上点击事件。
代码连接
2.2方式二事件代理
原理:给container绑定点击事件,经过e.target获取点击事件目标
代码:
<div class="container"> <div class="box">box1</div> <div class="box">box2</div> <div class="box">box3</div> </div> <button id="add">add</button> <script> function $(selector){ return document.querySelector(selector) } function $$(selector){ return document.querySelectorAll(selector) } $('.container').onclick = function(e){ console.log(this) console.log(e.target) if(e.target.classList.contains('box')){//contain少写s console.log(e.target.innerText) } } var i = 4 $('#add').onclick = function(){ var box = document.createElement('div') box.classList.add('box') box.innerText = 'box' + (i++) $('.container').appendChild(box)//box加'' }
遇坑:
一、contain少写s
常见事件类型 | 解析 |
---|---|
click | 单击 |
dblclick | 双击 |
focus | 焦点,好比表单input把光标放上去开始输入的时刻 |
blur | 失去焦点,好比输入完成切换到下一个输入框时,就失去了焦点 |
keyup | 按键按下松开的时候触发, |
change | 好比input失去焦点而且值发生了改变 |
submit | 表单提交的时候触发 |
scroll | 页面滚动的时候触发,注意使用函数节流 |
resize | 页面面积变化触发,注意使用函数节流 |
DOMContentLoaded | DOM 结构解析完成,不用等图片解析 |
load | 页面全部资源(图片css 等)加载完成触发,触发时间比较晚 |
mouseover | 鼠标放上去触发,注意进入元素的子元素会重复触发 |
mouseout | 鼠标拿出去触发,注意离开元素的子元素会重复触发 |
mouseenter | 鼠标进入触发,进入子元素不会触发,比较经常使用 |
mouseleave | 鼠标离开触发,离开子元素不会触发,比较经常使用 |
演示代码:直接复制代码到编辑器,在浏览器去测试这些事件
或者点击这个连接测试
<button id="btn">点我</button> <button id="btn1">点我1</button> <div class="ct" style="font-size: 20px"> <div class="box">hello</div> </div> <div class="ct1"> <div class="box1"></div> </div> <input id="input-name" type="text"> <form id="form" action="/upload"> <input id="username" name="username" type="text"> <p class="msg"></p> <input id="btn-submit" type="submit" value="注册"> </form> <img src="https://jirengu.com/data/upload/2017/0118/17/587f39fba695a.png" alt=""> <script> function $(selector){ return document.querySelector(selector); } $('#btn').addEventListener('click', function(){ console.log('click') console.log(this) }) $('#btn1').addEventListener('dblclick', function(){ console.log('dblclick') console.log(this) }) $('.ct').addEventListener('mouseover', function(){ console.log('mouseover') console.log(this) // this.style.borderColor = 'blue' this.classList.add('hover') }) $('.ct').addEventListener('mouseout', function(){ console.log('mouseout...') // this.style.borderColor = 'red' this.classList.remove('hover') }) $('.ct1').addEventListener('mouseenter', function(){ console.log('mouseenter...') //this.style.borderColor = 'blue' this.classList.add('hover') }) $('.ct1').addEventListener('mouseleave', function(){ console.log('mouseleave...') //this.style.borderColor = 'blue' this.classList.remove('hover') }) $('#input-name').addEventListener('focus', function(){ console.log('focus...') console.log(this.value) }) $('#input-name').addEventListener('blur', function(){ console.log('blur...') console.log(this.value) }) $('#input-name').addEventListener('keyup', function(e){ console.log('keyup...') console.log(this.value) console.log(e) this.value = this.value.toUpperCase() }) $('#input-name').addEventListener('change', function(e){ console.log('change...') console.log(this.value) console.log(e) this.value = this.value.toUpperCase() }) $('#form').addEventListener('submit', function(e){ e.preventDefault(); if(/^\w{6,12}$/.test($('#username').value)){ $('#form').submit(); }else{ $('#form .msg').innerText = '出错了' $('#form .msg').style.display = 'block' console.log(' no submit...'); } }) window.addEventListener('scroll', function(e){ console.log('scroll..') }) window.addEventListener('resize', function(e){ console.log('resize..') }) //页面全部资源加载完成 window.onload = function(){ console.log('window loaded') } //DOM 结构解析完成 document.addEventListener('DOMContentLoaded', function(){ console.log('DOMContentLoaded ') }) console.log($('img').width) //0 $('img').onload = function(){ console.log(this.width) //此时才能获得图片的真实大小 } </script> <style> body{ color: blue; } .ct,.ct1{ width: 100px; height: 100px; border: 1px solid red; background-color: yellow; margin: 20px; } .box,.box1{ width: 50px; height: 50px; background-color: blue; } .ct.hover, .ct1.hover{ border-color: blue; background-color: pink; } .box3{ list-style: none; background: yellow; margin: 0; padding: 0; } .box3>li{ background: pink; margin: 5px; padding: 10px; } .box3>li.hover{ background-color: blue; } .msg{ display: none; } </style>
var EventCenter = { on: function(type, handler){ document.addEventListener(type, handler) }, fire: function(type, data){ return document.dispatchEvent(new CustomEvent(type, { detail: data })) } } EventCenter.on('hello', function(e){ console.log(e.detail) }) EventCenter.fire('hello', '你好')