問題描述
今天同事遇到一個神一樣的BUG:
在原生浏覽器下,為dom元素綁定一個click事件,其中有個a標簽外鏈,點擊a後進入其他頁面,點擊浏覽器後退後,頁面點擊事件全體失效!
我於是用ios測了下沒事,用andriod其他浏覽器試了下也沒事,就是原生的有問題,懷疑是特定的手機有問題,又陸續換了幾台,發現原生的都有問題
於是便開始找解決方案,下面就來聊下今天的漫長之路,這裡先給會出問題的代碼:
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8" />
5 <title></title>
6 <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
7 </head>
8 <body>
9 <div id="ttt">
10 ttt</div>
11 <br />
12 <a href="http://www.baidu.com" name="n">百度一下</a>
13 <script type="text/javascript">
14 var i = 0;
15 var appendDiv = function (msg) {
16 var div = document.createElement('div');
17 if (msg) {
18 div.innerHTML = msg;
19 } else {
20 div.innerHTML = i++;
21 }
22 document.body.appendChild(div);
23 };
24 document.addEventListener('click', function (e) {
25 appendDiv('click')
26 });
27 </script>
28 </body>
29 </html>
DOM事件丟失
第一步想到的當然是事件丟失了,或者就是不執行了,於是乎寫了一段代碼:
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8" />
5 <title></title>
6 <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
7 </head>
8 <body>
9 <div id="ttt">
10 ttt</div>
11 <br />
12 <a href="http://www.baidu.com" name="n">百度一下</a> dsfsdffd<br>
13 <script type="text/javascript">
14 var i = 0;
15
16 setInterval(function () {
17 var div = document.createElement('div');
18 div.innerHTML = i++;
19 document.body.appendChild(div);
20
21 var type = 'click'; //要觸發的事件類型
22 var event = document.createEvent('MouseEvents');
23 event.initMouseEvent(type);
24 document.dispatchEvent(event);
25
26 }, 1000);
27 var appendDiv = function (msg) {
28 var div = document.createElement('div');
29 if (msg) {
30 div.innerHTML = msg;
31 } else {
32 div.innerHTML = i++;
33 }
34 document.body.appendChild(div);
35 };
36 document.addEventListener('click', function (e) {
37 appendDiv('click')
38 });
39 </script>
40 </body>
41 </html>
我定時器不停地向浏覽器打印數字,而且觸發document的click事件,他工作的蠻好的,但是當我點擊百度一下再回來時候,便不執行了
因為我們沒法在代碼層面上獲取dom的事件信息,所以暫時只能這樣做,而我的判斷是,沒錯!dom事件丟失了
Window事件未丟失
然後我又在這上面糾纏了好久,想試試windows的事件是否丟失,於是寫下了以下代碼:
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8" />
5 <title></title>
6 <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
7 </head>
8 <body>
9 <div id="ttt">
10 ttt</div>
11 <br />
12 <a href="http://www.baidu.com" name="n">百度一下</a> dsfsdffd<br>
13 <script type="text/javascript">
14 var i = 0;
15
16 setInterval(function () {
17 var div = document.createElement('div');
18 div.innerHTML = i++;
19 document.body.appendChild(div);
20
21 var type = 'click'; //要觸發的事件類型
22 var event = document.createEvent('MouseEvents');
23 event.initMouseEvent(type);
24 document.dispatchEvent(event);
25
26 }, 1000);
27 var appendDiv = function (msg) {
28 var div = document.createElement('div');
29 if (msg) {
30 div.innerHTML = msg;
31 } else {
32 div.innerHTML = i++;
33 }
34 document.body.appendChild(div);
35 };
36 document.addEventListener('click', function (e) {
37 appendDiv('click')
38 });
39
40 window.onresize = function () {
41 appendDiv('onresize')
42 }
43 </script>
44 </body>
45 </html>
我點擊回來後,發現事件還在,於是陷入深深的沉思.沉思.沉思.思.思.思.............
問題解決
最後我無意間將這個問題解決了,而且解決的方案匪夷所思:
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8" />
5 <title></title>
6 <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
7 </head>
8 <body>
9 <div id="ttt">
10 ttt</div>
11 <br />
12 <a href="http://www.baidu.com" name="n">百度一下</a> dsfsdffd<br>
13 <script type="text/javascript">
14 var t = document.getElementById('ttt');
15 var i = 0;
16 setInterval(function () {
17 var div = document.createElement('div');
18 div.innerHTML = i++;
19 document.body.appendChild(div);
20 }, 1000);
21 var appendDiv = function (msg) {
22 var div = document.createElement('div');
23 if (msg) {
24 div.innerHTML = msg;
25 } else {
26 div.innerHTML = i++;
27 }
28 document.body.appendChild(div);
29 };
30 document.addEventListener('click', function (e) {
31 appendDiv('click')
32 });
33 </script>
34 </body>
35 </html>
整個解決方案耗費我兩個多小時,而最終卻是這麼一段不起眼的代碼:
var t = document.getElementById('ttt');
// var btnfree = document.getElementsByTagName('a'); 無效
// var n = document.getElementsByName('name');無效
現在問題是解決了,我卻更疑惑了,一個大大的問號在我腦裡回旋不去,尼瑪在玩我啊......這是為什麼??????
問題原理猜想
注意,此處完全是扯淡時間
andriod硬件加速
andriod原生浏覽器本身使用了硬件加速功能,或者說andriod對自身的浏覽器做了很好的處理
我們在頁面上看到的頁面具有一個dom樹,而我們的事件js保存在另一個地方,而此時硬件加速為我們提供了一個類似png的中間件
他負責了通訊,但是在我們該網頁轉入後台時,這之間的映射關系卻被破壞了
而我們js代碼中若是多了這麼一段代碼:
var t = document.getElementById('ttt');
他的映射關系又建立起來了,如果是這樣的話,是說的過去的!!!