今天做了個手機頁面,點擊某個按鈕->彈出菜單,再點擊菜單以外的任意位置->關閉菜單,在其他瀏覽器里面沒有問題,但是在IOS瀏覽器中並不會關閉。
網上解決這個bug的帖子很多,這篇帖子主要是講原理,這里寫個簡單的代碼,大家可以復制到自己頁面中去實驗:
<html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no"/> </head> <script src="https://code.jquery.com/jquery-3.1.0.min.js"></script> <style> *{min-height:100px; line-height:100px;} body{ background:#ddd;} a,input{display:block;} div{background:#9CF;} </style> <body> <a href="#" >鏈接</a> <input type="button" value="按鈕"/> <div>div或span等</div> </body> </html> <script> $("body").bind("click",function(){ alert("body 被點擊") }) </script>
上面這段代碼在其他瀏覽器里面沒有問題,在IOS的瀏覽器中,點擊鏈接和按鈕都會有彈窗,但是點擊其他區域卻沒有。
原因是因為IOS瀏覽器的按鈕和鏈接才響應click事件,其他標簽不響應,所以點擊鏈接和按鈕之外的其他地方並不會把click事件冒泡到body上。
我們做一個比喻來理解這個事件是怎么運作的:
屏幕被點擊后,系統會發送一個事件公告(click),鏈接和按鈕收到這個公告后會處理相應的行為(比如打開個新頁面,提交表單,用戶綁定的其他行為)
window、document、body、div並不會搭理這個公告,跟沒看到似的,自然也就沒有彈窗出現
body只接受內部的冒泡事件,點擊按鈕后觸發了按鈕的click事件,然后按鈕會告訴自己的上級(body):老大,我被點擊了,
body會說:好的,我會處理的,這時候彈窗就出來了。
body里面的div,span等標簽默認是不會理睬click事件公告的,但是我們可以開啟他,開啟后他們就跟按鈕一樣,可以接受click事件,並匯報給上級。
開啟方法:給標簽綁定一個任意事件↓
1.HTML標簽中添加事件屬性
<div onMouseOver>div或span等</div> <div onClick>div或span等</div> <div onKeyDown>div或span等</div>
2.用js或者jquery綁定一個事件
$("body div").bind("click",function(){})
所以最后我們的彈出菜單可以這樣寫
/*給body里面的任意元素綁定事件,讓這些標簽能接受click事件*/
$("body>*").bind("click",function(){});
$("#button").bind("click",function(e){/*給按鈕綁定點擊事件*/
$("#menu").show();//按鈕點擊后顯示菜單
$("body").one("click",function(){/*菜單顯示后:給body綁定點擊事件,執行一次后自動刪除這個綁定*/
$("#menu").hide();//body收到click事件后關閉菜單
});
e.stopPropagation();//停止冒泡,按鈕被點擊后不告訴body,因為click事件如果冒泡到body會關閉菜單。
})
$("#menu").bind("click",function(e){/*給菜單綁定點擊事件*/
e.stopPropagation();//停止冒泡,菜單被點擊后不告訴body,不然菜單要被關閉
})