事件(下)
1、事件流
事件流是描述的从页面接受事件的顺序,当几个都具有事件的元素层叠在一起的时候, 那么你点击其中一个元素,并不是只有当前被点击的元素会触发事件,而层叠在你点击范围的所有元素都会触发事件。事件流包括两种模式:冒泡和捕获。
(1)事件冒泡
事件冒泡是从里往外逐个触发。但是一般我们只在指定的节点上添加事件, 而不想让其传递到下层节点触发事件, 这样我们就需要阻止事件冒泡。
阻止事件冒泡
1, 取消冒泡, IE
e.cancelBubble = true;
2, 停止传播, 非IE
e.stopPropagation();
e.stopPropagation?e.stopPropagation():e.cancelBubble = true //事件冒泡的兼容写法
//从里到外执行的
bigbox.onclick = function(e){
console.log('大盒子的点击事件触发了');
this.style.backgroundColor = 'red'
}
innerBox.onclick = function(e){
console.log('里面的盒子的点击事件触发了');
this.style.backgroundColor = 'blue'
}
content.onclick = function(e){
e = e || event //兼容ie
console.log('主体内容的点击事件触发了');
this.style.backgroundColor = 'yellow'
// e.stopPropagation(); //阻止事件冒泡 stopPropagation 函数
e.cancelBubble = true //ie的兼容 取消事件冒泡 未来可能会废弃
// e.stopPropagation?e.stopPropagation():e.cancelBubble = true 兼容写法
}
(2)事件捕获
事件捕获, 是从外往里逐个触发。现代的浏览器默认情况下都是事件冒泡的模式。
2、默认行为
默认行为指的是一个元素会自带的行为称为默认行为 a标签的默认行为会跳转 form标签里面submit按钮默认会提交(刷新页面)鼠标右键会出现一个菜单栏 等等一系列的问题。有些时候我们不需要这些行为的产生 那么我们就需要阻止默认行为。
阻止默认行为
- e.preventDefault() 函数 (prevent)
- e.returnValue = false ie的兼容
- return false 直接结束对应的操作
e.preventDefault?e.preventDefault():e.returnValue = false //阻止默认行为的兼容写法
document.querySelector('a').onclick = function(e){
e = e || event
// e.preventDefault() //阻止默认行为
// e.returnValue = false //ie的兼容
console.log('hello');
//一定是放在最后面
return false //函数的结束 gc垃圾回收机制会准备回收
}
//阻止表单的默认提交行为
document.querySelector('form').onsubmit= function(e){
e = e || event
// e.preventDefault() //阻止默认行为
e.preventDefault?e.preventDefault():e.returnValue = false //兼容
console.log('表单提交');
}
3、拖拽
所谓拖拽: 就是按住元素后移动位置, 最后松开的过程
拖拽的思路:
- 给拖拽的元素添加mousedown的事件 记录当前点击的位置
- 给对应的容器添加mousemove事件 记录每次移动的位置
- 给对应的容器添加mouseup 事件 清除上述mousemove事件
//获取div
var box = document.getElementById('box')
//给div添加mousedown事件
box.onmousedown = function(e){
e = e || event
//记录的是鼠标在div里面的位置
//在mousedown里面记录按下的位置
var x = e.offsetX
var y = e.offsetY
// var x = e.pageX-box.offsetLeft
// var y = e.pageY-box.offsetTop
//给document添加mousemove事件
document.onmousemove = function(e){
e = e || event
//记录每次的位置 在document里面的位置
var currentX = e.pageX
var currentY = e.pageY
//并且设置div的位置
box.style.left = currentX - x + "px"
box.style.top = currentY - y + "px"
}
//给document添加mouseup事件
document.onmouseup = function(){
//清除对应的mousemove事件
document.onmousemove = null
}
}
4、获取style样式
style属性 只能获取标签内容style属性里面存在的一些样式
如果你需要获取对应的全局所有地方设置样式 我们就需要采用一些方法
getComputedStyle 方法属于window的方法
window.getComputedStyle(元素对象,null) //返回给你的是一个样式对象
ie兼容
element.currentStyle //返回给你一个样式对象
var box = document.querySelector('div')
//通过style来获取样式 返回CSSStyleDeclaration对象 这个对象里面只存在对应style里面设置的样式
console.log(box.style.width); //100px
console.log(box.style.height); //空文本
//明显可以看出对应的style直接获取是不足 他获取不到内联样式以及外联的样式
//所以我们对应的window有对应的方法来获取所有地方的样式
var styleObj = window.getComputedStyle(box) //这个方法是属于window 传入元素
console.log(styleObj.width);
console.log(styleObj.height);
console.log(styleObj.backgroundColor);
console.log(styleObj.color); //返回默认值
//IE的兼容
console.log(box.currentStyle);//返回样式对象
//兼容写法
var style = window.getComputedStyle?window.getComputedStyle(box):box.currentStyle
//方法的封装
function getStyle(element,attr){
var style = window.getComputedStyle?window.getComputedStyle(element):element.currentStyle
return style[attr]
}
console.log(getStyle(box,'height'));
5、事件委托
指的是将对应的子元素的事件添加给父元素,用e.target来获取真实操作的元素 从而完成相关的操作(不能用到事件委托的 mouseenter 和 mouseleave 以及 mousemove..)
//事件委托 利用父元素添加事件 通过e.target获取真实的操作元素来进行相关的操作
//当你有许多需要同时添加一个事件行为的同级元素 这个时候我们不给这些元素加事件
// 而是给他的父元素添加事件 称为事件委托
gameList.onmouseover = function(e){
e = e || event
//控制对应的li标签的背景颜色变化 得到实际的触发对象 target
if(e.target.nodeName == 'LI'){
//先排他
for(var i=0;i<games.length;i++){
this.children[i].style.backgroundColor = 'black'
}
e.target.style.backgroundColor = 'red'
}
}
// 5, 选择某一项, 将顶部的名称改成你选择的游戏名称
gameList.onclick = function(e){
e = e || event
if(e.target.nodeName == 'LI'){ //如果当前的e.target是li的话 才执行对应的操作
title.innerText = e.target.innerText
}
}
6、offset家族
- offsetParent 偏移的父元素(一层一层的向上找 找到定位的元素就是对应的父元素 有定位的上层元素就他的父元素 找不到的就是body)
- offsetLeft 基于偏移的父元素的左偏移量
- offsetTop 基于偏移的父元素的上偏移量
- offsetHeight 获取偏移元素的高度(包含border以及padding)
- offsetWidth 获取偏移元素的宽度(包含border以及padding)
7、区间拖拽
指的是在一个区间内进行拖拽
//拖拽的方法实现 第一个是移动的盒子 第二个在哪移动
function tuoch(moveBox,box){
//给moveBox添加按下事件 记录一下当前鼠标在moveBox里面点击的位置
moveBox.onmousedown = function(e){
e = e || window.event
//获取对应的第一次按下的位置
var firstX = e.offsetX
var firstY = e.offsetY
// console.log(document.body.offsetParent); //偏移的父元素
//给box添加move事件 记录每次的位置 在box的位置 设置moveBox在box的定位
box.onmousemove = function(e){
e = e || event
//这个108是对应的box离body的距离 这个距离就是box偏移的距离
//offsetLeft 得到基于父元素左偏移量 offsetTop 得到基于父元素的上偏移量
//offsetParent 基于的父元素 基于定位的 他会一层层往上找 找到定位的父元素就基于他 如果没有找到就基于body
//有奶便是娘 谁有定位他就基于谁
var currentX = e.pageX - getOffset(this).left
var currentY = e.pageY - getOffset(this).top
var targetX = currentX - firstX
var targetY = currentY - firstY
//判断边界 offsetWidth 得到盒子的宽度 offsetHeight得到盒子的高度
if(targetX<0){
targetX = 0
}
if(targetY<0){
targetY = 0
}
if(targetX>this.offsetWidth-moveBox.offsetWidth){
targetX = this.offsetWidth-moveBox.offsetWidth
}
if(targetY>this.offsetHeight-moveBox.offsetHeight){
targetY = this.offsetHeight-moveBox.offsetHeight
}
// 设置moveBox在box的定位
moveBox.style.left = targetX + 'px'
moveBox.style.top = targetY + 'px'
}
//给box添加弹起事件 清除box的move事件
document.onmouseup = function(){
box.onmousemove = null
}
}
}
获取对应的盒子离最外层body的left值及top值
//获取对应的元素离body的距离 传入一个元素
function getOffset(element) {
var left = 0
var top = 0
while (element) {
left += element.offsetLeft
top += element.offsetTop
element = element.offsetParent
}
return {
left,
top
}
}
8、事件监听器
事件监听器, 是JS事件中的一种事件触发机制, 我们可以通过添加事件监听器的方式给元素添加事件及执行函数。
1、添加事件监听器
box.addEventListener(“click”, func, false) : 给box元素添加点击事件(click), 以及事件执行函数func. 针对该函数的三个参数作说明:
- 第一个参数(“click”) : 事件名称(前面没有on)
- 第二个参数(func): 事件执行函数名称(没有双引号, 也没有())
- 第三个参数(false/true) : 是否使用捕捉(反向冒泡),默认false,为冒泡
2、移除事件监听器
box.removeEventListener(“click”, func) : 将box元素的点击事件(click), 以及对应的事件执行函数func移除
注: 这里只会删除使用box.addEventListener()方法添加的事件监听器
//是否捕获 默认为不捕获(冒泡)
// 同时给一个事件加多个处理函数 (事件只会调用一次)
btn.addEventListener('click',function(){
console.log('点击了');
},true)
btn.addEventListener('click',function(){
console.log('点击了1');
},true)
btn.addEventListener('click',function(){
console.log('点击了2');
},true)
btn.addEventListener('click',function hello(){
console.log('点击了3');
})
btn.removeEventListener('click',function hello(){
console.log('点击了3');
})//不能被移除
//移除事件监听器 移除事件监听器根据对应的处理函数来的
//这个俩个函数对象不是一个对象 比对出不来 所以就删不掉
//所以我们如果需要删除对应的处理函数的话 那么必须在监听的时候 就要保证这个处理函数和对应的删除的时候的处理函数是一个
//正确示例
function sayHello(){
console.log('hello');
}
div.addEventListener('click',sayHello)
div.removeEventListener('click',sayHello)
兼容写法
//移除函数
function removeEvent(obj, type, fn, useCapture){
if (obj.removeEventListener) {
obj.removeEventListener(type, fn, useCapture);
}
else {
obj.detachEvent("on"+type, fn);
}
//三元的写法 obj.removeEventListener?obj.removeEventListener(type,fn,useCapture):obj.detachEvent("on"+type, fn);
}
//添加函数
function addEvent(obj, type, fn, useCapture){
if (obj.addEventListener) {
obj.addEventListener(type, fn, useCapture);
}
else {
obj.attachEvent("on"+type, fn);
}
//三元的写法 obj.addEventListener?obj.addEventListener(type,fn,useCapture):obj.attachEvent("on"+type, fn);
}