第九周第四天筆記

1 放大鏡實例

  • 頁面結構:
    • 創建左右兩個容器,左邊容器中添加一張圖片背景圖,右邊容器中添加一張與背景圖成比例放大的圖片,圖片相當于右邊容器進行定位;
    • 左右兩個容器設置浮動,使其并排顯示,在左邊容器中創建一個透明度的模糊層mark,相對于左邊容器進行定位,通過改變定位值來實現不斷移動,正常情況下右邊容器及mark均為隱藏;
  • 思路:
    • 給左邊容器left添加鼠標移入移出事件,當光標移入后,右邊容器及mark顯示,當光標移出后,右邊容器及mark隱藏;
    • 給左邊容器添加鼠標移動事件,然后通過事件對象屬性clientX,clientY計算出鼠標相對于左容器的位置,設置給mark定位值;進而實現mark的移動,計算出右面容器中圖片的定位數值,相對的讓其移動,進而達到放大鏡的效果;
  • 知識點:
    • 鼠標移入移出事件,onmouseover、onmouseout與onmouseenter、onmouseleave兩對事件都可以設置;
    • 鼠標移動事件,添加給左邊容器left,但是在實際移動中,光標一直在子級mark上移動,所以會觸發子級的移動事件,通過冒泡觸發left的移動事件,進而實現mark的定位數值設置,完成不斷移動效果;
    • 針對于mark元素
      • 定位值的計算及設置代碼:
       var l=e.clientX-this.offsetLeft-this.clientLeft-oMark.offsetWidth/2;
       var t=e.clientY-this.offsetTop-this.clientTop-oMark.offsetHeight/2;
      
      • 邊界值的計算及設置
    • 針對right中的圖片定位值計算:
      • 計算公式:等比例運動,mark運動的實時值/mark運動的最大值==img運動的實時值/img運動的最大值;
       //mark運動的實時值為:l和t
       //img運動的實時值設為:x和y
       //mark運動的最大值
       var maxL=oLeft.offsetWidth-oMark.offsetWidth;
       var maxT=oLeft.offsetHeight-oMark.offsetHeight;
       //img運動的最大值
       var maxImgL=oRight.offsetWidth-oImg.offsetWidth;
       var maxImgT=oRight.offsetHeight-oImg.offsetHeight;
       //計算公式:l/maxL==x/maxImgL  t/maxT==y/maxImgT
       x=-l/maxL*maxImgL=-l/(oLeft.offsetWidth-oMark.offsetWidth)*(oRight.offsetWidth-oImg.offsetWidth);
       y=-l/maxT*maxImgT=-t/(oLeft.offsetHeight-oMark.offsetHeight)*(oRight.offsetHeight-oImg.offsetHeight);
      
      • 注:計算出來的值為數字,設置時必須加單位;
  • 代碼:
     <!DOCTYPE html>
     <html lang="en">
     <head>
         <meta charset="UTF-8">
         <title>放大鏡實例</title>
         <style>
             *{
                 margin: 0;
                 padding: 0;
             }
             body{
                 margin: 50px;
                 height: 1000px;
             }
             .left{
                 background: url("img/1.jpg") no-repeat center;
                 background-size: 100%;
             }
             .left{
                 width: 215px;
                 height: 215px;
                 float: left;
                 position: relative;
                 margin: 20px;
             }
             .left .mark{
                 width: 50%;
                 height: 50%;
                 background-color: yellow;
                 opacity: 0.6;
                 filter: alpha(opacity:60);
                 position: absolute;
                 display: none;
             }
             .right{
                 width: 300px;
                 height: 300px;
                 float: left;
                 margin: 20px;
                 position: relative;
                 border: 1px solid red;
                 overflow: hidden;
                 display: none;
             }
             .right img{
                 width: 200%;
                 height: 200%;
                 position: absolute;
             }
         </style>
     </head>
     <body>
     <div class="left" id="left">
         <div class="mark" id="mark"></div>
     </div>
     <div class="right" id="right"><img src="img/1.jpg" alt=""></div>
     <script>
         var oLeft=document.getElementById("left");
         var oRight=document.getElementById("right");
         var oMark=document.getElementById("mark");
         var oImg=document.getElementsByTagName("img")[0];
         oLeft.onmouseover=function () {
             oRight.style.display=oMark.style.display="block";
         };
         //光標在運動中觸發的是子級的onmousemove事件,通過冒泡將父級onmousemove事件觸發;進而mark移動位置;
         oLeft.onmousemove=function (e) {
               e=e||window.event;
               var l=e.clientX-this.offsetLeft-this.clientLeft-oMark.offsetWidth/2;
               var t=e.clientY-this.offsetTop-this.clientTop-oMark.offsetHeight/2;
               //邊界值判斷
               var maxL=this.offsetWidth-oMark.offsetWidth;
               var maxT=this.offsetHeight-oMark.offsetHeight;
               if(l<=0){
                   l=0;
               }else if(l>=maxL){
                   l=maxL;
               }
               if(t<=0){
                   t=0
               }else if(t>=maxT) {
                   t = maxT;
               }
               //分別設置oMark和oImg的位置
               //公式:等比例運動
               oMark.style.left=l+"px";
               oMark.style.top=t+"px";
               oImg.style.left=-(oImg.offsetWidth-oRight.offsetWidth)/(this.offsetWidth-oMark.offsetWidth)*l+"px";
               oImg.style.top=-(oImg.offsetHeight-oRight.offsetHeight)/(this.offsetHeight-oMark.offsetHeight)*t+"px";
         };
         oLeft.onmouseout=function () {
             oRight.style.display=oMark.style.display="none";
         }
     </script>
     </body>
     </html>
    
1.2 放大鏡實例代碼優化
  • 代碼:
     <!DOCTYPE html>
     <html lang="en">
     <head>
         <meta charset="UTF-8">
         <title>放大鏡實例</title>
         <style>
             *{
                 margin: 0;
                 padding: 0;
             }
             .wrap{
                 width: 400px;
                 height: 400px;
                 margin-top: 1000px;
                 margin-bottom: 100px;
                 margin-left: 20px;
                 position: relative;
             }
             .wrap .smallimg{
                 width: 400px;
                 height: 400px;
                 background: url("./img/2.png") no-repeat;
                 background-size: 100%;
             }
             .wrap .bigimg{
                 width: 500px;
                 height: 500px;
                 border: 2px solid lightpink;
                 position: absolute;
                 left: 450px;
                 top: -50px;
                 overflow: hidden;
                 display: none;
             }
             .wrap .bigimg img{
                 position: absolute;
                 left: 0;
                 top: 0;
             }
         </style>
     </head>
     <body>
     <div class="wrap">
         <div class="smallimg"></div>
         <div class="bigimg"><img src="./img/3.png" alt="bigimg"></div>
     </div>
     <script src="../toolLibrary/myutils.js"></script>
     <script src="../toolLibrary/myEvent.js"></script>
     <script>
         var oWrap=document.getElementsByTagName("div")[0];
         var oSmall=oWrap.getElementsByTagName("div")[0];
         var oBig=oWrap.getElementsByTagName("div")[1];
         var obImg=oBig.getElementsByTagName("img")[0];
         var obimgmaxLeft=null;
         var obimgmaxTop=null;
         var osObj=utils.offset(oSmall);
         var oP=null;
         var maxoLeft=null;
         var maxoTop=null;
         on(oSmall,"mouseenter",toEnter);
         on(oSmall,"mousemove",toMove);
         on(oSmall,"mouseleave",toLeave);
         function toEnter() {
             console.log("in");
             oP=document.createElement("p");
             utils.css(oP,{
                 width: 100,
                 height: 100,
                 backgroundColor:"yellow",
                 opacity: 0.5,
                 position: "absolute",
                 cursor: "move"
             });
             this.appendChild(oP);
             oBig.style.display="block";
             maxoLeft=this.clientWidth-oP.offsetWidth;
             maxoTop=this.clientHeight-oP.offsetHeight;
             obimgmaxLeft=obImg.offsetWidth-oBig.clientWidth;
             obimgmaxTop=obImg.offsetHeight-oBig.clientHeight;
         }
         function toMove(e) {
             console.log("moving");
             var curLeft=e.pageX;
             var curTop=e.pageY;
             var osLeft=osObj.left;
             var osTop=osObj.top;
             var oLeft=curLeft-osLeft-this.clientLeft-oP.offsetWidth/2;
             var oTop=curTop-osTop-this.clientTop-oP.offsetHeight/2;
             //設置邊界值
             if(oLeft<0){
                 oLeft=0;
             }else if(oLeft>maxoLeft){
                 oLeft=maxoLeft;
             }
             if(oTop<0){
                 oTop=0;
             }else if(oTop>maxoTop){
                 oTop=maxoTop;
             }
             //大圖成比例移動
             var obigcurLeft=oLeft/maxoLeft*obimgmaxLeft;
             var obigcurTop=oTop/maxoTop*obimgmaxTop;
     
             //oP設置實時位置
             utils.css(oP,{
                 left:oLeft,
                 top:oTop
             });
             //bigImg設置實時位置
             utils.css(obImg,{
                 left: -obigcurLeft,
                 top: -obigcurTop
             })
         }
         function toLeave() {
             console.log("out");
             oBig.style.display="none";
             this.removeChild(oP);
             oP=null;
         }
     </script>
     </body>
     </html>
    

2 產品展示實例

  • 需求:當鼠標移出img元素上時,顯示該元素的大圖,然后大圖隨著光標的移動而移動,當移出后,大圖消失
  • 思路:
    • 利用jQuery的鏈式操作;
    • 添加鼠標移入事件,移出事件,移動事件;
    • 不能利用事件委托,事件委托會出現問題,當光標從img上移出到img間距中,這個過程中,會觸發移出事件,但是還會觸發div的移入事件,所以大圖不會消失;
  • 代碼:
     <!DOCTYPE html>
     <html lang="en">
     <head>
         <meta charset="UTF-8">
         <title>產品展示實例</title>
         <style>
             *{
                 margin: 0;
                 padding: 0;
             }
             #div1{
                 width: 668px;
                 height: 86px;
                 margin: 20px auto;
                 position: relative;
             }
             #div1 img{
                 width: 150px;
                 height: auto;
                 border: 1px solid black;
                 float: left;
             }
             #div1 img+img{
                 margin-left: 20px;
             }
             #div1 p{
                 position: absolute;
                 left: 0;
                 top: 0;
                 display: none;
             }
             #div1 p img{
                 display: block;
                 width: 300px;
             }
         </style>
     </head>
     <body>
     <div id="div1">
         <img src="img1/001.jpg" bigImg="img1/001-01.jpg" alt="">
         <img src="img1/002.jpg" bigImg="img1/002-02.jpg" alt="">
         <img src="img1/003.jpg" bigImg="img1/003-03.jpg" alt="">
         <img src="img1/004.jpg" bigImg="img1/004-04.jpg" alt="">
         <p>
             <img src="img1/004-04.jpg" alt="">
         </p>
     </div>
     <script src="jquery.js"></script>
     <script>
         //需求:當鼠標移出img元素上時,顯示該元素的大圖,然后大圖隨著光標的移動而移動,當移出后,大圖消失
         //思路:jQuery的鏈式操作
         $("#div1 img").mouseover(function (e) {
             e=e||window;
             var target=e.target ||e.srcElement;
             $("#div1 p").show().find("img").attr("src",$(target).attr("bigImg"))
         }).mousemove(function (e) {
             e=e||window;
             var target=e.target ||e.srcElement;
             $("#div1 p").css({
                 left:e.clientX-$("#div1").offset().left+10,
                 top:e.clientY-$("#div1").offset().top+10
             })
         }).mouseout(function () {
             $("#div1 p").hide()
         })
     </script>
     </body>
     </html>
    
2.2 原生JS版產品展示實例
  • 原生JS制作代碼:
     <!DOCTYPE html>
     <html lang="en">
     <head>
         <meta charset="UTF-8">
         <title>產品展示實例</title>
         <style>
             *{
                 margin: 0;
                 padding: 0;
             }
             h1{
                 width: 860px;
                 height: 50px;
                 line-height: 50px;
                 text-align: center;
                 margin: 30px auto;
             }
             .wrap{
                 display: flex;
                 width: 860px;
                 margin: 0 auto;
                 position: relative;
             }
             .wrap img{
                 width: 200px;
                 height: 112px;
             }
             .wrap img+img{
                 margin-left: 20px;
             }
             .wrap .move{
                 width: 400px;
                 height: 224px;
                 background: url("img1/001-01.jpg") no-repeat;
                 background-size: cover;
                 position: absolute;
                 left: 0;
                 top: 0;
                 display: none;
                 border: 2px solid red;
             }
         </style>
     </head>
     <body>
     <h1>產品展示欄</h1>
     <div class="wrap"><img src="img1/001.jpg" realImg="./img1/001-01.jpg" alt=""/><img src="img1/002.jpg" realImg="./img1/002-02.jpg" alt=""/><img src="img1/003.jpg" realImg="./img1/003-03.jpg" alt=""/><img src="img1/004.jpg" realImg="./img1/004-04.jpg" alt=""/>
         <div class="move"></div>
     </div>
     <script src="../toolLibrary/myutils.js"></script>
     <script src="../toolLibrary/myEvent.js"></script>
     <script>
         var oWrap=utils.getByClass("wrap")[0];
         var oMove=utils.getByClass("move")[0];
         var owtbLeft=utils.offset(oWrap).left;
         var owtbTop=utils.offset(oWrap).top;
         on(oWrap,"mouseover",toOver);
         on(oWrap,"mousemove",toMove);
         on(oWrap,"mouseout",toOut);
         function toOver(e) {
             var ele=e.target;
             if(ele.className==="wrap") return;
             var realImg=ele.getAttribute("realImg");
             utils.css(oMove,{
                 display:"block",
                 backgroundImage:"url("+realImg+")"
             });
         }
         function toMove(e) {
             var eLeft=e.pageX;
             var eTop=e.pageY;
             var omLeft=eLeft-owtbLeft-oWrap.clientLeft;
             var omTop=eTop-owtbTop-oWrap.clientTop;
             utils.css(oMove,{
                 left:omLeft+10,
                 top:omTop+20
             });
         }
         function toOut() {
             oMove.style.display="none";
         }
     </script>
     </body>
     </html>
    

3 拖拽實例

3.1 拖拽實例初級版
  • 需求:實現div元素在容器中拖拽移動
  • 問題:1)當鼠標移動太快時,光標會脫離div,此時div會停止;2)當body有內容時,當鼠標移動到文字上會默認將其選中,默認對文字進行拖拽,此時會出錯;
  • 思路:
    1. 添加onmousedown和onmousemove和onmouseup事件;
    2. 當鼠標按下事件觸發后,計算出初始位置時,光標在div中的距離,然后放在div的私有屬性上,然后在鼠標按下事件中觸發鼠標移動事件和鼠標抬起事件;
    3. 解決鼠標移動太快,會移出div的問題:在IE瀏覽器中使用setCapture將焦點捕獲到div上,在標準瀏覽器中,將鼠標移動事件和鼠標抬起事件添加到document上;
    4. 解決移動過程中默認選中文字的問題:在IE中已經焦點捕獲到div上,所以不會出現問題;在標準瀏覽器中,要取消默認事件;
    5. 在鼠標移動事件中,計算移動后位置的定位數值,進而實現移動效果
    6. 在鼠標抬起事件中要釋放事件,在IE中要釋放焦點捕獲,用releaseCapture;在標準瀏覽器下給document添加的事件釋放;
  • 知識點:
    • 焦點捕獲:setCapture,給一個元素設置焦點捕獲后,讓焦點永遠在該元素上;
    • 釋放焦點捕獲:releaseCapture
    • 兼容性問題:IE瀏覽器支持;fireFox火狐瀏覽器支持屬性,但是沒有效果;其他標準瀏覽器不支持;
  • 注意點:
    • up函數中的this指向問題,this指向不同的元素;
    • 事件的釋放問題,賦值為null;
  • 代碼:
     <!DOCTYPE html>
     <html lang="en">
     <head>
         <meta charset="UTF-8">
         <title>拖拽</title>
         <style>
             body{
                 width: 500px;
                 height: 1000px;
                 font-size: 30px;
             }
             div{
                 width: 200px;
                 height: 200px;
                 background-color: red;
                 position: absolute;
                 left: 0;
                 top: 0;
             }
         </style>
     </head>
     <body>
     fiefehisssjfjsfsdigheifefiefflsjfilfjskljfiefehisssjfjsfsdigheifefieffl
     sjfiengeifjiwedsnfiefnefkelfjskljfiefehifiefehisssjfjsfsdigheifefiefflsjfilfjskljfiefehi
     sssjfjsfsdigheifefiefflsjfiengeifjiwedsnfiefnefkelfjskljfiefehifiefehisssjfjsfsdigheifefiefflsjfilfjskljfiefehisssjfjs
     fsdigheifefiefflsjfiengeifjiwedsnfiefnefkelfjskljfiefehifiefehisssjfjsfsdigheifefiefflsjfilfjskljfiefehisssjfj
     sfsdigheifefiefflsjfiengeifjiwedsnfiefnefkelfjskljfiefehi
     <div id="div1"></div>
     <script>
         var oDiv=document.getElementById("div1");
         oDiv.onmousedown=down;
         function down(e) {
             e=e||window.event;
             this.disX=e.clientX-this.offsetLeft;
             this.disY=e.clientY-this.offsetTop;
             if(this.setCapture){//IE瀏覽器
                 this.setCapture();
                 this.onmousemove=move;
                 this.onmouseup=up;
             }else{//標準瀏覽器
                 var _this=this;
                 document.onmousemove=function (e) {
                     move.call(_this,e);
                 };
                 document.onmouseup=up;//傳入的this為document;
                 e.preventDefault();//阻止默認事件;防止選中文字;
             }
         }
         function move(e) {
             //在調用的時候,要始終保證里面的this為div元素;
             e=e||window.event;
             this.style.left=e.clientX-this.disX+"px";
             this.style.top=e.clientY-this.disY+"px";
         }
         function up() {
             //此時進入調用up后傳入的this可以不同;
             if(this.releaseCapture){
                 this.releaseCapture();//釋放焦點捕獲;
             }
             this.onmousemove=null;
             this.onmouseup=null;
         }
     </script>
     </body>
     </html>
    
3.2 拖拽實例終極版
  • 知識點:
    • 通過bind預處理的函數與原來的函數,二者不再是同一個函數體,是不同的地址;在函數解綁時,會出現問題;
    • 解決方法:可以將bind預處理的函數綁定在原函數的靜態屬性上,這樣在解綁時,就可以通過靜態屬性拿到函數體;
  • 代碼:
     <!DOCTYPE html>
     <html lang="en">
     <head>
         <meta charset="UTF-8">
         <title>拖拽實例終極版</title>
         <style>
             body{
                 height: 1000px;
                 font-size: 30px;
             }
             div{
                 width: 200px;
                 height: 200px;
                 background-color: red;
                 position: absolute;
                 left: 0;
                 top: 0;
             }
         </style>
     </head>
     <body>
     fiefehisssjfjsfsdigheifefiefflsjfilfjskljfiefehisssjfjsfsdigheifefieffl
     sjfiengeifjiwedsnfiefnefkelfjskljfiefehifiefehisssjfjsfsdigheifefiefflsjfilfjskljfiefehi
     sssjfjsfsdigheifefiefflsjfiengeifjiwedsnfiefnefkelfjskljfiefehifiefehisssjfjsfsdigheifefiefflsjfilfjskljfiefehisssjfjs
     fsdigheifefiefflsjfiengeifjiwedsnfiefnefkelfjskljfiefehifiefehisssjfjsfsdigheifefiefflsjfilfjskljfiefehisssjfj
     sfsdigheifefiefflsjfiengeifjiwedsnfiefnefkelfjskljfiefehi
     <div></div>
     <script src="../toolLibrary/myutils.js"></script>
     <script src="../toolLibrary/myEvent.js"></script>
     <script>
         var oDiv=document.getElementsByTagName("div")[0];
         on(oDiv,"mousedown",mouseDown);
         function mouseDown() {
             console.log("mousedown");
             //鼠標按下事件觸發后,綁定兩個事件,移動事件和鼠標抬起事件
             if(this.setCapture){
                 //IE瀏覽器支持
                 console.log("ie");
                 this.setCapture();//焦點捕獲
                 on(this,"mousemove",mouseMove);//將事件綁定在this上;
                 on(this,"mouseup",mouseUp);
             }else{
                 //其他瀏覽器中綁定在document中,
                 console.log("qita");
                 //mouseMove.bind(this)后的地址與mouseMove地址不同;為兩個不同的函數體
                 //把用bind預處理后的函數賦值在mouseMove函數的靜態屬性fn上;用于解綁函數;
                 mouseMove.fn=mouseMove.bind(this);
                 on(document,"mousemove",mouseMove.fn);
                 on(document,"mouseup",mouseUp);
             }
     
         }
         function mouseMove(e) {
             console.log("move");
             var eLeft=e.clientX;
             var eTop=e.clientY;
             var oLeft=eLeft-this.offsetWidth/2;
             var oTop=eTop-this.offsetHeight/2;
             var maxoLeft=document.body.offsetWidth-this.offsetWidth;
             var maxoTop=document.body.offsetHeight-this.offsetHeight;
             e.preventDefault();//阻止默認選中文字事件;
             //邊界值判斷
             if(oLeft<0){
                 oLeft=0;
             }else if(oLeft>maxoLeft){
                 oLeft=maxoLeft;
             }
             if(oTop<0){
                 oTop=0;
             }else if(oTop>maxoTop){
                 oTop=maxoTop;
             }
             utils.css(this,{
                 left: oLeft,
                 top: oTop
             });
         }
         function mouseUp() {
             console.log("mouseup");
             //鼠標抬起事件觸發后,mousemove解綁;
             if(this.releaseCapture){
                 this.releaseCapture();//釋放焦點捕獲;
                 off(this,"mousemove",mouseMove);
             }else{
                 off(this,"mousemove",mouseMove.fn);//解綁靜態屬性,即bind預處理的函數;
             }
             off(this,"mouseup",mouseUp);
         }
     </script>
     </body>
     </html>
    

4 bind兼容版myBind()封裝

  • 原因:類函數原型上存在三個屬性方法,call(),apply(),bind(),其中call(),apply()兩個方法時改變this指向并傳入參數后,函數就立即執行了,在一些場景中,不希望函數立即執行,比如在點擊事件中,給事件賦值,賦值為函數的定義階段,當點擊行為發生時,才讓函數執行,所以需要進行函數的預處理,讓其改變了this指向和傳入參數后,返回的還是函數定義階段,所以只能用bind()方法,但是問題就是,bind()只在標準瀏覽器(包括IE9,10)下才支持,在IE瀏覽器(IE6,7,8)下不支持,會報錯;所以需要封裝一個都兼容的方法;
  • 目的:封裝一個跟bind()方法功能一樣,和使用方法也一樣的方法,就是為了兼容IE瀏覽器;
  • 分析bind()方法:
    • bind是類函數Function原型上的公有屬性,所有的函數實例均可以使用此屬性方法;
    • bind()方法使用時的代碼:函數名.bind(thisArg,...)
    • 參數:第一個參數必傳,為改變后的this,后面的參數可傳可不傳,為函數中的實參值;
    • bind()方法的實質為:"函數名.bind"這個函數的執行,將傳入的參數進行一些處理,返回一個匿名函數;
    • "函數名.bind()"中的this指向函數名實例;
  • 封裝兼容版的myBind()函數
    • 封裝思路:
      • 封裝位置:封裝在大Function類的原型上
      • 參數:至少要傳入一個參數,改變this指向,剩余的參數用arguments獲取
      • 函數體封裝:判斷類函數原型上是否存在bind屬性,來判斷瀏覽器種類,確定在標準瀏覽器下執行系統bind,在IE瀏覽器下封裝新的函數
      • 返回值:匿名函數;
    • 知識點:
      • 類數組(arguments)轉數組:利用數組原型上的slice屬性,通過call代表其函數中的this指向,來實現克隆,進而獲取一個真數組
        • 代碼:outArg=[].slice.call(arguments,1);,其中1代表從索引為1的元素開始截取,形成一個新數組;
      • 在標準瀏覽器下,直接使用bind方法,但是在給bind()中傳入實參時,outArg為一個數組,不能直接往里面傳,所以需要apply來往里面傳數組,將this.bind作為一個函數,用apply傳參,第一個參數為改變this指向的,傳入當前的this,也就是函數實例,但不能傳null;為什么不能傳null,有待解答;
        • 代碼:this.bind.apply(this,[thisArg].concat(outArg));
    • 注意點:
      • 在IE瀏覽器下,需要返回一個匿名函數,但是當匿名函數執行的時候,函數中的this不再是函數實例,而是執行時點前面的元素,或是事件觸發的元素;所以需要創建變量_this來保存住外面的this,然后在匿名函數中使用_this,使用apply方法來實現this指向的改變和實參的傳入;
      • 當myBind使用在事件賦值時,會出現問題,因為在事件觸發時,會向賦值中的匿名函數中傳入一個實參,為事件對象,所以必須myBind在封裝時,必須考慮事件對象實參的傳入,由于在IE瀏覽器中,事件觸發不會向匿名函數中傳入事件對象實參,但是匿名函數中需要使用事件對象時,就需要通過window.event獲取,所以必須用apply將事件對象innerArg傳入函數實例對象中;
    • 問題:
      • 在IE瀏覽器下,myBind不使用在事件賦值中,此時在函數中arguments獲取的所有實參值組成的類數組中的最后一項為null,因為不存在事件對象,但是還是會存在此項,值為null;
    • 代碼:
     <!DOCTYPE html>
     <html lang="en">
     <head>
         <meta charset="UTF-8">
         <title>bind函數封裝</title>
         <style>
             div{
                 width: 200px;
                 height: 200px;
                 background-color: red;
             }
         </style>
     </head>
     <body>
     <div id="div"></div>
     <script>
         //封裝在類函數的原型上
         Function.prototype.myBind=function (thisArg) {
             var outArg=[].slice.call(arguments,1);//指的是將類數組arguments轉化為數組,然后從索引為1的元素開始截?。猾@取除了thisArg以外的其他實參組成的數組;
             if("bind" in Function.prototype){
                 //如果瀏覽器支持bind屬性,則用系統自帶的bind屬性
                 //bind()方法就是將傳入的參數經過一系列操作,然后到達目的,怎么做不用管,只要保證傳入參數就行,此時就是為了給bind傳參,但是outArg為一個數組,不能直接給bind傳,所以需要用apply來傳入數組,但是apply不需要改變this.bind這個函數中的this,所以傳參為this,后面以一個數組的形式傳入實參,所以需要把thisArg與outArg拼接;
                 return this.bind.apply(this,[thisArg].concat(outArg));//此時apply中必須串this,不能穿null;
             }
             //在IE瀏覽器下,要返回一個匿名函數
             var _this=this;
             return function (e) {
                 //事件在觸發時,在標準瀏覽器下,會默認向匿名函數中傳入一個實參,為事件對象,在IE瀏覽器下,不會默認傳入實參,所以獲取事件對象需要用window.event;
                 //此時實際上e肯定沒有值,但是為了以后的代碼更新,所以判斷一下;
                 //匿名函數在執行時里面的this一定不是實例;
                 var innerArg=arguments.length==0?window.event:e;
                 return _this.apply(thisArg,outArg.concat(innerArg));
             }
         };
         var oDiv=document.getElementById("div");
         var obj={};
         function fn(n,m) {
             console.log(arguments);
             console.log(this);
             console.log(n+m);
             //console.log(e.clientX,e.clientY);
         }
         //1 函數一般執行
         var res=fn.myBind(obj,2,3);
         res();
         /*在IE瀏覽器下的打印結果:
         * {0: 2, 1: 3, 2: null}
         * [Object]
         * 5
         * */
         //2 點擊事件觸發函數執行
         oDiv.onclick=fn.myBind(obj,2,3);
         /*在IE瀏覽器下的打印結果:
         * {0: 2, 1: 3, 2: MouseEvent}
         * [Object]
         * 5
         * */
     </script>
     </body>
     </html>
    

5 事件對象基礎解讀

  • 事件對象的獲取
    • 若事件賦值為:匿名函數,若匿名函數中需要使用事件對象,就必須在匿名函數中設置形參e,然后在匿名函數體才能使用e來獲取事件對象,如果不需要使用事件對象,就不用在匿名函數中設置形參e;
     //此時事件賦值了一個匿名函數,在匿名函數要設置形參e,目的是在匿名函數體中用e來代表傳入的實參
     oDiv.onmousemove=function (e) {
        move.call(this,e);//call用來改變this指向和傳入實參e;此時的e作為實參,傳入到move中,必須要穿;
      };
     function move(e) {//此時形參e就接受到傳入的實參e;
        e=e||window.event;
        this.style.left=e.clientX-this.disX+"px";
        this.style.top=e.clientY-this.disY+"px";
      }
     //總結:call里面必須要傳入實參e,如果不傳入實參e,在move函數體中,拿到e為undefined,原因是:函數中如果設置形參,形參相當于聲明加定義,會進行預解釋,如果沒有傳入實參,那形參時為undefined,相當于var e=undefined,現在的e為函數的私有變量,跟外界沒有任何關系;如果不設置形參e,在move函數執行后的私有作用域中找不到e,它就會通過作用域鏈向其上一級作用域查找,永遠不會去onmousemove事件賦值中的匿名函數查找,得不到里面的e,它里面的e也是自己的私有變量
    
    • 若事件賦值為:fn.myBind(),那么不管在fn中是否需要事件對象,在括號中,都不需要傳入e。如果在fn函數中需要事件對象,就設置形參e,如果不需要事件對象,就不用設置形參e;
     <!DOCTYPE html>
     <html lang="en">
     <head>
         <meta charset="UTF-8">
         <title>事件與myBind函數</title>
         <style>
             div{
                 width: 200px;
                 height: 200px;
                 background-color: red;
             }
         </style>
     </head>
     <body>
     <div id="div1">11111</div>
     <script>
         Function.prototype.myBind=function (thisArg) {
             var outArg=[].slice.call(arguments,1);
             if("bind" in Function.prototype){
               return this.bind.apply(this,[thisArg].concat(outArg));
             }
             var _this=this;
             return function (e) {
                 var innerArg=arguments.length==0?window.event:e;
                 return _this.apply(thisArg,outArg.concat(innerArg));
             }
         };
         var oDiv=document.getElementById("div1");
         var age=3;
         var obj={age:1};
         //1 move中不使用事件對象,不用設置e;
         oDiv.onclick=move.myBind(null,2,3);
         function move(n,m) {//此時形參e1就接受到傳入的實參e;
             console.log(this.age);//打印結果為:3
             console.log(n+m);
         }
         //2 move中使用事件對象,則設置形參e
         oDiv.onclick=move.myBind(obj,2,3);
         function move(n,m,e) {//此時形參e1就接受到傳入的實參e;
             console.log(this.age);//打印結果為:1
             console.log(n+m);
             console.log(e.clientX,e.clientY);
         }
         //無論在move函數中是否使用事件對象,在myBind()括號中都不傳e;
     </script>
     </body>
     </html>
    

6 點擊事件知識點

  • 點擊事件賦值
    • 賦值為匿名函數:點擊事件觸發時,匿名函數中的this為被點擊元素,而且在標準瀏覽器下,會默認向匿名函數傳事件對象實參;
    • 賦值為函數名:點擊事件觸發時,函數體內的this為被點擊元素,而且在標準瀏覽器下,會默認向函數體內傳入事件對象參數;
    • 賦值為fn.bind():點擊事件觸發時,在標準瀏覽器下,會默認向函數體fn內傳入事件對象實參;但函數體內的this不再是被點擊元素,而是自己的this,一般為window;
      • bind(null)中改變this指向的參數為:null,此時的fn中的this為window;意思是沒有改變fn中的this;
      • bind(this)中改變this指向的參數為:this,此時狀態下的this指的是window,所以fn中的this為window;意思是將fn中的this改變為window;將fn中的this改變了;
      • bind(oDiv)中改變this指向的參數為:oDiv,此時fn中的this被改變為oDiv元素;
     <script>
         var oDiv=document.getElementById("div1");
         function move(e) {
             console.log(this);
             console.log(e)
         }
         oDiv.onclick=move.bind(null);//打印結果為:window;
         oDiv.onclick=move.bind(this);//打印結果為:window;
         oDiv.onclick=move.bind(oDiv);//打印結果為:oDiv;
     </script>
    
  • 點擊事件實例
    • 需求:oDiv添加點擊事件,當點擊事件觸發時,執行move1()函數,保證move1函數中的this為該點擊元素,并在move1函數中獲取事件對象;
    • 方法一:給點擊事件賦值為匿名函數,在匿名函數中執行move1函數,通過call來改變this指向和傳入實參;
      • 注意兼容處理,在IE瀏覽器下,點擊事件不會向匿名函數傳事件對象實參,所以需要通過window.event獲??;
       <!DOCTYPE html>
       <html lang="en">
       <head>
           <meta charset="UTF-8">
           <title>點擊事件驗證</title>
           <style>
               div{
                   width: 200px;
                   height: 200px;
                   background-color: red;
               }
           </style>
       </head>
       <body>
       <div id="div1">1111</div>
       <script>
           //需求:給oDiv添加點擊事件,當點擊事件觸發時,執行move1()函數,保證move1函數中的this為該點擊元素,并在move1函數中獲取事件對象;
           var oDiv=document.getElementById("div1");
           oDiv.onclick=function (e) {
               move1.call(this,2,3,e);
               //move1.call(null,2,3,e);//若此時call中賦值為null,則move1執行時,函數中的this為window;
           };
           function move1(n,m,e) {
               e=e||window.event;//在IE瀏覽器中,點擊事件觸發不會向匿名函數傳事件對象實參,所以獲取到的e為undefined;此代碼就會執行window.event獲取到事件對象;
               console.log(this);
               console.log(n+m);
               console.log(e.type);
           }
           //打印結果為:oDiv,5,click;
           //總結:點擊事件后面賦值為匿名函數,當事件觸發時,在匿名函數中的this為該元素,在標準瀏覽器下,會默認向匿名函數中傳入事件對象實參;在IE瀏覽器下,不會傳入事件對象實參;
       </script>
       </body>
       </html>
      
    • 方法二:給點擊事件賦值bind方法
      • 注意1:bind方法只能在標準瀏覽器中使用,IE瀏覽器不支持
      • 注意2:點擊事件觸發后,move1中的this不再是被點擊元素,需要通過bind改變為元素,不要在傳參的時候添加e;
       <script>
           //需求:給oDiv添加點擊事件,當點擊事件觸發時,執行move1()函數,保證move1函數中的this為該點擊元素,并在move1函數中獲取事件對象;用bind方法實現
           var oDiv=document.getElementById("div1");
           //oDiv.onclick=move1.bind(this,2,3);//此時this為window,函數執行時,獲取到的this也為window;
           //oDiv.onclick=move1.bind(null,2,3);//此時賦值null,在函數執行時,函數體里獲取的this為window;
           //oDiv.onclick=move1;//此時賦值函數名,在函數執行時,函數體里獲取的this為oDiv元素;
           function move1(n,m,e) {
               console.log(this);
               console.log(n+m);
               console.log(e.type);
           }
           oDiv.onclick=move1.bind(oDiv,2,3);
           //打印結果為:oDiv,5,click;
           //總結:bind方法,是對函數進行預處理,需注意的是:1)添加bind后,如果this執行賦值為null;那么在點擊事件發生時,在函數體內獲取的this為window;
       </script>
      
    • 方法三:給點擊事件賦值自己封裝的myBind方法
      • myBind方法本質上就是模仿bind方法,旨在達到跟bind一樣的效果,保證IE瀏覽器下能夠使用,使所有瀏覽器都兼容;
      • 使用:跟bind方法使用一樣
       <!DOCTYPE html>
       <html lang="en">
       <head>
           <meta charset="UTF-8">
           <title>點擊事件與myBind函數</title>
           <style>
               div{
                   width: 200px;
                   height: 200px;
                   background-color: red;
               }
           </style>
       </head>
       <body>
       <div id="div1">11111</div>
       <script>
           //myBind封裝兼容版
           //本質上就是模仿bind方法,旨在達到跟bind一樣的效果,保證IE瀏覽器下能夠使用,使所有瀏覽器都兼容;
           //使用:跟bind方法使用一樣
           Function.prototype.myBind=function (thisArg) {
               var outArg=[].slice.call(arguments,1);
               if("bind" in Function.prototype){
                   return this.bind.apply(this,[thisArg].concat(outArg));
               }
               var _this=this;
               return function (e) {
                   var innerArg=arguments.length==0?window.event:e;
                   return _this.apply(thisArg,outArg.concat(innerArg));
               }
           };
           //實現需求
           var oDiv=document.getElementById("div1");
           function move1(n,m,e) {
               e=e||window.event;
               console.log(this);
               console.log(n+m);
               console.log(e.type);
           }
           oDiv.onclick=move1.myBind(oDiv,2,3);
           //打印結果為:oDiv,5,click;
       </script>
       </body>
       </html>
      
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,825評論 6 546
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,814評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,980評論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 64,064評論 1 319
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,779評論 6 414
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,109評論 1 330
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,099評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,287評論 0 291
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,799評論 1 338
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,515評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,750評論 1 375
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,221評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,933評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,327評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,667評論 1 296
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,492評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,703評論 2 380

推薦閱讀更多精彩內容

  • "use strict";function _classCallCheck(e,t){if(!(e instanc...
    久些閱讀 2,045評論 0 2
  • 事件 1 事件流 冒泡:從該元素開始由里向外觸發一類事件,事件對象中的事件源為該元素,觸發同一類事件,在子級父級祖...
    果木山閱讀 205評論 0 0
  • 1. tab列表折疊效果 html: 能源系統事業部 崗位名稱: 工作地點 崗位名...
    lilyping閱讀 1,886評論 0 1
  • 第一部分 HTML&CSS整理答案 1. 什么是HTML5? 答:HTML5是最新的HTML標準。 注意:講述HT...
    kismetajun閱讀 27,588評論 1 45
  • 遇到困難和挑戰,我想打退堂鼓的時候,就會對自己說“沒關系,我不想取得多大成就,只想做個普通人”。那時候以為做一個普...
    冬素閱讀 860評論 2 1