DOM事件
一、事件流
描述的是从页面中接收事件的顺序(当你点击一个容器里的子控件时,默认同时也点击了这个父容器)。
事件冒泡(ie):事件最开始由最具体的元素接收,然后逐级向上传播到最不具体的结点(子 -- 父 -- 祖父 --..--document )
事件捕获(ne):不具体的结点首先接收到事件,最具体的结点最后接收到,与冒泡相反
二、事件处理程序
1、HTML事件:直接在标签里添加的事件
<input id="btn" type="button" onclick="fun()" value="按钮"/> //log()是定义在js中的一个函数
缺点:HTML和JS代码紧密的耦合在一起
2、DOM 0级事件:把一个函数赋值给一个事件 【ie】
var btn=document.getElementById('btn');
btn.onclick = function(){ //添加事件
console.log('被点击了');
}
btn.onclick = null; //删除事件
3、DOM 2级事件:定义了两个方法用于处理和删除事件 (chrome)
addEventListener( ...)、removeEventListener(event, listener, useCapture) :第一个参数 要处理的事件名、第二个参数事件处理的函数、第三个布尔值,表明事件是在冒泡阶段(false)还是捕获阶段(true)时调用
btn.addEventListener("click", function(){
console.log('addEvent被点击的');
}, false);
btn.removeEventListener("click",fun,false); //通过addEL添加的事件处理只能有removeEL删除
4、IE 事件处理程序:添加 、删除事件 ( IE8之前只支持冒泡、欧普)
attachEvent( ...)、detachEvent(eventType, function) :第一个参数 事件处理名称、第二个 事件处理的函数
btn.attachEvent("onclick",log ); //注意是带 on 的
5、IE跨浏览器的事件处理程序:考虑兼容 ,需要封装一个对象方法
/**
* 解决浏览器兼容 事件处理程序
* @param {[type]} element 事件源
* @param {[type]} type 事件处理类型(click/mouseover...)
* @param {[type]} handler 处理事件
*/
function addHandler(element,type,handler){
//如果支持DOM 2级事件处理程序
if(element.addEventListener){
element.addEventListener(type,handler,false);
} else if(element.attachEvent){ //支持IE 的事件处理程序
element.attachEvent('on'+type,handler);
} else{ //支持DOM 0级
element['on'+type]= handler;
}
}
//移除事件
function removeHandler(element,type,handler){
//如果支持DOM 2级事件处理程序
if(element.addEventListener){
element.removeEventListener(type,handler);
} else if(element.attachEvent){ //支持IE 的事件处理程序
element.detachEvent('on'+type,handler);
} else{ //支持DOM 0级
element['on'+type]= null;
}
}//调用方法
addHandler(btn4,'click',fun);
removeHandler(btn4,'click',fun);
三、事件对象
触发DOM上事件产生的对象
1、DOM中的事件对象event ( 调用 : event.type ) ---IE无用
1)type :事件类型( click )
2)target :事件目标( 事件源)
3)stopPropagation():阻止事件冒泡
4)preventDefault(): 阻止事件的默认行为 (a标签的跳转页面)
2、IE中的事件对象( window.event )
在使用event时要先做一个兼容性:var event= event || window.event;
1)type :事件类型( click )
2) srcElement:事件源 【IE8获取得到的类型是object】
3) cancelBubble:阻止事件冒泡(这是一个属性,true为阻止冒泡)
4) returnValue:阻止默认事件(false表示阻止事件默认行为)
3、封装方法解决兼容性
//封装事件方法的对象
var eventUtil={
//获取事件对象
getEvent:function(event){
return event|| window.event; //兼容IE
},
//获取事件对象类型
getType:function (event){
return event.type;
},//事件源
getTarget:function (event){
return event.target || event.srcElement;
},//阻止事件冒泡
stopPropagation:function (event){
if(event.stopPropagation){
event.stopPropagation();
} else{ //IE事件
event.cancelBubble=true;
}
},//阻止默认行为
preventDefault:function (event){
if(event.preventDefault){
event.preventDefault();
} else{ //IE事件
event.returnValue=false;
}
}
}
四、事件类型
document.keyUp=function(event){ var event=event || window.event; console.log(event.keyCode); }
动画
一、速度动画
/**
* 实现对象的左右移动
* @param {[type]} obj 目标对象
* @param {[type]} target 移动终点
* @param {[type]} speed 移动速度
* @return {[type]} 无返回
*/
function move(obj,target,speed){
clearInterval(obj.timer); //清空计时器,
obj.timer=setInterval(function(){ //自定义定时器
var left=obj.offsetLeft; //number 数值
if(left>target){ //当前位置在目标值的右边,则速度为负
speed=speed <0 ? speed:-speed; //速度值,保持为负数
console.log('speed'+speed);
}
//如果移动的某一时间段在一定的范围内,则直接设为目标值
if( Math.abs( Math.abs(left)-Math.abs(target) ) < Math.abs(speed) ){
obj.style.left=target+'px'; //达到目标值
console.log('=='+left);
clearInterval(obj.timer);
} else{
left+=speed; //移动
obj.style.left=left+'px';
console.log('left'+left);
}
},50);
}
二、透明度动画
<!-- 样式-->
div{
width: 200px;
height: 200px;
background-color: blue;
filter:alpha(opacity:10); /*滤镜效果*/
opacity:0.1;
}
var alpha=10; //先获取opacity的值
/**
* 改变透明度的动画 ---要先取得当前对象的opacity(透明度)
* @param {[type]} obj 目标对象
* @param {[type]} target 目标透明度值 0-1
* @param {[type]} speed 变化速度 1-100
* @return {[type]} 无返回值
*/
function changeOpacity(obj,target,speed){
clearInterval(obj.timer); //清除
obj.timer=setInterval(function(){ //自定义的定时器
var current=alpha/100; //当前透明度0-1
if(current>target){ //当前透明度更低,更不透明(越接近1)
speed=speed <0 ? speed:-speed; //速度值,保持为负数
console.log('speed'+speed);
}
//如果透明度的变化将达到目标值,则直接设为目标值
if( Math.abs( Math.abs(current)-Math.abs(target) ) < Math.abs(speed/100) ){
obj.style.filter='alpha(opacity:'+target*100+')'; //达到目标值
obj.style.opacity=target; //设为目标值
clearInterval(obj.timer);
} else{
alpha+=speed; //改变透明度 0-100
console.log("alpha"+alpha);
obj.style.filter='alpha(opacity:'+alpha+')';
obj.style.opacity=alpha/100; //设置透明度属性
}
},50);
}
//解决多物体同时运行的冲突
obj.alpha=10; //通过自定义属性的方式获取到透明度的值
三、缓冲动画
/**
* 缓冲运动,速度是逐渐变小
* @param {[type]} obj 目标对象
* @param {[type]} target 移动终点
* @param {[type]} speed 移动速度(可不传参
* @return {[type]} 无返回
*/
function move(obj,target,speed){
clearInterval(obj.timer); //清空计时器,
obj.timer=setInterval(function(){ //自定义定时器
var left=obj.offsetLeft; //number 数值
speed=(target-left)/10;
console.log("speed1::"+speed);
speed= speed > 0 ? Math.ceil(speed) : Math.floor(speed);
//解决小数【注意是向上/向下取整
console.log("speed2::"+speed);
//如果移动的某一时间段在一定的范围内,则直接设为目标值
if(left==target){
//达到目标值
clearInterval(obj.timer);
} else{
obj.style.left=left+speed+'px';
}
},50);
}
四、自定义属性的动画
获取样式:作用请看 来源(当变化宽高,而设定css样式时有border属性,最后变化是不一样的 )
/**
* 获取对象的样式
* @param {[type]} obj 目标对象
* @param {[type]} attr 样式参数
* @return {[type]} 对应的样式值
*/
function getStyle(obj,attr){
console.log(typeof attr);
if(obj.currentStyle){
return obj.currentStyle[attr]; //ie浏览器
} else {
return getComputedStyle(obj,false)[attr]; //火狐
}
}
//调用:
console.log(getStyle(box,'width'));
/**
* 自定义属性的动画,改变样式【宽高等单位为px的属性】
* @param {[type]} obj 目标对象
* @param {[type]} target 变化结果
* @param {[type]} attr 变化的属性
*/
function move(obj,target,attr){
clearInterval(obj.timer); //清空计时器,
obj.timer=setInterval(function(){ //自定义定时器
var myStyle=parseInt( getStyle(obj,attr) ); //获取当前属性值,并转化为number
console.log(myStyle);
var speed=(target-myStyle)/10;
speed= speed > 0 ? Math.ceil(speed) : Math.floor(speed);
if(myStyle==target){
//达到目标值
clearInterval(obj.timer);
} else{
obj.style[attr] = myStyle+speed+'px';
}
},50);
}
//透明度属性
//传参数时,透明度为0-100,对应0-1
if(attr==='opacity'){ //判断是否为透明度
var myStyle=parseFloat( getStyle(obj,'opacity') )*100 ; //小数
myStyle=Math.round(myStyle); //四舍五入解决不精确
}
if(attr==='opacity'){
obj.style.filter='alpha(opacity:'+myStyle+speed+')';
//设置透明度
obj.style[attr]=(myStyle+speed)/100 ;
}
五、链式动画(连续动画)
增加函数参数,当执行完动画后,调用了此回调函数,再次进行动画
function move(obj,target,attr,fun){
....
if(myStyle==target){
//达到目标值
clearInterval(obj.timer);
if(fun){ //判断是否有值
fun(); //设为并执行函数
}
}
}
box.οnmοuseοver=function(){
move(box,100,'opacity',function(){ //回调函数
move(box,100,'width',400);
});
}
五、完成动画--运动框架--实现多物体同时进行 多动画
运动框架--速度动画
<script type="text/javascript">
var box=document.getElementById('box');
var box2=document.getElementById('box2');
box.οnmοuseοver=function(){
var json={'width':201,'height':300,'opacity':20};
move(box,json);
move(box2,json);
}
box.οnmοuseοut=function(){
var json2={'width':200,'height':200,'opacity':100};
move(box,json2);
move(box2,json2);
}
/**
* 运动框架--可完成多物体同时进行 多个动画
* @param {[type]} obj 对象
* @param {[type]} jsonTarAttr json={"变化的属性attr":变化的目标值}
* @param {[type]} fun 回调函数
*/
function move(obj,jsonTarAttr,fun){
clearInterval(obj.timer); //清空计时器,
obj.timer=setInterval(function(){ //自定义定时器
for(var attr in jsonTarAttr){ //遍历json
var flag=true;
//解决当一个动画已经完成时,清除了定时器使后续的动画还未完成就结束
if(attr==='opacity'){
var myStyle=parseFloat( getStyle(obj,'opacity') )*100 ; //小数
myStyle=Math.round(myStyle); //四舍五入解决不精确
} else{
var myStyle=parseInt( getStyle(obj,attr) );
}
var speed=(jsonTarAttr[attr]-myStyle)/10;
speed= speed > 0 ? Math.ceil(speed) : Math.floor(speed);
if(myStyle!=jsonTarAttr[attr]){
flag=false; //动画为全部完成的标记
console.log("d");
if(attr==='opacity'){
obj.style.filter='alpha(opacity:'+myStyle+speed+')';
//设置透明度
obj.style[attr]=(myStyle+speed)/100 ;
} else {
obj.style[attr] = myStyle+speed+'px';
}
}
}
if(flag){ //动画全部完成
clearInterval(obj.timer);
if(fun){
fun(); //设为并执行函数
}
}
},50);
}
/**
* 获取对象的样式
* @param {[type]} obj 目标对象
* @param {[type]} attr 样式参数
* @return {[type]} 对应的样式值
*/
function getStyle(obj,attr){
if(obj.currentStyle){
return obj.currentStyle[attr]; //ie浏览器
} else {
return getComputedStyle(obj,false)[attr]; //火狐
}
}
</script>