JS筆記(17):事件

1、事件的種類

  • 事件:一件事情或者一種行爲(對於元素來講,他的不少事件都是天生自帶的),只要咱們去操做這個元素,就會觸發這些行爲
    • 若是沒有事件函數賦值,事件默認值爲null
    • 系統默認事件:null
    • 自定義事件:undefined

元素天生自帶的事件(事件自己不帶on):

1) 【鼠標事件】

  • click: 點擊(PC端是點擊,移動端的click表明單擊[移動端使用click會有300ms的延遲])
  • dblclick: 雙擊
  • mouseover: 鼠標通過
  • mouseout:鼠標移出
  • mouseenter:鼠標進入(沒有冒泡)
  • mouseleave:鼠標離開(沒有冒泡)
  • mousemove:鼠標移動
  • mousedown:鼠標按下(鼠標左右鍵都起做用,按下即觸發,click是按下擡起才觸發,並且先把down和up觸發,才觸發click)
  • mouseup:鼠標擡起
  • mousewheel:鼠標滾輪滾動
  • contextmetu:右鍵上下文菜單

2) 【鍵盤事件】

  • keydown:鍵盤按下(獲取不到最新的value值,只能獲取到上一個)
  • keyup:鍵盤擡起(能夠獲取到新的value值)
  • keypress:鍵盤長按(通常不用),和keydown相似,但keydown返回的是鍵盤碼,keypress返回的是ASCII碼
  • input:移動端的內容改變事件。因爲PC端有物理鍵盤,能夠監聽到鍵盤的按下和擡起,可是移動端時虛擬鍵盤,因此keydownkeyup在大部分手機上都沒有,因此使用input事件統一代替他們

3) 【表單元素經常使用的事件】

  • input:當<input><select><textarea>的值發生變化時觸發
// input事件
<textarea id="txt"></textarea>
<span id="span">0字</span>
// js部分
txt.addEventListener('input',function(ev){
    span.innerHTML = txt.value.length + '字'
})
複製代碼
  • focus:獲取焦點
  • blur:失去焦點
  • select:在<input><textarea>裏面選中文本時觸發。(也有聚焦的功能)
// focus事件 select事件
<input type="text" id="txt1"/>
<button id="btn">選中代碼</button>

//js部分
 txt1.addEventListener('focus',function(){
    console.log(1)
})
// txt1.focus(); //打開頁面自動聚焦
btn.onclick = function(){
    txt1.select()
}
複製代碼
  • change:事件當<input><select><textarea>的值發生變化時觸發。
    • 它與input事件的最大不一樣,就是不會連續觸發,只有當所有修改完成時纔會觸發,另外一方面input事件必然伴隨change事件。
    • 具體來講,分紅如下幾種狀況:
      • A. 激活單選框(radio)或複選框(checkbox)時觸發。
      • B. 用戶提交時觸發。好比,從下列列表(select)完成選擇,在日期或文件輸入框完成選擇。
      • C. 當文本框或<textarea>元素的值發生改變,而且喪失焦點時觸發。
// change事件
 <select name="" id="sele">
    <option>哈哈</option>
    <option>呵呵</option>
    <option>嘿嘿</option>
    <option>嘻嘻</option>
</select>
<div id="div">哈哈</div>

//js部分
sele.onchange = function(){
    console.log(this.value);
    div.innerHTML = this.value;
}
複製代碼

4)【其餘經常使用事件】

  • load:加載完成
  • unload:在窗口關閉或者document對象將要卸載時觸發
  • beforeunload:事件在窗口、文檔、各類資源將要卸載前觸發。它能夠用來防止用戶不當心卸載資源
  • scroll:滾動條滾動事件(頁面必需要有滾動條)
  • mousewheel:滾動條滾動事件(只要鼠標滾輪就觸發)
    • ev.wheelDelta: 能夠檢測滾動的方向
      • 180 上滾輪
      • -180 下滾輪
  • DOMMouseScroll: 火狐瀏覽器的滾輪滾動事件(只支持DOM2)
    • ev.detail: 檢測滾動的方向
      • -3 上滾輪
      • 3 下滾輪
  • resize:大小改變事件 window.onresize = function(){} 當瀏覽器窗口大小發生改變,會觸發這個事件
  • error:事件是在頁面或資源加載失敗時觸發
  • hashchange:事件在 URL 的 hash 部分(即#號後面的部分,包括#號)發生變化時觸發

5) 【移動端手指事件】

[單手指操做:touch]javascript

  • touchstart:手指按下
  • touchmove:手指移動
  • touchend:手指離開
  • touchcancel:由於意外狀況致使手指操做取消 [多手指操做:gesture]
  • gesturestart:多手指按下
  • gesturechange:手指改變
  • gestureend:手指離開

6) 【H5中audio/video音視頻事件】

  • canplay:能夠播放(播放過程當中可能出現因爲資源沒有加載完成致使的卡頓)
  • canplaythrough:資源加載完成,能夠正常無障礙播放

7) 【網頁狀態事件】

  • DOMContentLoaded: DOM加載完成才觸發的事件(高版本支持)
  • readystatechange: DOM加載完成才觸發的事件(DOM加載完成才觸發的事件)
    • 在低版本IE下,document有個doScroll的方法 document.documentElement.doScroll('left')java

      這個方法在DOM沒有加載出來以前是沒有的,也就是說 調用該方法會報錯,換句話來講,只要DOM記載成功 就有doScroll方法chrome

try{
    document.documentElement.doScroll('left')
    console.log('DOM加載完成');
}catch(e){
    再次調用trycatch直到進try
}
複製代碼
/* 在try中包裹可能會報錯的代碼,包裹以後不會影響下面代碼執行 只要捕獲到錯誤,那麼會進catch */

// let a = 5;
try{
    console.log(a);
}catch(error){
    a = 10;
    console.log(error);//字符串
}
alert(a);
複製代碼

可自主擴展其餘事件後端

2、事件綁定

  • 事件綁定: 給元素天生自帶的事件行爲綁定方法,當事件觸發,會把對應的方法執行

【DOM0級事件綁定】

  • element.onxxx = function(){}
  • 解除事件:ele.事件 = null

【DOM2級事件綁定】

  • element.addEventListener('xxx', function(){}, false);
  • 該方法接受三個參數。
    • 第一個參數:事件名稱,大小寫敏感。
    • 第二個參數:監聽函數。事件發生時,會調用該監聽函數。
    • 第三個參數:布爾值,表示監聽函數是否在捕獲階段(capture)觸發,默認爲false(監聽函數只在冒泡階段被觸發)。該參數可選。
  • 移除事件的監聽函數: ele.removeEventListener('click', listener, false);
    • 注意:listener參數若是爲 fn.bind(this),則不能移除,由於bind會改變函數地址

事件綁定的目的:

給當前元素的某個事件綁定方法(不論是基於DOM0仍是DOM2),都是爲了觸發元素的相關行爲的時候,能把綁定的方法執行,不只把方法執行,並且瀏覽器還給方法傳遞了一個實參信息 ===>事件對象數組

3、事件對象:

事件對象的種類

  • MouseEvent 鼠標事件對象
  • KeyboardEvent 鍵盤事件對象
  • Event 普通事件對象
  • TouchEvent 手指事件對象

事件對象的目的:

  • 事件對象中記錄了不少屬性名和屬性值,這些信息中心包含了當前操做的基礎信息,例如:
    • 鼠標點擊位置的X/Y軸座標
    • 鼠標點擊的是誰(事件源)

事件對象中經常使用的屬性:

1) 【MouseEvent:鼠標事件對象中的屬性】

  • ev.target: 事件源(操做的是哪一個元素),在嵌套關係中,給上層元素綁定事件,能夠經過事件源,查到事件觸發的對象(元素)
  • ev.target.tagName: 'LI' 查看標籤名(大寫)
  • ev.clientX / ev.clientY: 當前鼠標觸發點距離當前窗口可視區左上角的X/Y軸座標

  • ev.pageX / ev.pageY: 當前鼠標觸發點距離body(第一屏幕)左上角X/Y軸座標
    • 至關於 pageXOffset + event.clientX (元素到body左邊的距離+元素自己寬度)
    • 至關於 pageYOffset + event.clientY (元素到body頂部的距離+元素自己高度)
  • ev.preventDefault(): 阻止默認行爲
  • ev.stopPropagation(): 阻止事件的冒泡傳播(低版本瀏覽器不兼容)
  • ev.cnacelBubble = true: 阻止事件的冒泡傳播(chrome/IE: window中都有一個event對象,火狐中沒有event對象)
  • ev.type: 當前事件類型

2) 【KeyboardEvent: 鍵盤事件對象中的屬性】

  • ev.keycode: 當前按鍵的鍵盤碼(數字類型) 13
  • v.ctrlKey: 布爾值
  • ev.shiftKey: 布爾值
  • ev.altKey: 布爾值 [經常使用的鍵盤碼]
  • 左-上-右-下: 37 38 39 40
  • Backspace: 8
  • Enter: 13
  • Space: 32
  • Delete: 46
  • Shift: 16
  • Alt: 18
  • Ctrl: 17
  • F1-F12: 112-123
  • 0-9: 48-57
  • 小寫字母: 65-90
// MouseEvent 鼠標事件對象
box.onclick = function(ev){
    //定義一個形參ev用來接收方法執行的時候,瀏覽器傳遞的信息值(事件對象)
    console.log(ev); 
    //MouseEvent {isTrusted: true, screenX: 52, screenY: 161, clientX: 52, clientY: 58, …}
}
複製代碼
// KeyboardEvent 鍵盤事件對象
box.onkeydown = function(ev){
    console.log(ev); 
}
input.onkeydown = function(ev){
    console.log(ev); //KeyboardEvent {isTrusted: true, key: "Enter", code: "Enter", location: 0, ctrlKey: false, …}
}
複製代碼
// Event 普通事件對象
window.onload = function(ev){
    console.log(ev); //Event {isTrusted: true, type: "load", target: document, currentTarget: Window, eventPhase: 2, …}
}
複製代碼

鍵盤事件小例子

結構和樣式瀏覽器

<input type="text" id="txt">
<ul id="ul"></ul>
複製代碼
let ul = document.getElementById('ul')
txt.addEventListener('keyup',function(ev){
    console.log(ev);
    // 同時按住ctrl鍵和enter鍵 就把input輸入框中輸入的內容插入到已有li元素的前面
    if(ev.keyCode === 13 && ev.ctrlKey){
        ul.insertAdjacentHTML('afterbegin',`<li>${this.value}</li>`)
    }
})
複製代碼

關於mouseenter和mouseover的區別:

  • mouseover: 鼠標通過
  • mouseout:鼠標移出
  • mouseenter:鼠標進入(阻止冒泡傳播)
  • mouseleave:鼠標離開(阻止冒泡傳播) 真實項目中多用 mouseenter/mouseleave

結構和樣式bash

<style>
    #outer {
        position: absolute;
        top: 30px;
        left: 30px;
        width: 500px;
        height: 500px;
        background: red;
        cursor: pointer;
    }
    #inner {
        position: absolute;
        top: 30px;
        left: 30px;
        width: 150px;
        height: 150px;
        background: #fff;
        cursor: pointer;
    }
</style>
複製代碼
<div id="outer">
    <div id="inner"></div>
</div>
複製代碼
// 用onmouseover / onmouseout 
inner.onmouseover = function () {
    console.log('進入白盒子')
}
inner.onmouseout = function () {
    console.log('離開白盒子')
}
outer.onmouseover = function () {
    console.log('進入紅盒子')
}
outer.onmouseout = function () {
    console.log('離開紅盒子')
}
複製代碼
// 用onmouseenter / onmouseleave
inner.onmouseenter = function () {
    console.log('進入白盒子')
}
inner.onmouseleave = function () {
    console.log('離開白盒子')
}
outer.onmouseenter = function () {
    console.log('進入紅盒子')
}
outer.onmouseleave = function () {
    console.log('離開紅盒子')
}
複製代碼

4、事件的默認行爲

事件的默認行爲:

事件自己就是天生就有的,某些事件觸發,即便沒有綁定方法,也會存在一些效果,這些默認的效果就是事件的默認行爲服務器

A. 例如:a標籤的點擊操做就存在默認行爲

  • 1.頁面跳轉
    • <a href="http://www.baidu.com" target="_blank"><a/>
  • 2.描點定位(hash定位)
    • <a href="#box" target="_blank"><a/>
    • 首先會在當前頁面URL地址欄末尾設置一個hash值,瀏覽器檢測到hash值後,會默認定位到當前頁面中id和hash相同的盒子的位置(基於hash值實現spa單頁面應用)

B. 例如:input標籤的默認行爲:

  • 1.輸入內容能夠呈現到文本框當中
  • 2.輸入內容時,會把以前輸入的一些信息呈現出來(並非全部瀏覽器和全部狀況都有)

C. 例如:submit標籤的默認行爲:

form當中設置anction,點擊submit,會默認按照anction的地址進行頁面跳轉,而且把表單中的信息傳遞進去(非先後端分離項目中,有服務器進行頁面渲染,由其餘語言實現數據交互)前後端分離

<form action="https://www.baidu.com/">
<input type="submit" value="提交"/>
</form>
複製代碼

5、阻止事件的默認行爲

A. 阻止a標籤的默認行爲

不少時候咱們使用a標籤僅僅是想作一個普通的按鈕,點擊實現一個功能,不想頁面跳轉,也不想錨點定位ide

    1. 在結構中阻止:

    <a href="javascript:void 0/undefined/null/false;">珠峯最新視頻</a>

    1. 在JS中阻止:

給其click事件綁定方法,當咱們點擊a標籤,先觸發click事件,其次纔會執行本身的默認行爲

    1. ev.returnValue = false; (支持DOM0和DOM2,能夠設置布爾值來控制是否阻止默認行爲)
    1. return false; (只支持DOM0)
    1. ev.preventDefault(); (DOM2經常使用)

若是想阻止某部分元素的默認行爲,在指定元素下阻止便可;若是在document上阻止默認行爲,那麼整個文檔中的默認行爲都會被阻止

// 阻止a標籤的默認行爲
link.onclick = function(ev){
    ev = ev || window.event;
    // return false;
    ev.preventDefault ? ev.preventDefault():ev.returnValue = false;
}
複製代碼

B. 阻止input標籤的默認行爲

// 阻止input標籤的默認行爲,即不能輸入內容 

// DOM0
input1.onkeydown = function(ev){
    // ev = ev || window.event;
    ev.preventDefault() ? ev.preventDefault() : ev.returnValue = false;
    // return false;
}

// DOM2
input1.addEventListener('keydown',function(ev){
    ev.preventDefault();
})
複製代碼

C. 阻止contectmenu的默認行爲

// 阻止右鍵菜單的默認行爲
document.addEventListener('contextmenu',function(ev){
    ev.preventDefault()
})
複製代碼

6、事件的傳播機制

1) 事件的傳播機制:(事件流/事件模型機制)

  • 冒泡傳播:

觸發當前元素的某一個事件(好比點擊事件)行爲,不只當前元素事件行爲觸發,並且其祖先元素的相關事件行爲也會被依次觸發,這種機制就是事件的傳播機制

  • 這種傳播分紅三個階段。
    • 第一階段:從window對象傳導到目標節點(上層傳到底層),稱爲「捕獲階段」(capture phase)。
    • 第二階段:在目標節點上觸發,稱爲「目標階段」(target phase)。
    • 第三階段:從目標節點傳導回window對象(從底層傳回上層),稱爲「冒泡階段」(bubbling phase)。

這三個階段的傳播模型,使得同一個事件會在多個節點上觸發

2) DOM0級事件與DOM2級事件綁定方式

  • xxx.onxxx = function(){};

    • DOM0級事件綁定方式,只有冒泡階段。若是事件綁定的是目標元素,就按照目標事件的前後順序依次綁定
  • xxx.addEventListener('xxx',function(){},false);

    第三個參數:

    • 爲false:是控制綁定的方法在事件傳播的冒泡階段(或者目標階段)執行;
    • 爲true:表明讓當前方法在事件傳播的捕獲階段觸發執行(這種捕獲階段

3) 事件對象的一些理解:

  • 1.事件對象是用來存儲當前本次操做的相關信息的,和操做有關,和元素無必然關聯。
  • 2.當咱們基於鼠標或者鍵盤等操做的時候,瀏覽器會把本次操做的信息存儲起來(標準瀏覽器存儲到默認的內存當中(本身找不到),IE低版本存儲到window.event中),存儲的值是一個對象(堆內存);操做會觸發元素的某個行爲,把綁定的方法執行,此時標準瀏覽器會把以前存儲的對象(內存地址)當作實參傳遞給每個執行的方法,因此操做一次,即便再多方法中都有ev,可是存儲的值都是一個(本次操做的信息對象)

4) 事件的傳播機制代碼演示

公共樣式:

<style>
#outer {
    position: absolute;
    top: 30px;
    left: 30px;
    width: 500px;
    height: 500px;
    background: red;
    cursor: pointer;
}

#center {
    position: absolute;
    top: 30px;
    left: 30px;
    width: 300px;
    height: 300px;
    background: pink;
    cursor: pointer;
}

#inner {
    position: absolute;
    top: 30px;
    left: 30px;
    width: 150px;
    height: 150px;
    background: #fff;
    cursor: pointer;
}
</style>

複製代碼
<div id="outer">
    <div id="center">
        <div id="inner">
            <button id="btn">按鈕</button>
        </div>
    </div>
</div>
複製代碼
let aa = null;
window.onclick = function(ev){
    console.log(ev === aa); //true
    alert('window')
}
outer.onclick = function(ev){
    console.log(ev === aa); //true
    alert('紅盒子')
}
center.onclick = function(ev){
    console.log(ev === aa); //true
    alert('粉盒子')
}
inner.onclick = function(ev){

    aa = ev;
    alert('白盒子')
}
btn.onclick = function(ev){
    ev = ev || window.event;
    ev.stopPropagation()?ev.stopPropagation():ev.cancelBubble = true;
    // 阻止冒泡傳播 ev.stopPropagation()低版本不兼容 ev.cancelBubble = true 全部瀏覽器都兼容
    alert('按鈕')
}
複製代碼

5) 事件的傳播機制練習題

//結構和樣式同上
function fn() { alert('btn1'); }
btn.addEventListener('click', fn, true);
outer.addEventListener('click',function(){alert('red');});
btn.addEventListener('click', fn, true);
inner.addEventListener('click', function () { alert('yellow'); }, true);
center.addEventListener('click', function () { alert('green'); });
btn.addEventListener('click', function () { alert('btn捕獲'); }, true);
btn.addEventListener('click', function () { alert('btn冒泡'); });
btn.addEventListener('click', fn, false);
// 答案:yellow btn1 btn捕獲 btn冒泡 btn1 green red
複製代碼

七。事件委託(事件代理)

  • 事件委託(事件代理):

利用事件冒泡傳播機制,若是一個容器的後代元素當中,不少元素的點擊行爲(其餘事件行爲也是)都要作一些處理,此時咱們不須要再像之前同樣一個個獲取一個個綁定,只須要給容器的click綁定方法便可,這樣無論點擊的是哪個後代元素,都會根據冒泡傳播機制把容器的click行爲觸發,把綁定的方法執行,根據事件源咱們能夠知道點擊的是誰,從而作不一樣的事情便可

  • ev.target: 事件源(操做的是哪一個元素),在嵌套關係中,給上層元素綁定事件,能夠經過事件源,查到事件觸發的對象(元素)
    • tagName: 'LI' 查看標籤名(大寫)

事件委託這種處理方式比一個個的事件綁定,性能上提升50%左右,並且須要操做的元素越多,性能提升越大

公共樣式:

<style>
ul {
    margin: 0 auto;
    width: 100px;
    border: 2px solid fuchsia;
}

li {
    width: 50px;
    height: 50px;
    border: 1px solid #000;
}
</style>
複製代碼
<ul id="ul">
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
</ul>
複製代碼
// 給全部li的上級元素ul綁定點擊事件,則其全部後代元素都會執行這個方法
ul.addEventListener('click',function(ev){
   ev.target.style.background = 'green'
})
複製代碼
// 點擊一個變色,點擊下一個變色,同時上一個取消變色
let lis = document.querySelectorAll('#ul>li')
ul.onclick = function (ev) {
    // console.log(ev.target.tagName); // 'LI'
    // ev.target.tagName 即當前點擊的標籤的標籤名(大寫)
    if (ev.target.tagName === 'LI') {
        for (let i = 0; i < lis.length; i++) {
            // 循環全部的li元素,若是當前循環的li元素不等於當前點擊的li元素,就把當前循環的li元素的背景顏色清空,若是當前循環的li元素等於當前點擊的元素,就把當前點擊的li元素加上顏色
            if (lis[i] !== ev.target) {
                lis[i].style.background = '';
            } else {
                ev.target.style.background = 'green';
            }
        }
    }
}
複製代碼

8、DOM0和DOM2的運行機制

DOM0: element.onxxx = function(){}

每個元素對象都是對應類的實例,瀏覽器天生爲其設置了不少私有屬性和公有的屬性方法,而onclick就是其中的一個私有屬性(事件相似私有屬性,還有不少其餘的事件私有屬性),這些屬性默認值是null

  • DOM0事件綁定原理:
    • 就是給元素的某一個事件私有屬性賦值(瀏覽器會創建監聽機制,當咱們觸發元素的某個行爲,瀏覽器會本身把屬性中賦的值去執行)

DOM2的事件池機制:

  • element.addEventListener('xxx', function(){}, false);
  • 移除事件的監聽函數: ele.removeEventListener('click', listener, false);
  • 使用的方法都是EventTarget.prototype上定義的
  • DOM2事件池: 當咱們觸發box的click行爲後,瀏覽器會到事件池中「按照順序」依次把以前監聽的方法執行
    • 1.每個被執行的方法,瀏覽器都會把事件對象傳遞給他
    • 2.方法中的this是當前操做的元素
    • 3.執行的方法不會出現重複,在向事件池增長的時候就去重了
  • 完整事件池機制:
    • DOM2事件綁定能夠給當前元素的某一個行爲綁定「多個不一樣的方法」

DOM0和DOM2事件綁定的區別:

  • 1.機制不同
    • DOM0採用的是給私有屬性賦值,因此只能綁定一個方法,DOM2採用的是事件池機制,因此能綁定多個不一樣的方法
  • 2.關於移除的操做
    • DOM0移除,將事件賦值爲null便可,不須要考慮綁定的是誰
    • DOM2移除,必須清楚要移除的是哪個方法,才能在事件池當中移除掉。因此基於DOM2作事件綁定,要有「瞻前顧後」的思路,也就是綁定的時候要考慮一下如何移除(不要綁定匿名函數)
  • 3.DOM2事件綁定中增長了一些DOM0沒法操做的事件行爲;例如:DOMContentLoaded事件(當頁面中的頁面中HTML結構加載完成就會觸發執行)
// DOM0事件綁定:只容許給當前元素的某個事件行爲綁定一個方法,屢次綁定,後面綁定的內容會替換前面綁定的,以最後一次綁定的方法爲主
box.onclick = function(){
    console.log(1)
}  
box.onclick = function(){
    console.log(2);// 觸發點擊行爲,只輸出2
}  
複製代碼
// DOM2事件綁定
function fn1(){console.log(1)}
function fn2(){console.log(2)}
function fn3(){console.log(3)}
function fn4(ev){
    console.log(4,this === box,ev.target)
    box.removeEventListener('click',fn5);
    box.removeEventListener('click',fn8);
}
function fn5(){console.log(5)}
function fn6(){console.log(6)}
function fn7(){console.log(7)}
function fn8(){console.log(8)}
function fn9(){console.log(9)}
function fn10(){console.log(10)}

box.addEventListener('click',fn1);
box.addEventListener('click',fn3);
box.addEventListener('click',fn5);
box.addEventListener('click',fn7);
box.addEventListener('click',fn9);
box.addEventListener('click',fn2);
box.addEventListener('click',fn2);//重複
box.addEventListener('click',fn2);//重複
box.addEventListener('mouseenter',fn2); //增長到事件池當中的
box.addEventListener('click',fn4);
box.addEventListener('click',fn6);
box.addEventListener('click',fn8);
box.addEventListener('click',fn10);
複製代碼

在上個例子中:

首先在事件未執行前,會把box的click的全部方法添加到一個數組裏面(即添加到事件池裏面),此時數組中有[fn1,fn3,fn5,fn7,fn9,fn2,fn4,fn6,fn8,fn10]

當第一次點擊box,會依次輸出1,3,5,7,9,2,4(此時移除了數組中的fn5和fn8方法),6,10

當第二次點擊box,會依次輸出1,3,7,9,2,4,6,10

let fn = function(){ }
box.addEventListener('DOMContentLoaded',fn); //能夠
box.onDOMContentLoaded = fn; //不能夠,box沒有這個屬性
複製代碼

9、鼠標跟隨

結構和樣式

<style>
#box {
    width: 100px;
    height: 100px;
    position: absolute;
    top: 0;
    left: 0;
    background: red;
}
body{
    height: 3000px;
}
</style>
複製代碼
<div id="box"></div>
複製代碼

js代碼

document.onmousemove = function (ev) {
    // console.log(ev.clientX);
    // console.log(ev.clientY);
    // 實現鼠標在盒子中間:ev.pageX: 鼠標離窗口左邊的距離 - 盒子寬度的一半 此時left:盒子左邊到瀏覽器左邊的距離
    let left = ev.pageX - box.clientWidth / 2;
    let top = ev.pageY - box.clientHeight / 2;

    if (left < 0) {
        left = 0;
    } 
    if (left > document.documentElement.clientWidth - box.clientWidth) {
        // document.documentElement.clientWidth - box.clientWidth 即盒子距離窗口左邊的最大距離(超過此最大距離,盒子就會溢出窗口)
        // 盒子到瀏覽器左邊的距離 > 最大距離,就讓盒子到瀏覽器左邊的距離 = 最大距離
        left = document.documentElement.clientWidth - box.clientWidth;
    }

    if (top < 0) { 
        top = 0;
    } else if (top > document.documentElement.clientHeight - box.clientHeight) {
        top = document.documentElement.clientHeight - box.clientHeight;
    }
    //讓盒子距窗口左邊/頂部的距離 = 鼠標離窗口左邊/頂部的距離
    box.style.left = left + 'px';
    box.style.top = top + 'px';
}
複製代碼

10、推箱子

結構和樣式

<style>
    #box {
        width: 100px;
        height: 100px;
        position: absolute;
        top: 0;
        left: 0;
        background: red;
    }
</style>
複製代碼
<div id="box"></div>
複製代碼

js代碼

num1 = 0;
num2 = 0
let timer = null;
document.addEventListener('keydown', function move(ev) {
    clearInterval(timer);
    timer = setInterval(() => {
        switch (ev.keyCode) {
            case 39:
                num1 += 10;
                // box.style.left = num1 + 'px';
                break;
            case 40:
                num2 += 10;
                // box.style.top = num2 + 'px';
                break;
            case 37:
                num1 -= 10;
                // box.style.left = num1 + 'px';
                break;
            case 38:
                num2 -= 10;
                // box.style.top = num2 + 'px';
                break;
        }
        num1 < 0 ? num1 = 0 : null;
        box.style.left = num1 + 'px';
        num2 < 0 ? num2 = 0 : null;
        box.style.top = num2 + 'px';
    }, 22)
});
document.addEventListener('keyup',function(){
    clearInterval(timer)
})

複製代碼
相關文章
相關標籤/搜索