關於js中e.preventDefault()的具體使用

背景:

同事在項目中遇到的問題,在項目中導入瞭某一個組件作為根組件之後,發現原來的子組件中的滾動效果不再生效,因為是移動端的項目,所以這裡的滾動效果是通過touchmove事件進行觸發的,在對引入的組件進行研究後,發現是在根組件中阻止瞭touchmove事件的默認事件,也就是調用瞭e.preventDefault()方法,然後同事們通過阻止冒泡阻止瞭這個方法的調用,解決掉瞭因為引入組件而帶來的問題,但這卻引發瞭一連串的有關於preventDefault()這個方法的思考。

問題:

為什麼我在父組件上使用preventDefault(),阻止默認事件會導致我的子組件的默認事件失效?

分析:

首先,我們看官網對event.preventDefault()這一方法的解釋,在繁體中文版的MDN網站中,隻是簡單的提到瞭取消事件的預設行為,而不影響事件的傳遞。如字面意思,很好理解。

而在簡體中文版的MDN網站中,對於此事件描述的文字對比繁體版較多

在這裡提到一個詞,叫顯示處理,不是很能理解這個詞。繁體版與簡體版的比較對應下來,也能夠說的過去,所以這裡並不能解決我們的疑問,到底為什麼在父元素上調用瞭這個方法阻止默認事件,子元素的默認事件也消失瞭?

持續跟進:

翻遍瞭百度,我沒有找到有關於這個問題的解答,莫得辦法瞭,隻有自己去試著找一些結論性的東西。

嘗試:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        #box{
            height: 300px;
            overflow: auto;
            width:200px;
            padding: 40px;
            margin: 0 auto;
            background: grey;
        }
        #gdfather{
            position: relative;
            height: 600px;
            overflow: auto;
            width:400px;
            margin: 40px;
            background: rgba(0, 255, 255, 0.219);
        }
        #father{
            position: absolute;
            top: 20px;
            height: 200px;
            overflow: auto;
            width: 600px;
            margin: 40px;
            background-color: rgba(128, 128, 128, 0.349);
        }
        #son{
            position: absolute;
            top: 20px;
            height: 1400px;
            width: 800px;
            margin: 40px;
            background-color: rgba(205, 92, 92, 0.26);
        }
        #box2{
            display: flex;
            justify-content: center;
            align-items: center;
            flex-direction: column;
            height:200px;
            width: 200px;
            background-color: khaki;
        }
    </style>
</head>
<body>
    <div id='box'>
        <div id='gdfather'>
            <p>祖先中的內容</p>
            <p>祖先中的內容</p>
            <p>祖先中的內容</p>
            <p>祖先中的內容</p>
            <p>祖先中的內容</p>
            <p>祖先中的內容</p>
            <p>祖先中的內容</p>
            <p>祖先中的內容</p>
            <p>祖先中的內容</p>
            <div id='father'>
                <p>父親中的內容</p>
                <p>父親中的內容</p>
                <p>父親中的內容</p>
                <p>父親中的內容</p>
                <p>父親中的內容</p>
                <p>父親中的內容</p>
                <p>父親中的內容</p>
                <p>父親中的內容</p>
                <p>父親中的內容</p>
                <div id='son'>
                    <p>兒子中的內容</p>
                    <p>兒子中的內容</p>
                    <p>兒子中的內容</p>
                    <p>兒子中的內容</p>
                    <p>兒子中的內容</p>
                    <p>兒子中的內容</p>
                    <p>兒子中的內容</p>
                    <p>兒子中的內容</p>
                    <p>兒子中的內容</p>
                </div>
            </div>
        </div>
    </div>
    <div id='box2'>
        <input id="ipt" type="text">
        <div id='inbox'>
            <input id='inIpt' type="text">
        </div>
    </div>
    <script>
        let gdfather=document.getElementById('gdfather')
        let father=document.getElementById('father')
        let son=document.getElementById('son')
        gdfather.addEventListener('touchmove',(e)=>{
            // console.log('gdfather')
            // e.preventDefault()
        })
        father.addEventListener('touchmove',(e)=>{
            // console.log('father')
            console.log(e.preventDefault.toString())
            console.log(e)
        })
        let box2=document.getElementById('box2')
        let inbox=document.getElementById('inbox')
        let ipt=document.getElementById('ipt')
        let inIpt=document.getElementById('inIpt')
        let events
        box2.addEventListener('keydown',(e)=>{
            // e.preventDefault()
            console.log(e===events)
        })
        ipt.addEventListener('keydown', (e)=>{
            console.log(e===events)
            console.log(JSON.stringify(e)===JSON.stringify(events))
            events=e
        })

        inIpt.addEventListener('keydown', (e)=>{
            // e.preventDefault()
            events.preventDefault()
            console.log(events)
        })
    </script>
</body>
</html>

總結

元素並不擁有事件,實際上,元素隻是對事件進行瞭一個監聽。就比如一個人進行一場馬拉松比賽,這個人進行比賽的這個過程,就是事件從誕生到結束的整個過程。而在比賽的途中,我們設置瞭一些裡程點,每一場馬拉松比賽都會在裡程點設置對應的補給,我們規定每到達一個補給點就會進行補給,這個可以看作事件的默認行為。當事件每到達一個裡程點時,我們可以在這個裡程點做一些事,比如歡呼之類的(也就是設置事件監聽),也可以啥都不做。這個裡程點就是元素,而歡呼就是元素在監聽到這個事件時我們設置的行為。

實際上,即使是同一個事件,所擁有的event也是不同的,這個在上面的118和119行可以進行證明,而同一類型的事件在觸發時隻會擁有這一個event,這一點通過118和115可以證明,對應到馬拉松就是每一次馬拉松都是不同的,而一條路線上隻可能進行一場馬拉松比賽。當我們阻止事件冒泡時,相當於我們在跑到23公裡時,放棄瞭這場比賽,那麼在32公裡處等著為我們歡呼的人就永遠不會觸發這個動作。而我們在使用event.preventDefault()這個方法時,相當於我們撤掉瞭所有的裡程點的補給,自然也就沒有瞭默認行為,但我們還在跑,原來在32公裡處為我們歡呼的人依舊會為我們歡呼。

在通過上面的分析後,已經可以很好的理解為什麼在父組件中使用瞭preventDefault(),而子組件也沒有默認行為瞭,因為所有的補給都被撤掉瞭。即在這一條線上所有的默認行為都沒有瞭。

e.preventDefault()與return false的區別

事件處理函數的返回值(return false)隻對通過屬性註冊的處理函數才有意義;
也就是說如果我們不是通過addEventListener()函數來綁定事件的話,那麼要禁止默認事件的話,用的就是return false;

如果使用addEventListener()或者attachEvent()函數來綁定的話,就要使用e.preventDefault()方法或者設置事件對象的returnValue屬性來阻止默認事件。

到此這篇關於關於js中e.preventDefault()的具體使用的文章就介紹到這瞭,更多相關js e.preventDefault()內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: