原生andriod瀏覽器回退後dom(click)事件全體失效問題探究

問題描述

 

今天同事遇到一個神一樣的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   <p id="ttt">

10     ttt</p>

11   <br />

12   <a href="https://www.baidu.com" name="n">百度一下</a>  

13   <script type="text/javascript">

14       var i = 0;

15       var appendDiv = function (msg) {

16           var p = document.createElement('p');

17           if (msg) {

18               p.innerHTML = msg;

19           } else {

20               p.innerHTML = i++;

21           }

22           document.body.appendChild(p);

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   <p id="ttt">

10     ttt</p>

11   <br />

12   <a href="https://www.baidu.com" name="n">百度一下</a> dsfsdffd<br>

13   <script type="text/javascript">

14       var i = 0;

15       

16       setInterval(function () {

17           var p = document.createElement('p');

18           p.innerHTML = i++;

19           document.body.appendChild(p);

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 p = document.createElement('p');

29           if (msg) {

30               p.innerHTML = msg;

31           } else {

32               p.innerHTML = i++;

33           }

34           document.body.appendChild(p);

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   <p id="ttt">

10     ttt</p>

11   <br />

12   <a href="https://www.baidu.com" name="n">百度一下</a> dsfsdffd<br>

13   <script type="text/javascript">

14       var i = 0;

15       

16       setInterval(function () {

17           var p = document.createElement('p');

18           p.innerHTML = i++;

19           document.body.appendChild(p);

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 p = document.createElement('p');

29           if (msg) {

30               p.innerHTML = msg;

31           } else {

32               p.innerHTML = i++;

33           }

34           document.body.appendChild(p);

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   <p id="ttt">

10     ttt</p>

11   <br />

12   <a href="https://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 p = document.createElement('p');

18           p.innerHTML = i++;

19           document.body.appendChild(p);

20       }, 1000);

21       var appendDiv = function (msg) {

22           var p = document.createElement('p');

23           if (msg) {

24               p.innerHTML = msg;

25           } else {

26               p.innerHTML = i++;

27           }

28           document.body.appendChild(p);

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');

他的映射關系又建立起來瞭,如果是這樣的話,是說的過去的!!!

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *