【JS】js学习小笔记 5#

你捡起了道具:遗失的纸片5#
一张普通的纸片,隐隐约约能够看到目录:“事件对象、BOM、定时器、JSON”。边角还有被撕扯的痕迹,它们应该属于一个笔记本,但不知为什么被主人撕下来丢掉了。
提示:集齐所有纸片应该可以得到一本技能书。
👇点击下方按钮调查

29.事件对象

  • 当事件的响应函数被触发时,浏览器每次都将一个事件对象作为实参传递进响应函数
  • 在事件对象中封装了当前事件相关的一切信息,如鼠标的坐标、按下的键、滚轮滚动的方向等

①mouseEvent

该事件将会在鼠标再元素中移动时被触发
常用属性:

  • 相对于浏览器窗口:
    1. clientX→指针水平坐标
    2. clientY→指针垂直坐标
  • 相对于页面(IE8+)
    1. pageX→指针水平坐标
    2. pageY→指针垂直坐标

在IE8及以下版本的浏览器中,响应函数被触发时浏览器不会传递事件对象,取而代之,其会将时间作为window对象的属性保存。

window.event

该属性在火狐浏览器中不存在

②全兼容方式:

在响应函数中添加:

event=event||window.event;

④事件的冒泡

  • 所谓的冒泡指的就是事件的向上传导,当后代元素的事件被触发时,其祖先元素相同事件也会被触发
  • 在开发中大部分情况冒泡是有用的,如果不希望发生事件冒泡可以通过事件对象来取消冒泡:将event.cancelBubble设置为true即可取消冒泡

⑤事件的委派

我们希望,只绑定依次事件,即可应用到若干元素上,即使元素是后添加的。

可以尝试将其绑定给元素共同的祖先元素→原事件冒泡到祖先事件

事件的委派:
– 指将事件统一绑定给元素的共同祖先元素,这样当后代元素上的事件触发时,会一直冒泡到祖先元素从而通过祖先元素的响应函数来处理事件
– 事件的委派利用了冒泡,通过委派可以减少事件绑定的次数,提高程序的性能
防止祖先元素被触发:如果触发事件的对象是我们期望的元素则执行,否则不执行
使用event.target属性可以得到触发事件的元素

⑥事件的绑定

㈠addEventListener() (IE8+)

通过该方法可为元素绑定响应函数
参数:
1. 时间的字符串,不要“on”
1. 回调函数,当事件触发时该函数会被调用
1. 是否在捕获阶段触发事件,需要一个布尔值,一般都传“false”

使用addEventListener()可谓一个元素的相同事件同时绑定多个响应函数,这样当事件触发时,响应函数将会按照函数的绑定顺序执行this绑定的事件

㈡attachEvent() (IE1~10)

参数:
1. 事件字符串(要on)
1. 回调函数

该方法可同时为一个事件绑定多个处理函数
不同的是它是后绑定先执行,执行顺序与addEventListener()相反

㈢全兼容方式:

  1. obj→要绑定的对象
  2. eventStr→事件的字符串 (不要on)
  3. callback→回调函数
function bind(obj,eventStr,callback)
{
    if(obj.addEventListener){
        //大部分浏览器的兼容方式
        obj.addEventListener(eventStr,callback,false);
    }
    else{
        //this是谁由调用方式决定(callback.call(obj))
        //IE8及以下浏览器
        objattachEvent("on"+eventStr,function(){
           //在匿名函数中调用回调函数 
            callback.call(obj);
        });
    }
}

⑦事件的传播

  • 关于事件的传播网景公司与微软公司有不同的理解
    • 微软认为事件应该是由内向外传播,也就是事件触发时,应该先出发当前元素上的事件,然后再向当前元素的祖先元素外传播,也就是该事件应该在冒泡阶段进行
    • 网景认为事件应该是由外向内传播的,也就是当前事件应该先出发当前元素的最外层祖先元素的事件,然后再向内传播给后代元素
  • W3C结合了两个公司的方案,将事件传播分成了三个阶段:
    1. 捕获阶段
      在捕获阶段时从最外层的祖先元素向目标元素进行事件的捕获,但默认此时不会触发事件
    2. 目标阶段
      事件捕获到目标元素,捕获结束开始在目标元素上触发事件
    3. 冒泡阶段
      事件从目标元素向其祖先元素传递,依次触发祖先元素上的事件

⑧滚轮事件

㈠onmousewheel

  • 鼠标滚轮滚动的事件,会在滚轮滚动时触发
  • 火狐不支持该属性,其通过addEventListener()函数绑定DOMMouseScroll事件来绑定相应函数
    例:
addEventListener(obj,"DOMMouseScroll",function(){
    //相应函数体
});
  • 兼容性解决方案:
obj.onmousewheel=function(){
    //相应函数体
};
addEventListener(obj,"DOMMouseScroll",function(){
    //相应函数体
});

㈡判断方向

  1. event.wheelDelta属性可以获取鼠标滚轮的滚动方向
    • 火狐不能用
    • 向上→120;向下→120
    • 不看大小只看正负
  2. event.detail
    • 只有火狐能用
    • 向上→-3;向下→3
    • 不看大小只看正负
  3. 兼容性解决方案:
if(event.wheelDelta>0||event.detail<0)
{
    //向上滚
}
else
{
    //向下滚
}

㈢当滚轮滚动时,若浏览器有滚动条,滚动条会随之滚动

这是浏览器的默认行为,若不希望其发生,可以取消默认行为

return false;

火狐:
使用addEventListener()方法绑定的响应函数不能通过return false来取消默认行为,需要使用event来取消默认行为:

event.preventDefault();

兼容性解决方案:

event.preventDefault&&event.preventDefault();
return false;

⑨键盘事件

  • 键盘事件一般都会绑定给一些可以获取到焦点的对象或者document
  • 常用事件
    • onkeydown 按键被按下
      若一直按某键不松手,事件会一直触发。当onkeydown连续触发时,**第一次与第二次之间间隔会稍长一些,其余会短些,这种设计是为了防止误触
    • onkeyup 按键被松开

㈠获取按键

  1. 可通过keycode属性获取某键的Unicode编码,借此可判断哪个键被按下
  2. 判断组合键:除了keycode,event还提供altkey/ctrlkey/shiftkey属性,这三个用来判断alt、ctrl、shift是否被按下,按下则返回true,否则返回false

㈡在文本框使用键盘事件

在文本框中输入内容属于onkeydown的默认行为,如果在onkeydown中取消默认行为,则输入的内容不会出现在文本框中,可用此功能屏蔽某些字的输入

⑩实验:键控div

  • keycode:
    • 左:37
    • 上:38
    • 右:39
    • 下:40
    • 顺时针增加

代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <style>
        div{
            height: 100px;
            width:100px;
            background-color: red;
            position: absolute;
        }
    </style>
    <script>
        window.onload=function(){
            var div=document.getElementsByTagName("div")[0];
            document.onkeydown=function (event) {
                event=event||window.event;
                var speed=10;
                if(event.ctrlKey)speed=100;
                switch (event.keyCode) {
                    case 37:div.style.left=div.offsetLeft-speed+"px";break;
                    case 38:div.style.top=div.offsetTop-speed+"px";break;
                    case 39:div.style.left=div.offsetLeft+speed+"px";break;
                    case 40:div.style.top=div.offsetTop+speed+"px";break;
                }
            }
        }
    </script>
    <title>keydownTest</title>
</head>
<body>
<div></div>
</body>
</html>

实验:元素跟随鼠标

chrome认为浏览器的滚动条是body的,火狐等浏览器认为滚动条是html标签的
解决方案:

//垂直:
var st=document.body.scrollTop||document.documentElement.scrollTop;
//水平:
var sl=document.body.scrollLeft||document.documentElement.scrollLeft;

代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        #movdiv{
            position: absolute;
        }
        body{
            height: 12000px;
        }
    </style>
    <script>
        window.onload=function(){
            var movdiv=document.getElementById("movdiv");
            document.onmousemove=function(e){
                var st=document.body.scrollTop||document.documentElement.scrollTop;
                var sl=document.body.scrollLeft||document.documentElement.scrollLeft;
                movdiv.style.top=e.clientY+st+"px";
                movdiv.style.left=e.clientX+sl+"px";
            }
        }
    </script>
</head>
<body>
<button id="movdiv">甩掉我啊</button>
</body>
</html>

30.BOM

  • 浏览器对象模型
  • BOM可以使我们通过JS操作浏览器
  • 在BOM中为我们提供了一组对象,用来完成浏览器的操作
  • BOM对象:
    1. window
      代表的是整个浏览器窗口,同时window也是网页中的全屏对象
    2. navigator
      代表当前浏览器的信息,通过该对象可以来识别不同的浏览器
    3. location
      代表当前浏览器的地址栏信息,通过location可以获取地址栏信息或操作浏览器跳转页面
    4. history
      代表浏览器的历史纪录,可以通过该对象来操作浏览器的历史记录。由于隐私原因,该对象不能获取到具体的历史记录,只能操作浏览器向前或向后翻页,而且该操作只在档次访问时有效
    5. screen
      代表用户的屏幕信息,通过该对象可以获取到用户的显示器相关信息

这些BOM对象在浏览器中都是作为window对象的属性保存的,可以通过window对象来使用,也可以直接使用

①navigator

由于历史原因,navigator中的大部分属性已经不能帮助我们识别浏览器了。一般我们只会使用userAgent来判断浏览器信息

㈠userAgent

userAgent是一个字符串,这个字符串中含有用来描述浏览器信息的内容,不同浏览器有不同的userAgent。

var ua=navigator.userAgent;
if(/firefox/i.test(ua)){
    //火狐
}
else if(/chrome/i.test(ua)){
    //chrome
}
else if(/msie/i.test(ua)){
    //IE10以下的IE
}
else if("ActiveXObject" in window)
{
    //IE或Edge
}

㈡对于IE10+的识别,需要寻找特有对象

如:ActiveXObject→IE有,其他均没有
不能直接对window.ActiveXObject进行逻辑查找,使用以下方法查找:

if("ActiveXObject" in window){
    //IE
}else{
    //非IE
}

②history

  1. length
    该属性可以获取到当前访问的连接数量
  2. back()
    该方法用来退回上一个页面,与浏览器中的回退按钮作用相同
  3. forward()
    该方法用来跳转到下一个页面,与浏览器中的前进按钮作用相同
  4. go()
    该方法可以用来跳转到指定页面,它需要一个整数作为参数:

    • 正数n→向前跳转n个页面
    • 负数n→向后跳转n个页面

③location

如果直接打印location,可获取到地址栏信息(当前页面的完整路径)。如果直接将location修改为绝对/相对路径,则页面会自动跳转到该路径,并自动生成历史纪录
1. assign()
用来跳转到其他页面,作用与直接修改location一样
1. reload()
刷新当前页面
1. reload(true)
强制清空缓存刷新页面
1. replace()
用新页面替换当前页面,不会生成历史纪录,不能回退

31.定时器

①定时调用

如果希望一段程序可以每间隔一段时间执行一次可以使用定时调用

㈠(window).setInterval()

可将一个函数每隔一段时间执行一次
参数:
1. 回调函数,该函数会每隔一段时间被调用一次
1. 每次调用间隔的时间,单位是毫秒

返回值:
返回一个Number类型的数据,这个数字用来作为定时器的唯一标识,主要用来取消定时器

㈡clearInterval()

可以用来关闭一个定时器。
方法中需要一个定时器标识作为参数,这样将关闭标识对相应的定时器

var timer=setInterval(function(){
    //定时器执行代码
    if(定时器关闭条件)clearInterval(timer);
},定时时间);

②实验:切换图片

注意不要开启多个定时器→每开一个就关上一个

③实验:解决键控移动div时卡顿的问题

分离方向与速度的控制
代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <style>
        div{
            height: 100px;
            width:100px;
            background-color: red;
            position: absolute;
        }
    </style>
    <script>
        window.onload=function(){
            var speed=10;
            var direction=0;
            var div=document.getElementsByTagName("div")[0];
            var timer=setInterval(function(){
                switch (direction)
                {
                    case 37:div.style.left=div.offsetLeft-speed+"px";break;
                    case 38:div.style.top=div.offsetTop-speed+"px";break;
                    case 39:div.style.left=div.offsetLeft+speed+"px";break;
                    case 40:div.style.top=div.offsetTop+speed+"px";break;
                }
            },30);
            document.onkeydown=function (event) {
                event=event||window.event;
                if(event.ctrlKey)speed=100;
                else speed=10;
                direction=event.keyCode;
                };
            document.onkeyup=function(){
                direction=0;
            };
        };
    </script>
    <title>keydownTest</title>
</head>
<body>
<div></div>
</body>
</html>

④延时调用

setTimeOut():延时调用一个函数不马上执行,而是隔一段时间执行,且只执行一次,用法与setInteral()相似
clearTimeOut():关闭一个延时调用
延时调用和定时调用实际上是可以相互代替的,在开发过程中可根据自己的需要去选择。

⑤实验:定时器的应用——元素移动方法

tools.js:

function getStyle(obj,name){
    //非IE8以下浏览器获取目前CSS
    if(window.getComputedStyle)return getComputedStyle(obj,null)[name];
    //IE8以下浏览器获取目前CSS
    else return obj.currentStyle[name];
}

/*obj→控制对象
attr→控制属性
target→终点位置
→到达终点后的回调函数*/
function move(obj,attr,speed,target,callback){
    //防止多次点击设置多个定时器,所以每次点击移除上一个定时器
    clearInterval(obj.timer);

    obj.timer=setInterval(function(){
        var current=getStyle(obj,attr);
        //未设置属性初值时,ie将返回auto,其不可参与运算,当这种情况发生时,将其属性赋值为0
        current=="auto"?current=0:current=parseInt(current);
        //判断速度方向
        //bug:临时变量未消除??
        if(current>target&&speed>0)speed=-speed;
        var newValue=current+speed;
        //防止速度非终点位置的整数倍造成的停止位置偏移,强制将最后的位置赋值为终点位置
        if((speed>0&&newValue>target)||(speed<0&&newValue<target))newValue=target;
        //改变对象属性
        obj.style[attr]=newValue+"px";
        //判断对象是否到达终点
        if(newValue==target)
        {
            //到达终点后清除定时器,触发回调函数
            clearInterval(obj.timer);
            callback&&callback();
        }
    },30);
}

代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>moveFunc</title>
    <style>
        body{
            margin-top: 0px;
            margin-left: 0px;
        }
        #box1{
            width: 100px;
            height:100px;
            background-color: red;
            position: absolute;
        }
        #box2{
            width: 100px;
            height:100px;
            top:200px;
            background-color: yellow;
            position: absolute;
        }
        #line{
            width: 0px;
            height: 1000px;
            border-right:1px black solid;
            left: 1000px;
            top:0px;
            position: absolute;
        }
        #control{
            margin:10px;
        }
    </style>
    <script src="tools.js"></script>
    <script>

        window.onload=function(){
            var box1=document.getElementById("box1");
            var box2=document.getElementById("box2");
            var btn1=document.getElementById("btn1");
            var btn2=document.getElementById("btn2");
            btn1.onclick=function (){
                move(box1,"left",10,1000);
            }
            btn2.onclick=function () {
                move(box2,"width",10,500,function () {
                    move(box2,"height",10,500,function () {
                        move(box2,"width",10,100,function(){
                            move(box2,"height",10,100);
                        })
                    })
                })
            };
            /*btn2.onclick=function () {
                move(box2,"width",10,10);
            };*/
        }
    </script>
</head>
<body>
<div id="control">
    <button id="btn1">box1移动</button>
    <button id="btn2">box2移动</button>
</div>
<div id="box1"></div>
<div id="box2"></div>
<div id="line"></div>
</body>
</html>

⑥实验——轮播页面

代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Cycle Image Frame</title>
    <style>
        *{
            margin:0;
            padding:0;
        }
        #outer{
            height: 470px;
            /*宽度值为图片宽度+外边距margin10*2=610px*/
            width: 610px;
            margin:50px auto;
            background-color: aquamarine;
            padding:10px 0;
            position: relative;
            overflow: hidden;
        }
        #imgList{
            list-style: none;
            position: absolute;
        }

        #imgList li{
            float:left;
            margin: 0 10px;
        }

        #nav{
            position: absolute;
            bottom:20px;
        }

        #nav a{
            float:left;
            width: 10px;
            height: 10px;
            background-color: black;
            margin: 0 5px;
            opacity: 0.5;
            /*IE8透明*/
            filter:alpha(opacity=50);
            border-radius: 5px;
        }

        #nav a:hover{
            background-color: aliceblue;
        }

        .borderbtn{
            position: absolute;
            width: 20px;
            height: 100px;
            opacity: 0.5;
            filter:alpha(opacity=50);
            background-color: black;
            color: aliceblue;
            vertical-align: center;
            text-align: center;
            line-height: 100px;
            top:215px;
        }

        .borderbtn:hover{
            background-color: aliceblue;
            color: black;
        }

        #rbtn{
            right: 0px;
        }

    </style>
    <script src="tools.js"></script>
    <script>
        window.onload=function(){

            var timer;
            //根据图片数量自动设置图片列的宽度
            var imgList=document.getElementById("imgList");
            var imgArr=document.getElementsByTagName("img");
            imgList.style.width=610*imgArr.length+"px";

            //自动居中跳转按钮
            var nav=document.getElementById("nav");
            var outer=document.getElementById("outer");
            nav.style.left=(outer.offsetWidth-nav.offsetWidth)/2+"px";

            //为目前显示的图片按钮更改颜色
            var allA=document.getElementsByTagName("a");
            var index=0;
            allA[index].style.backgroundColor="aliceblue";

            var lbtn=document.getElementById("lbtn");
            var rbtn=document.getElementById("rbtn");
            lbtn.onclick=function () {
                index==0?index=allA.length-1:index--;
                changeImg();
            }
            rbtn.onclick=function () {
                index==allA.length-1?index=0:index++;
                changeImg();
            }

            for(var i=0;i<allA.length;i++)
            {
                allA[i].index=i;
                allA[i].onclick=function () {
                    index=this.index;
                    changeImg();
                };
            }

            function changeImg() {
                //清除自动定时器
                clearInterval(timer);
                //imgList.style.left=-610*index+"px"
                var oldindex=parseInt(imgList.style.left)/-610;
                var speed=50;
                if(Math.abs(oldindex-index)>1)speed=80;
                move(imgList,"left",speed,-610*index,function(){
                    //动画执行完毕,开启自动切换
                    autoChange();
                });
                setAColor();
            }

            autoChange();

            function setAColor(){
                //判断当前图片是否为最后一张图片
                if(index>=imgArr.length-1){
                    index=0;
                    //通过css将图片设置到第一张
                    imgList.style.left=0;
                }
                //去除内联样式,式样式表中的鼠标悬浮变色样式实现
                for(var i=0;i<allA.length;i++)allA[i].style.backgroundColor="";
                allA[index].style.backgroundColor="aliceblue";
            }

            function autoChange()
            {
                timer=setInterval(function(){
                    index++;
                    index%=imgArr.length;
                    move(imgList,"left",40,-610*index,function () {
                        setAColor();
                    });
                },3000);
            }
        }

    </script>
</head>
<body>
<div id="outer">
    <ul id="imgList">
        <li><img src="https://www.z4a.net/images/2019/05/13/157ca6b4974b78c89.jpg"> </li>
        <li><img src="https://www.z4a.net/images/2019/05/13/2840b21773dc852f3.jpg"> </li>
        <li><img src="https://www.z4a.net/images/2019/05/13/3197936dabdc3025c.jpg"> </li>
        <li><img src="https://www.z4a.net/images/2019/05/13/4bef50cec6ab80f08.jpg"> </li>
        <li><img src="https://www.z4a.net/images/2019/05/13/5bbaed807aafe43a4.jpg"> </li>
        <li><img src="https://www.z4a.net/images/2019/05/13/6016ef4e19fed0ded.jpg"> </li>
        <li><img src="https://www.z4a.net/images/2019/05/13/761ccf35b9ff73af5.jpg"> </li>
        <li><img src="https://www.z4a.net/images/2019/05/13/157ca6b4974b78c89.jpg"> </li>
    </ul>
    <div id="nav">
        <a href="javascript:;"></a>
        <a href="javascript:;"></a>
        <a href="javascript:;"></a>
        <a href="javascript:;"></a>
        <a href="javascript:;"></a>
        <a href="javascript:;"></a>
        <a href="javascript:;"></a>
    </div>
    <div id="lbtn" class="borderbtn"><</div>
    <div id="rbtn" class="borderbtn">></div>
</div>
</body>
</html>

32.类的操作

通过Style属性来修改元素的样式,每修改一个样式,浏览器就需要重新渲染一次页面,这样执行的性能较差,且这种形式要修改多个样式时也不太方便

可以通过修改元素的class属性来间接的修改多个央视,这样浏览器只需渲染页面一次,性能更好,并且这种方式可以使表现和行为进一步分离

①自建方法

统一参数:
1. obj→操作对象
1. cn→类名

㈠ 判断类方法

function hasClass(obj,cn){
    var reg=new RegExp("\\b"+cn+"\\b");
    return reg.test(obj.className);
}

㈡合并类方法

function addClass(obj,cn){
    if(!hasClass(obj,cn))obj.className+=""+cn;
}

㈢删除类方法

function removeClass(obj,cn){
    var reg=new RegExp("\\b"+cn+"\\b");
    obj.className=obj.class.replace(reg,"");
}

㈣切换类方法

  • 若元素中具有该类,则删除
  • 若元素中没有该类,则添加
function toggleClass(obj,cn){
    if(hasClass(obj,cn))removeClass(obj,cn);
    else addClass(obj,cn);
} 

②实验——三级菜单

当div中有collapsed这个类时,div就是折叠状态,没有就是展开状态

33.JSON

  • js中的对象只有js自己认识,其他语言都不认识
  • JSON就是一个特殊格式个字符串,这个字符串可以被任意语言所识别,并且可以转换为任意语言中的对象,JSON在开发中主要用来数据交互
  • 全名JavaScript Object Notation == JS对象方法
  • JSON与js对象的格式一样,只不过JSON字符串中的属性名必须加双引号,其他的与js语法一致

①分类

  1. 对象:{}
  2. 数组:[]

②JSON中允许的数据类型

  1. 字符串
  2. 数值
  3. 布尔值
  4. null
  5. 对象
  6. 数组

(没有函数!!)

③将JSON字符串转换为JS对象

在js中为我们提供了一个工具类,就叫JSON,该对象可将JSON转换为js对象,也可将js对象转换为JSON字符串

㈠JSON.parse()

  • 它可将JSON字符串转换为js对象
  • 它需要一个JSON字符串作为参数,会将该字符串转换为js对象返回

㈡JSON.stringify()

  • 它可将一个js对象转换为JSON字符串
  • 它需要一个js对象作为参数,会返回一个JSON字符串

JSON对象在IE7及以下浏览器中不支持,会报错

eval()

  • 这个函数可以用来执行一段字符串形式的js代码,并将结果返回。
  • 如果使用eval()执行的字符串中含有{},它会将{}当成代码块,若不需要将其当成代码块解析,则需在字符串前后各加一个括号

    var obj=eval(“(“+JSONstr+”)”);

  • 这个函数的功能很强大,但在开发中尽量不要使用,首先它的执行性能比较差,还有安全隐患!
    综上,若需兼容IE7及一下浏览器的JSON操作,可在网页源代码中引入JSON对象的定义文件

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据