事件冒泡与捕获
<div class="a1">
<div class="a2">
<div class="a3">
</div>
</div>
</div>
当我们点击a3时,则点击事件传递开始,顺序为a1->a2->a3->a3->a2->a1
前半部分a1->a2->a3我们称之为捕获过程
后半部分a3->a2->a1我们称之为冒泡过程
在不使用任何框架下,通过原生js的addEventListener方法给Dom添加监听事件。
addEventListener(event,fn,useCapture),其中event为click,blur,focus等事件,fn为函数,useCapture默认不传为false,用来控制是否捕获触发。
js中通过stopPropagation来阻止事件的继续传递,若在a2添加stopPropagation,则只会执行a1->a2
e.currentTarget 指向捕获事件的对象; e.target 指向发生这个事件的对象
<script>
var a1 = document.querySelector(".a1");
a3.addEventListener("click",clickHandler);
function clickHandler(e){
console.log(e.currentTarget); //a1
console.log(e.target); //a3
}
</script>
事件委托
事件委托 将子元素或者后代元素的事件委托给父元素
减少事件侦听的增加,防止内存泄漏,内存泄漏是指当创建多个对象后并没有回收,
可以给变量null进行堆的回收,每隔一段时间浏览器就会有垃圾回收车进行回收内存。
事件委托例子
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
ul {
max-height: 1000px;
transition: all 0.5s;
overflow: hidden;
}
</style>
</head>
<body>
<ul class="menu">
<li>
北京
<ul>
<li>朝阳</li>
<li>
昌平
<ul>
<li>沙河</li>
<li>老牛湾</li>
<li>回龙观</li>
<li>霍营</li>
<li>天通苑</li>
</ul>
</li>
<li>海淀</li>
<li>东城</li>
<li>通州</li>
</ul>
</li>
<li>上海</li>
<li>山西</li>
<li>
陕西
<ul>
<li>西安</li>
<li>
咸阳
<ul>
<li>泾阳</li>
<li>三原</li>
<li>淳化</li>
<li>旬邑</li>
</ul>
</li>
<li>铜川</li>
<li>宝鸡</li>
</ul>
</li>
<li>河北</li>
<li>河南</li>
</ul>
<script>
var menu = document.querySelector(".menu");
menu.addEventListener("click", clickHandler);
function clickHandler(e) {
if (e.target.nodeName !== "LI") return;
if (
e.target.firstElementChild &&
e.target.firstElementChild.nodeName === "UL"
) {
if (!e.target.bool) {
e.target.firstElementChild.style.maxHeight = 0;
e.target.bool = true;
} else {
e.target.firstElementChild.style.maxHeight = "1000px";
e.target.bool = false;
}
}
}
</script>
</body>
</html>
事件
// 早期的事件会自动设计了一个event全局变量,用于事件的处理
// 同步执行时不会丢失,异步执行延迟会清除
// 只能执行一个函数
// 有冒泡功能,没有捕获功能,这样写大多数都会写出匿名函数
// 大多数的回调地狱都是在事件函数中发生的,原因时匿名函数的使用
// 不支持自定义事件
//=======================================================
//现在的事件
// 一般这种事件不写匿名函数,写命名函数,适合于函数式编程
// 这种事件包括捕获,冒泡阶段和阻止,还包括自带事件event对象
// 是否执行一次,它支持自定义事件,可以执行多个函数
// 写起来麻烦,IE8及以下不支持
// onclick等所有系统事件,将会去掉on
// bn.addEventListener("click",clickhandler2);
//=========================================================
// IE11以下支持,IE11及以上不支持
// 没有捕获阶段触发
// var bn=document.querySelector("button");
// bn.attachEvent("onclick",clickHandler3);
// bn.attachEvent("onclick",clickHandler4);
// function clickHandler3(e){
// console.log("abc");
// }
// function clickHandler4(e){
// console.log("cde")
// bn.detachEvent("onclick",clickHandler4)
// }
//submit和reset
var form=document.querySelector("form");
form.addEventListener("submit",submitHanlder);
form.addEventListener("reset",submitHanlder);
function submitHanlder(e){
// 阻止表单提交跳转 submit
// 阻止表单重置 reset
e.preventDefault();//阻止默认事件行为
console.log(e);
// e.returnValue=false;//兼容写法
}
//select 针对input或者textArea的
var input=document.querySelector("input");
input.addEventListener("select",selectHandler);
function selectHandler(e){
console.log(e);
// console.log(input.selectionStart,input.selectionEnd)
input.value=input.value.slice(0,input.selectionStart)+input.value.slice(input.selectionStart,input.selectionEnd).toUpperCase()+input.value.slice(input.selectionEnd)
}
//change 可以针对表单元素,也可以针对form表单
//失去焦点时,原value的值发生改变时,触发
var input=document.querySelector("input");
//判断整个表单的修改
var form=document.querySelector("form");
form.addEventListener("change",changeHandler);
function changeHandler(e){
console.log(e.target,e.target.value);
}
//resize 更改浏览器中文档的大小 window侦听
resizeHandler();
window.addEventListener("resize",resizeHandler);
function resizeHandler(e){
// console.log(screen.width)
document.documentElement.style.fontSize=document.body.clientWidth/screen.width*100+"px";
}
//load 加载完成
window.addEventListener("load",loadHandle
鼠标事件
/*
MouseEvent对象中
按住键盘辅助键点击
altKey: false
ctrlKey:false
shiftKey:false
metaKey:false
判断鼠标按键
button: 0 1 2
buttons: 1 4 2
which 1 2 3
// 坐标
// clientX x 相同都是鼠标相对视口距离
clientX: 495
clientY: 87
x: 221
y: 48
是相对e.target左上角的坐标
layer如果目标元素e.target定位了,offset和他相同
如果目标元素e.target没有定位,offset不变,layer相对父元素的左上角位置
layerX: 293
layerY: 73
offsetX: 293
offsetY: 73
用于Mousemove事件,相对上次移动的距离
movementX: 0
movementY: 0
// 绝对于屏幕左上角位置
screenX: 293
screenY: 144
// 相对页面顶端左上角位置
pageX: 221
pageY: 48
addEventListener可监听的事件
click
dblclick
mousedown
mouseup
mousemove
mouseover
mouseout
mouseenter
mouseleave
contextmenu 单击右键
*/
封装ajax
;(function(win){
function ajax(options){
if(!isObject(options))options = {};
var _default = {
type:"GET",
dataType:"html",
jsonp:"callback"
}
for(var attr in options){
_default[attr] = options[attr];
}
options = _default;
options.type = options.type.toUpperCase();
if(isObject(options.data)){
var _data = "";
for(var p in options.data){
_data+="&"+p+"="+options.data[p];
}
_data = _data.slice(1);
console.log(_data);
if(options.type === 'GET'){
options.url+="?"+_data;
}
options.data = _data;
}
switch (options.dataType){
case "jsonp":
return _jsonp(options);
default:
return _xhr(options);
}
}
function _jsonp(options){
return new Promise(function(fulfill,reject){
var glovbal_fn_name = "GP"+ Date.now()+Math.random();
glovbal_fn_name = glovbal_fn_name.replace(/0\./g,"_");
win[glovbal_fn_name] = function (res){
delete win[glovbal_fn_name];
fulfill(res);
typeof options.callback === "function" ?options.callback(res):"";
}
})
}
function _xhr(options){
return new Promise(function(fulfill,reject){
var xhr = new XMLHttpRequest();
xhr.open(options.type,options.url);
if(options.type === "POST"){
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
}
xhr.send(options.type === "POST" ? options.data:null);
xhr.onreadystatechange = function (){
if(xhr.readyState === 4 && /^2\d{2}$/.test(xhr.status)){
var data = xhr.responseText;
switch(options.dataType){
case "json":
data = JSON.parse(data);
break;
case "html":
data = data;
}
fulfill(data);
typeof options.callback === "function" ? options.callback(data):"";
}
}
})
}
function isObject(data){
return (typeof data === "object" && data !== null && !(data instanceof Array));
}
win.ajax = ajax;
})(window);