JavaScript事件流、事件类型、事件对象和事件委托

JavaScript事件流

事件流描述的是在页面中接受事件的顺序,分为事件冒泡事件捕获

事件冒泡指事件一级一级的往上触发,一直到根元素为止

事件捕获指事件从根元素开始触发,一直到触发元素的事件为止

事件绑定
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
DOM0级事件	直接在元素上绑定,绑定多个后面会覆盖前面
例如:
wrap.onclick=function(){
alert("a");
}
wrap.onclick=function(){
alert("b");//仅仅会弹出b,因为覆盖前面
}

DOM2级事件 可以多次绑定

addEventListener(type,fn,bol); 绑定事件
removeEventListener(type,fn,bol); 解除事件
type:事件类型
fn: 事件语句,必须是对应的非匿名函数
bol: 事件触发机制 false事件冒泡 true事件捕获
解除检测某个事件语句,type、fn、bol都必须对应相同

attachEvent(type,fn); IE上的DOM2级绑定事件
detachEvent(type,fn); IE上的DOM2级解除事件

wrap.addEventListener("click",function(e){
//匿名函数的匿名参数,表示触发的事件对象
//为了兼容IE低版本,需要使用window.event
var e=e||window.event;
console.log(e.currentTarget);
},false)

函数不添加(),就是执行代码块;添加(),就是执行结果

event对象

event对象代表事件的状态,比如事件在其中发生的元素、键盘按键的状态、鼠标的位置、鼠标按钮的状态。

事件通常与函数结合使用,函数不会在事件发生前被执行!

event方法

event.initEvent();初始化新创建的event对象的属性

event.preventDefault();阻止默认事件

event.stopPropagation();阻止事件继续派发

事件类型

UI事件:当用户与页面上的元素交互时触发

load事件:当页面加载完毕之后触发

resize事件:当浏览器窗口改变大小时候触发

scroll事件:当用户滚动一个带滚动条的元素时触发

鼠标事件:通过鼠标在页面上执行操作

contextmenu事件:弹出右键菜单

click事件:对象被点击时发生(在同一元素发生鼠标按下事件后又发生鼠标放开事件时才发生的)

mousedown事件:鼠标被按下时触发

mousemove事件:在鼠标指针移动时触发

mouseup事件:在鼠标按键松开时触发

mouseover事件:鼠标指针移动到指定的对象上时触发(鼠标指针穿过任何子元素,同样会触发事件)

mouseenter事件:当鼠标指针进入(穿过)指定元素时触发(只有鼠标指针穿过被选元素时才会触发)

mouseout事件:无论鼠标指针离开被选元素还是任何子元素都会触发mouseout事件(鼠标指针离开任何子元素,同样会触发事件)

mouseleave事件:只有在鼠标指针离开被选元素时,才会触发mouseleave事件(只有在鼠标指针离开被选元素时,才会触发)

mousewheel事件:非火狐滚轮事件

DOMMouseScroll事件:火狐滚轮事件

键盘事件:通过键盘在页面上执行操作

keydown事件:某个键盘按键被按下触发

keyup事件:某个键盘按键被松开触发

keypress事件:某个键盘被按下并松开触发

表单事件

focus事件:在对象获得焦点时发生

blur事件:在对象失去焦点时发生

change事件:当元素的值发生改变时在元素失去焦点时发生(可以作用于<input><textarea><keygen><select>元素)

input事件:当元素的值发生改变时立即发生(可以作用于<input><textara>元素)

触屏事件

touch事件:在用户触摸屏幕(页面)时触发

事件对象

clientX 当事件被触发时,鼠标指针的水平坐标。相对于可视区域

clientY 当事件被触发时,鼠标指针的竖直坐标。相对于可视区域

layerX 鼠标相对于定位父级border左上角的起始位置(包括border)

layerY 鼠标相对于定位父级border左上角的起始位置(包括border)

offsetX 鼠标相对于触发事件元素的位置,从内容区域的左上角开始定位(不包括border)

offsetY 鼠标相对于触发事件元素的位置,从内容区域的左上角开始定位(不包括border)

pageX 鼠标在页面上的位置,从页面左上角开始定位。相对于整个页面

pageY 鼠标在页面上的位置,从页面左上角开始定位。相对于整个页面

screenX 鼠标在显示屏幕上的坐标,相对于屏幕

screenY 鼠标在显示屏幕上的坐标,相对于屏幕

movementX 鼠标的移动距离 mousemove事件特有

movementY 鼠标的移动距离 mousemove事件特有

X 在IE里独有,跟layerX一个效果

Y 在IE里独有,跟layerY一个效果

alrKey 返回当事件被触发时,”ALT”是否被按下

button 当事件被触发时,哪个鼠标按钮被点击(0鼠标左键,1鼠标中键,2鼠标右键)IE(1鼠标左键,4鼠标中键,2鼠标右键)

bubbles 表明事件是否冒泡,是则返回true;否则返回false

cancelable 表明事件是否拥有可取消的默认动作

ctrlKey 当事件触发时,”CTRL”键是否被按下

currentTarget 返回其监听器触发的节点,即当前处理该事件的元素、文档或窗口。也就是事件绑定的元素,和this是一样的(在捕获和气泡阶段非常有用,在这两个节点不同于target属性)

defaultPrevented 是否阻止了默认事件

detail 判断滚轮向上或向下 火狐浏览器 正值表示页面向下滑动

wheelDelta 判断滚轮向上或向下 非火狐浏览器 负值表示页面向下滑动

eventPhase 返回事件传播的当前阶段。分别为捕获阶段、正常事件派发和气泡阶段

formElement 对于mouseover和mouseout事件,fromElement引用移出鼠标的元素

isTrusted 表明当前事件是否由用户行为触发

metaKey 当事件被触发时,”meta”键是否被按下

path 层级关系

relatedTarget 返回与事件的目标节点相关的节点。对于mouseover事件来说,该属性是鼠标指针移到目标节点上时所离开的那个节点。对于mouseout事件来说,该属性是离开目标时,鼠标指针进入的节点。对于其他类型的事件来说,这个属性没有用。

returnValue IE属性,它的值比事件句柄的返回值优先级高。把这个属性设置为false,可以取消发生事件的源元素的默认动作。

shiftKey 事件被触发时,”SHIFT”键是否被按下

srcElement IE属性,对于生成事件的window对象、document对象或element对象的引用

target 返回触发此事件的元素(事件的目标节点)

timeStamp 返回一个时间戳,距离页面打开的毫秒数

toElement 对于mouseover和mouseout事件,该属性引用移入鼠标的元素

type 当前event对象表示的事件的名称(如:”click”、”submit”、”load”等)

view 根元素

which 返回哪个键被按下了

事件委托

利用冒泡原理,把事件加到父级上,触发执行效果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<style>
.btntarget{
width:150px;
height:40px;
background-color:gray;
border:none;
font-size:20px;
border-radius:10px;
}
</style>
<button class="btntarget">增加一个li</button>
<ul class="ultarget">
<li>我是li1</li>
<li>我是li2</li>
<li>我是li3</li>
</ul>
<script>
var btnli=document.querySelector(".btntarget");
var ul=document.querySelector(".ultarget");
var lis=ul.getElementsByTagName("li");
var num=4;
btnli.addEventListener("click",function(){
var newLi=document.createElement("li");
newLi.innerHTML="我是li"+num;
ul.appendChild(newLi);
num++;
},false)
ul.onclick=function(){
var e=e||window.event;
var targets=e.target||e.srcElement;
for(var i=0;i<lis.length;i++){
if(targets==lis[i]){
alert(i);
}
}
}
</script>
    
    
    
  • 我是li1
  • 我是li2
  • 我是li3

JavaScriptBOM浏览器对象模型

BOM简介

BOM:Browser Object Model 是浏览器对象模型,浏览器对象模型提供了独立与内容的,可以与浏览器窗口进行互动的对象结构,BOM由多个对象构成,其中代表浏览器窗口的window对象是BOM的顶层对象,其他对象都是该对象的子对象。

BOM对象

window对象

window是根对象,screen、navigator、location、history都属于window,只不过我们使用这些方法的时候可以省略前面的window。

window.close();关闭浏览器窗口

window.open();打开一个新的浏览器窗口或查找一个已命名的窗口

window.innerWidth;浏览器可视区的宽度(在IE8及以下有兼容问题)

window.innerHeight;浏览器可视区的高度(在IE8及以下有兼容问题)

screen对象

screen对象包含有关客户端显示屏幕的信息。

screen.width;显示器的宽

screen.height;显示器的高

screen.availWidth;浏览器的屏幕可用的宽度

screen.availHeight;浏览器的屏幕可用的高度

navigator.appCodeName;浏览器的代码名

navigator.appVersion;浏览器的版本信息

navigator.platform;浏览器的操作系统和(或)硬件平台

navigator.userAgent;浏览器用于HTTP请求的用户代理头的值

location路径信息

location.host;返回主机名及端口

location.name;返回主机名

location.hash;锚 指#及其后面的值,只有一个值

location.href;完整的链接(URL)

location.pathname;当前URL的路径部分

location.port;端口号

location.protocol;当前URL的协议

location.search;问号(?)开始的URL(查询部分),到#为止

location.assign();加载新文档

location.reload();重新加载当前页面

location.replace();用新文档替换当前文档

history历史记录

history.length;返回浏览器历史列表中的URL数量

history.back();加载history列表中的前一个URL

history.forward();加载history列表中的下一个URL

history.go();加载history列表中的某个具体页面

JavaScriptDOM元素对象

在HTML DOM中,元素对象代表着一个HTML元素。

DOM元素对象类型主要有:

client

clientLeft左边框border-left-width

clientTop上边框border-top-width

clientHeight可视区的高度paddingTop+height+paddingBottom

clientWidth可视区的宽度paddingLeft+width+PaddingRight

offset

offsetWidth盒模型的宽borderLeft+paddingLeft+width+paddingRight+borderRight

offsetHeight盒模型的高borderTop+paddingTop+height+paddingBottom+borderBottom

offsetParent定位父级,离元素最近的设置了position属性的父元素(若无则为body)

offsetLeft到定位父级左边框borderLeft的距离

offsetTop到定位父级上边框borderTop的距离

scroll

scrollTop滚动条向上滚动的距离(滚动条滚动到可视区上面的距离)

scrollLeft滚动条向左滚动的距离(滚动条超出可视区左边的宽度)

scrollHeight滚动条的高度paddingTop+height(内容高度)+paddingBottom,最小值为clientHeight。

scrollWidth滚动条的宽度paddingLeft+width+paddingRight(当被包含元素的width超出包含元素的width时,包含元素的margin-right和padding-right都不起作用),最小值为clientWidth。

DOM浏览器兼容问题

主要兼容问题元素对象为scrollHeight、scrollTop和clientHeight,可通过三元运算来选择不同的设置来兼容不同浏览器。保险起见,可以都设置三元运算来避免浏览器兼容问题

例如:scrollTop=document.body.scrollTop?document.body.scrollTop:document.documentElement.scrollTop;

注意:浏览器可视区的宽高只能使用document.documentElement.clientWidthdocument.documentElement.clientHeight来表示

offsetLeft、offsetTop值的获取

    function offset(obj){
        var offset={};
        offset.left=obj.offsetLeft;
        offset.top=obj.offsetTop;
        while(obj.offsetParent){
            obj=obj.offsetParent;
            offset.left+=(obj.offsetLeft+obj.clientLeft);
            offset.top+=(obj.offsetTop+obj.clientTop);
        }
        return offset;
    }

onscroll事件

onscroll事件在元素滚动条滚动时触发。

object.onscroll=function(){myScript};

JavaScript瀑布流

瀑布流,又称瀑布流式布局。是比较流行的一种网站页面布局,视觉表现为参差不齐的多栏布局,随着页面滚动条向下滚动,这种布局还会不断加载数据块并附加至当前尾部。最早采用此布局的网站是Pinterest,逐渐在国内流行开来。

    <style>
        .flowul{
            position:relative;
            min-width:200px;
        }
        .flowul li{
            margin:0;
            padding:0;
            list-style-type:none;
            position:absolute;
            margin-bottom:10px;
            font-size:30px;
            text-align:center;
            color:black;
        }
    </style>
    <ul class="flowul"></ul>
    <script>
        var flowul=document.querySelector(".flowul");
        var window_W;//定义窗口的宽度
        var col;//定义列数
        var old;//定义现在的列数
        var arr=[];

        getWidth();
        old=col;//先给其一个当前的列数

        function getWidth(){
            arr=[];
            window_W=document.body.currentStyle?document.body.currentStyle.width:getComputedStyle(document.body,[]).width;//根据浏览器类型,选择合适的代码获取宽度
            window_W=parseInt(window_W);
            col=parseInt((window_W-30)/400);
            flowul.width=col*210-10+"px";
            for(i=0;i<col;i++){
                arr.push(0);
            }
        }

        //开始循环,排列出来所需要的li(及其个数)
        for(var i=0;i<20;i++){
            var newLi=document.createElement("li");
            newLi.style.width=200+"px";
            newLi.style.backgroundColor="rgb("+getRandom(0,255)+","+getRandom(0,255)+","+getRandom(0,255)+")";
            newLi.innerHTML=i+1;
            var newHeight=getRandom(150,300);
            newLi.style.height=newHeight+"px";
            newLi.style.lineHeight=newHeight+"px";
            //判断数组最小值及其对应下标            
            var minH=arr[0];
            var minNum=0;
            for(var j=1;j<arr.length;j++){
                if(minH>arr[j]){
                    minH=arr[j];
                    minNum=j;
                }
            }
            newLi.style.left=minNum*210+"px";
            newLi.style.top=arr[minNum]+"px";
            flowul.appendChild(newLi);
            arr[minNum]+=newHeight+10;
        }
        ulHeight();
        //当浏览器宽度发生改变时,对li重新定位
        window.onresize=function(){
            getWidth();
            if(old==col){
                return;//当列数没有发生改变时,跳出
            }else{
                old=col;
            }
            //通过循环改变li的位置
            for(var i=0;i<20;i++){
                var lis=document.querySelectorAll(".flowul li");
                lis[i].style.transitionDuration="3s";
                var newHeight=parseInt(lis[i].style.height);
                var minH=arr[0];
                var minNum=0;
                for(var j=1;j<arr.length;j++){
                    if(minH>arr[j]){
                        minH=arr[j];
                        minNum=j;
                    }
                }
                lis[i].style.left=210*minNum+"px";
                lis[i].style.top=arr[minNum]+"px";
                arr[minNum]+=newHeight+10;
            }
            ulHeight();            
        }
        function ulHeight(){
            var maxH=arr[0];
            var maxNum=0;
            for(var j=1;j<arr.length;j++){
                if(minH<arr[j]){
                    maxH=arr[j];
                    maxNum=j;
                }
            }
            flowul.style.height=arr[maxNum]+"px";
        }
        function getRandom(min,max){
            return Math.round(Math.random()*(max-min)+min);
        }
    </script>
    
    

    JavaScript图片轮播

        <style>
            ul{
                margin:0;
                padding:0;
                list-style-type:none;
            }
            .imgoc{
                width:75%;
                margin:0 auto;
                overflow:hidden;
                position:relative;
            }
            .imgocdiv{
                width:600%;
                position:relative;
                left:-100%;
                transition-duration:.5s;
            }
            .imgocdiv img{
                width:16.66666666%;
                float:left;
            }
            .imgoc ul{
                text-align:center;
                position:absolute;
                width:100%;
                bottom:0px;
            }
            .imgoc ul li{
                display:inline-block;
                width:10px;
                height:10px;
                border-radius:50%;
                background-color:red;
                margin:4px;
            }
            .imgoc .imgactive{
                background-color:blue;
            }
            .imgocbtn{
                width:40px;
                height:45px;
                font-size:30px;
                position:absolute;
                top:50%;
                transform:translateY(-20px);
            }
            .imgocbtn1{
                left:0;
            }
            .imgocbtn2{
                right:0;
            }
        </style>
        <div class="imgoc">
            <div class="imgocdiv">
                <img src="http://www.jiujiuba.com/xxpict2/picnews/7132249442.jpg" />
                <img src="http://pic.putaojiayuan.com/uploadfile/tuku/KaTongChaHua/12190515346673.jpg" />
                <img src="http://img.ivsky.com/download/Photo/UploadFiles/2009-7/2009714102041365.jpg" />
                <img src="http://www.dianmeng.com/moban/tupian/200808/2008080611515139.jpg" />
                <img src="http://www.jiujiuba.com/xxpict2/picnews/7132249442.jpg" />
                <img src="http://pic.putaojiayuan.com/uploadfile/tuku/KaTongChaHua/12190515346673.jpg" />
            </div>
            <ul>
                <li class="imgactive"></li>
                <li></li>
                <li></li>
                <li></li>
            </ul>
            <button class="imgocbtn imgocbtn1"><</button>
            <button class="imgocbtn imgocbtn2">></button>
        </div>
        <script>
            var div=document.querySelector(".imgocdiv");
            var lis=document.querySelectorAll(".imgoc ul li");
            var last=document.querySelector(".imgocbtn1");
            var next=document.querySelector(".imgocbtn2");
            var thisIndex=0;
            for(var i=0;i<lis.length;i++){
                lis[i].index=i;
                lis[i].onclick=function(){
                    thisIndex=this.index;
                    move();
                }
            }
            //给轮播设置自动切换
            var timer;
            function timing(){
                timer=setInterval(function(){
                    thisIndex++;
                    move();    
                },3000)
            }
            timing();
            //当鼠标在图片上停止切换,离开再运行
            div.onmouseover=function(){
                clearInterval(timer);
            }
            div.onmouseout=function(){
                timing();
            }
            last.onmouseover=function(){
                clearInterval(timer);
            }
            next.onmouseover=function(){
                clearInterval(timer);
            }
            last.onmouseout=function(){
                timing();
            }
            next.onmouseout=function(){
                timing();
            }
            //点击切换上一个
            lastMove();
            function lastMove(){
                last.onclick=function(){
                    last.onclick="";
                    thisIndex--;
                    move();
                    setTimeout(function(){
                        lastMove();
                    },500)
                }
            }
            //点击切换下一个
            nextMove();
            function nextMove(){
                next.onclick=function(){
                    next.onclick="";
                    thisIndex++;
                    move();
                    setTimeout(function(){
                        nextMove();
                    },500)
                }
            }
            function move(){
                for(var j=0;j<lis.length;j++){
                    lis[j].className="";
                }
                div.style.left=-(thisIndex+1)*100+"%";
                if(thisIndex==lis.length){
                    thisIndex=0;
                    lis[thisIndex].className="imgactive";
                    setStyle();
                }else if(thisIndex==-1){
                    thisIndex=lis.length-1;
                    lis[thisIndex].className="imgactive";
                    setStyle();
                }else{
                    lis[thisIndex].className="imgactive";
                }
            }
            function setStyle(){
                setTimeout(function(){
                    div.style.transitionDuration="0s";
                    div.style.left=-(thisIndex+1)*100+"%";
                    setTimeout(function(){
                        div.style.transitionDuration="0.5s";
                    },30)
                },500)
            }
        </script>
    
        
        

    JavaScript制作简易日历

    制作日历原理就是通过对Date对象和BOM对象的混合使用来完成。

    innerHTML和innerText的区别:

    innerHTML会把整个语句当成代码来执行

    innerText会把整个语句当成一个文本节点来处理

        <style>
            .divcalinder ul{
                margin:0;
                padding:0;
                list-style-type:none;
            }
            .divcalinder{
                width:434px;
                margin:0 auto;
            }
            .calinderset{
                text-align:center;
            }
            .calinderset button{
                width:100px;
                height:40px;
                margin:2px;
                font-size:20px;
                overflow:hidden;
            }
            .divmessage{
                height:30px;
                line-height:30px;
                font-size:20px;
                text-align:center;
                color:gold;
            }
            .ulweek{
                text-align:center;
                height:30px;
                border-bottom:1px solid white;
                overflow:hidden;
            }
            .ulweek li{
                float:left;
                color:black;
                width:62px;
                padding:5px 0;
                font-size:16px;
                color:white;
            }
            .ulday{
                overflow:hidden;
            }
            .ulday li{
                float:left;
                width:58px;
                height:58px;
                border:1px solid aqua;
                margin:1px;
                text-align:center;
                line-height:58px;
                font-size:18px;
                color:black;
            }
        </style>
        <div class="divcalinder">
            <div class="calinderset">
                <button>上一年</button>
                <button>上一月</button>
                <button>下一月</button>
                <button>下一年</button>
            </div>
            <div class="divmessage"></div>
            <ul class="ulweek">
                <li>星期日</li>
                <li>星期一</li>
                <li>星期二</li>
                <li>星期三</li>
                <li>星期四</li>
                <li>星期五</li>
                <li>星期六</li>
            </ul>
            <ul class="ulday"></ul>
        </div>
        <script>
            var btns=document.querySelectorAll(".calinderset button");
            var message=document.querySelector(".divmessage");
            var ul=document.querySelector(".ulday");
            var time=new Object();
            var date1=new Date();
            time.y=date1.getFullYear();
            time.m=date1.getMonth();
            var newD=date1.getDate();
            var newM=date1.getMonth();
            var newY=date1.getFullYear();
            function calinder(){
                ul.innerHTML="";
                message.innerHTML="";
                message.innerHTML=time.y+"年"+(time.m+1)+"月";
                var first=new Date(time.y,time.m,1);
                time.first=first.getDay();
                var last=new Date(time.y,time.m+1,0);
                time.last=last.getDate();    
                for(var i=0;i<time.first;i++){
                    var newLi=document.createElement("li");
                    newLi.style.backgroundColor="aqua";
                    ul.appendChild(newLi);
                }
                for(var i=1;i<=time.last;i++){
                    var newLi=document.createElement("li");
                    newLi.innerText=i;
                    newLi.style.backgroundColor="lime";
                    ul.appendChild(newLi);
                    if(newD==i&&newM==time.m&&newY==time.y){
                        newLi.style.backgroundColor="red";
                    }
                }
            }
            calinder();
            btns[1].onclick=function(){
                time.m--;
                if(time.m<0){
                    time.m=11;
                    time.y--;
                }
                calinder();
            }
            btns[2].onclick=function(){
                time.m++;
                if(time.m>11){
                    time.m=0;
                    time.y++;
                }
                calinder();
            }
            btns[0].onclick=function(){
                time.y--;
                calinder();
            }
            btns[3].onclick=function(){
                time.y++;
                calinder();
            }
        </script>
    
        
        
    • 星期日
    • 星期一
    • 星期二
    • 星期三
    • 星期四
    • 星期五
    • 星期六

      JavaScriptDOM文档对象类型

      DOM文档对象类型

      childNodes子节点,获取所有的文本和子元素

      children子元素

      parentNode父节点

      nextElementSibling同级的下一个子元素

      previousElementSibling同级的上一个子元素

      nextSibling同级的下一个节点

      previousSibling同级的上一个节点

          console.log(uls.childNodes);
      
          console.log(uls.children);
      
          console.log(uls.parentNode);
      
          console.log(lis[1].nextElementSibling);
      
          console.log(lis[1].previousElementSibling);
      
          console.log(lis[1].nextSibling);
      
          console.log(lis[1].previousSinling);
      

      createElement创建元素

      appendChild插入元素

      如果插入的元素原文档里没有,那就是直接插入;如果有,那就是把要插入的元素从原位置移动到被插入元素的最后面。

      removeChild删除子元素

      insertBefore(ele1,ele2)在ele2前插入

      ele1要插入的元素,如果原先在文档里有此元素,那么就是调换位置,如果没有,那就是插入

      ele2插入在谁前面

      hasChildNodes检查元素是否有子节点

      replaceChild(ele1,ele2)替换元素

      ele1替换的元素,如果原先在文档里有此元素,那么对ele1来说就是换个位置

      ele2被替换的元素,替换后被删除

          var newDiv=document.createElement("div");
      
          uls.appendChild(newDiv);
      
          uls.removeChild(lis[2]);
      
          uls.insertBefore(newDiv,lis[0]);
      
          console.log(uls.hasChildNodes());//返回布尔值
      
          uls.replaceChild(newDiv,lis[1]);
      

      getAttribute获取元素的属性值

      setAttribute更改原有属性的属性值/创建新的属性

      setAttribute假如元素有该属性,则为更改原有属性的属性值

      setAttribute假如元素无该属性,则为创建新的属性

      removeAttribute删除属性

      hasAttribute检查是否有此属性

      cloneNode()复制元素

      cloneNode(true)复制整个元素,包括子节点

      cloneNode(false)复制元素本身,不包括子节点

      cloneNode接收的参数默认为false,只能复制元素或节点,不能复制事件,也就证明了复制的元素和原元素不全等

          <div class="imdiv" index="5"></div>
      
          var imdiv=document.querySelector(".imdiv");
      
          console.log(imdiv.getAttribute("index"));
      
          imdiv.setAttribute("index",90);//改变原有属性值
      
          imdiv.setAttribute("width",100);//创建新的属性
      
          imdiv.removeAttribute("index");
      
          console.log(imdiv.hasAttribute("index"));//返回布尔值
      
          var newDiv=imdiv.cloneNode(true);
      
          document.body.appendChild(newDiv);
      

      DOM简易应用:

          <button class="dombtn">增加一个li</button>
          <ul class="domul"></ul>
          <script>
              var btn=document.querySelector(".dombtn");
              var ul=document.querySelector(".domul");
              var sum=1;
              btn.onclick=function(){
                  var newLi=document.createElement("li");
                  newLi.innerHTML="我是第"+sum+"个li";
                  sum++;
                  var newSpan=document.createElement("span");
                  newSpan.innerHTML="删除";
                  newSpan.style.color="blue";
                  newLi.appendChild(newSpan);
                  ul.appendChild(newLi);
                  newSpan.onclick=function(){
                      this.parentNode.parentNode.removeChild(this.parentNode);
                  }
              }
          </script>
      
          
          

        JavaScript闭包、Object对象

        JavaScript闭包

        定义:闭包指一个拥有许多变量和绑定这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。

            function a(){
                var i=0;
                function b(){
                    i++;
                    alert(i);
                }
                return b;
            }
            var c=a();
            c();//弹出 1
            c();//弹出 2
        

        函数特点:

        1. 函数b嵌套在函数a内部;
        2. 函数a返回函数b。

        当执行var c=a()后,变量c实际上就指向了函数b,再执行c()后就会弹出窗口显示的值。

        当函数a的内部函数b被函数a外的一个变量引用的时候,就创建了一个闭包。

        闭包就是能够读取其他函数内部变量的函数,本质上闭包就是将函数内部和函数外部连接起来的一座桥梁,而非内部能访问外部、外部不能访问内部。

        作用:就是在a执行完后,闭包使得函数a不会释放,因为a的内部函数b的执行需要依赖a的变量。也就使得上述例子中,a中的i一直存在,每次执行c(),i都是自加1后的值。

            //模拟私有变量
            function Counter(start){
                //父函数Counter当做对象使用
                var count=start;
                return{
                    sum: function(){
                        count++;
                    },
                    get: function(){
                        return count;
                    }
                }
            }
        
            var fn1=Counter(4);
            fn1.sum();
            console.log(fn1.get());//打印值为 5
        

        在这里,Counter函数返回两个闭包,函数sum和函数get。这两个函数都维持着对外部作用域Counter的引用,因此可以访问作用域内定义的变量count。

        基础应用场景:

        1. 保护函数内的变量安全(以第一个函数为例,函数a中i只有函数b能访问,无法通过其他途径访问到,因此保护了i的安全性);
        2. 在内存中维持一个变量(依然如第一个为例,由于闭包,函数a中i一直存在于内存中,因此每次执行c()都会给i加1)。

        判断下面的代码执行完成的结果可以帮助更好理解闭包:

            var name="The Window";
            var object={
                name: "My Object",
                getNameFunc: function(){
                    return function(){
                        return this.name;
                    };
                }
            };
            alert(object.getNameFunc()());//弹出 The Window
        
            var name="The Window";
            var object={
                name: "My Object",
                getNameFunc: function(){
                    var that=this;
                    return function(){
                        return that.name;
                    };
                }
            };
            alert(object.getNameFunc()());//弹出 My Object
        

        在for循环中使用闭包

        表示方法()()

        第二个括号里传变量,第一个括号通过一个匿名函数接收第二个括号传递的变量,然后就隐形的定义了一个私有的(局部)变量。

            for(var i=0;i<10;i++){
                (function(w){
                    setTimeout(function(){
                        console.log(w);
                    },1000)
                })(i);
            }
        
            //这个函数的效果和上面一样
            for(var i=0;i<10;i++){
                setTimeout((function(e){
                    return function(){
                        return console.log(e);
                    }
                })(i),1000)
            }
        

        在上述例子中,外部的匿名函数会立即执行,并把i作为它的参数,此时函数内w变量就拥有了i的一个拷贝。当传递给setTimeout的匿名函数执行时,它就拥有了对w的引用,而这个值是不会被循环改变的。

        闭包传递的变量接收后不会被释放,一直占用内存(不建议使用)

            <div class="divclosure">
                <button>按钮1</button>
                <button>按钮2</button>
                <button>按钮3</button>
                <button>按钮4</button>
                <button>按钮5</button>
            </div>
            <script>
                var btns=document.querySelectorAll(".divclosure button");
                for(var i=0;i<btns.length;i++){
                    btns[i].style.width=80+"px";
                    btns[i].style.height=45+"px";
                    btns[i].style.borderRadius=10+"px";
                    btns[i].style.marginRight=10+"px";
                    (function(w){
                        btns[w].onclick=function(){
                            alert(w);
                        }
                    })(i);
                }
            </script>
        
            

        Object对象

        1.第一种方法

            <script>
                //object
                var person=new Object();
                //属性
                person.finger=10;
                person.name="人";
                person.age=23;
                //方法
                person.sayHello=function(){
                    document.write("你好,我叫"+this.name+";");
                }
                person.sayAge=function(){
                    document.write("我今年"+this.age+"岁;");
                }
                person.studyAge=function(study,dream){
                    document.write("我"+study+"开始上学的,我希望成为"+dream+";")
                }
                var xiaoming=new Object();
                xiaoming.name="小明";
                xiaoming.age="23";
                person.sayHello();
                person.sayAge();
                person.sayHello.call(xiaoming);
                person.sayAge.call(xiaoming);
                person.studyAge.call(xiaoming,6,"科学家");
                person.studyAge.apply(xiaoming,[6,"科学家"])
            </script>
        
            
        

        call方法:

        改变方法里面的this的指向,方法使用的是原对象的,通过this获得的数据都是call的对象的;也就是调用一个对象的一个方法,以另一个对象替换当前对象。

        function call(obj,[param1[,param2[,…[,paramN]]]])

        obj:这个对象将代替function类里this对象

        params:这个是一个参数列表

        apply方法:

        与call方法意思一样,参数列表不同;也就是调用一个对象的一个方法,以另一个对象替换当前对象。

        function.apply(obj,args)方法能接收两个参数

        obj:这个对象将代替Function类里this对象

        args:这个是数组,它将作为参数传给function(args–>arguments)

        JavaScript碰撞检测

        JavaScript碰撞检测主要用于游戏开发等。几乎所有的游戏都离不开碰撞检测——无论是各物体之间的碰撞检测,还是物体与场景之间的碰撞检测。

        代码如下:

            <style>
                div.divtest{
                    width:500px;
                    height:300px;
                    border:1px solid black;
                    position:relative;
                }
                div.divtest div:first-child{
                    width:50px;
                    height:50px;
                    background-color:red;
                    position:absolute;
                    top:0;
                    left:0;
                }
                div.divtest div:last-child{
                    width:50px;
                    height:50px;
                    background-color:blue;
                    position:absolute;
                    top:250px;
                    left:450px;
                }
            </style>
            <div class="divtest">
                <div></div>
                <div></div>
            </div>
            <script>
                var div=document.querySelector(".divtest");
                var box1=document.querySelector(".divtest div:first-child");
                var box2=document.querySelector(".divtest div:last-child");
                var dir1_l=true,dir1_t=true,dir2_l=false,dir2_t=false;//定义盒子的运动方向
                var speed1_l=5,speed1_t=3,speed2_l=3,speed2_t=6; //定义盒子各个方向的运动速度
                var divw,divh,boxw,boxh,box1_l,box1_t,box2_l,box2_t;//定义盒子的各个属性值
                //检测浏览器获取样式(主要为了兼容IE)
                if(div.currentStyle){
                    divw=parseInt(wrap.currentStyle.width);
                    divh=parseInt(wrap.currentStyle.height);
                    boxw=parseInt(box1.currentStyle.width);
                    boxh=parseInt(box1.currentStyle.height);
                    box1_l=parseInt(box1.currentStyle.left);
                    box1_t=parseInt(box1.currentStyle.top);
                    box2_l=parseInt(box2.currentStyle.left);
                    box2_t=parseInt(box1.currentStyle.top);
                }else{
                    divw=parseInt(getComputedStyle(div,[]).width);
                    divh=parseInt(getComputedStyle(div,[]).height);
                    boxw=parseInt(getComputedStyle(box1,[]).width);
                    boxh=parseInt(getComputedStyle(box1,[]).height);
                    box1_l=parseInt(getComputedStyle(box1,[]).left);
                    box1_t=parseInt(getComputedStyle(box1,[]).top);
                    box2_l=parseInt(getComputedStyle(box2,[]).left);
                    box2_t=parseInt(getComputedStyle(box2,[]).top);
                }
        
                setInterval(function(){
                    //动态获取盒子的属性值
                    if(box1.style.left){
                        box1_l=parseInt(box1.style.left);
                        box1_t=parseInt(box1.style.top);
                        box2_l=parseInt(box2.style.left);
                        box2_t=parseInt(box2.style.top);
                    }
                    //判断box分别碰到边框的情况,改变其方向
                    if(box1_l<=0){
                        dir1_l=true;
                    }else if(box1_l>=divw-boxw){
                        dir1_l=false;
                    }
                    if(box2_l<=0){
                        dir2_l=true;
                    }else if(box2_l>=divw-boxw){
                        dir2_l=false;
                    }
                    if(box1_t<=0){
                        dir1_t=true;
                    }else if(box1_t>=divh-boxh){
                        dir1_t=false;
                    }
                    if(box2_t<=0){
                        dir2_t=true;
                    }else if(box2_t>=divh-boxh){
                        dir2_t=false;
                    }
                    //开始设置盒子碰撞的情况
                    //首先当盒子在水平方向上碰撞时,其top差的绝对值小于left差的绝对值
                    if(Math.abs(box1_l-box2_l)>Math.abs(box1_t-box2_t)){
                        //水平方向发生碰撞,left的差值不超过box的宽度
                        //接下来就可以判断box1和box2分别在左右侧碰撞就可以了
                        if(box1_l<box2_l&&box1_l+boxw>=box2_l){
                            dir1_l=false;
                            dir2_l=true;
                            console.log("红左蓝右");
                        }else if(box1_l>box2_l&&box1_l<=box2_l+boxw){
                            dir1_l=true;
                            dir2_l=false;
                            console.log("红右蓝左");
                        }
                    }else if(Math.abs(box1_l-box2_l)<Math.abs(box1_t-box2_t)){
                        //其次当盒子在竖直方向上碰撞时,其top差的绝对值大于left差的绝对值
                        //竖直方向发生碰撞,top的差值不超过box的高度
                        //接下来就可以判断box1和box2分别在上下侧碰撞就可以了
                        if(box1_t<box2_t&&box1_t+boxh>=box2_t){
                            dir1_t=false;
                            dir2_t=true;
                            console.log("红上蓝下");
                        }else if(box1_t>box2_t&&box1_t<=box2_t+boxh){
                            dir1_t=true;
                            dir2_t=false;
                            console.log("红下蓝上");
                        }
                    }
                    //开始规定盒子的运动数值
                    if(dir1_l){
                        box1_l+=speed1_l;
                    }else{
                        box1_l-=speed1_l;
                    }
                    if(dir2_l){
                        box2_l+=speed2_l;
                    }else{
                        box2_l-=speed2_l;
                    }
                    if(dir1_t){
                        box1_t+=speed1_t;
                    }else{
                        box1_t-=speed1_t;
                    }
                    if(dir2_t){
                        box2_t+=speed2_t;
                    }else{
                        box2_t-=speed2_t;
                    }
                    //写入盒子的行间样式属性,使其开始运动
                    box1.style.left=box1_l+"px";
                    box2.style.left=box2_l+"px";
                    box1.style.top=box1_t+"px";
                    box2.style.top=box2_t+"px";
                    },30)
            </script>
        
            
            

        JavaScript导航滚动

        每个导航对应一个区域内容,当选择特定区域时菜单会自动切换,一般会有高亮样式。主要应用在各大电商的首页导航里。

        代码如下:

            <style>
                div.jsnav{
                    width:700px;
                    margin:0 auto;
                }
                div.jsnav>div>span{
                    text-align:center;
                    display:inline-block;
                    width:40px;
                    border:1px solid gold;
                    margin:5px 30px;
                }
                div.jsnav>div:last-child{
                    position:relative;
                    left:0px;
                    width:100px;
                    height:3px;
                    background-color:palegreen;
                    transition-duration:1s;
                    transition-timing-function:cubic-bezier(0,1.92,1,-1.67);
                }
            </style>
            <div class="jsnav">
                <div>
                    <span>导航1</span>
                    <span>导航2</span>
                    <span>导航3</span>
                    <span>导航4</span>
                    <span>导航5</span>
                </div>
                <div></div>
            </div>
            <div class="jsnav">
                <div>
                    <span>导航1</span>
                    <span>导航2</span>
                    <span>导航3</span>
                    <span>导航4</span>
                    <span>导航5</span>
                </div>
                <div></div>
            </div>
            <div class="jsnav">
                <div>
                    <span>导航1</span>
                    <span>导航2</span>
                    <span>导航3</span>
                    <span>导航4</span>
                    <span>导航5</span>
                </div>
                <div></div>
            </div>
            <script>
                var nav=document.querySelectorAll(".jsnav div:first-child");
                var slide=document.querySelectorAll(".jsnav div:last-child");
                for(var i=0;i<nav.length;i++){
                    var span=nav[i].querySelectorAll(".jsnav span");
                    for(var j=0;j<span.length;j++){
                        span[j].i=i
                        span[j].j=j;
                        span[j].onmouseover=function(){
                        slide[this.i].style.left=this.j*100+"px";
                        }
                    }
                }
        
            </script>
        
            
            
        导航1导航2导航3导航4导航5
        导航1导航2导航3导航4导航5
        导航1导航2导航3导航4导航5