又到周末了,我們一起來研究【瀏覽器如何檢測是否安裝app】吧


前言

扯淡

這個月比較倒霉,我送了女朋友一台筆記本電腦作為生日禮物,結果15天一過電腦就壞了,悲劇的我還把電腦盒子給扔了!淘寶不給換更不給退

於是被女朋友臭罵了一過星期后,今天本來在公司有任務的,但是去修了個電腦(換主板啊......),一蹉跎就快五點了,現在反正干勁也不行,就寫篇博客吧

需求

上周五的時候,確切說是周四晚上,老板終於又遞上了一個神奇的需求

瀏覽器檢測手機是否安裝app

尼瑪,反正在我看來,這個需求夠奇葩的,當時我還一致認為不能完成,但是最后也居然想出了(抄出了)一個辦法,於是這里拿出來與各位分享下

在此之前,我們繼續聊下上次遇到的tap點透問題

tap“點透”再探索

http://www.cnblogs.com/yexiaochai/p/3377900.html

http://www.cnblogs.com/yexiaochai/p/3391015.html

看過上面兩篇博客的的朋友應該知道我們為什么要使用tap事件替換click事件,然后大概知道tap會帶來哪些問題,以及我是如何解決這些問題的

雖然完整解決方案因為公司財產問題未拿出來,但是基本思路是有了,其核心就是蒙版遮蓋!

話說還頭,這個蒙版其實還是不太能讓人接受,這不我又請教了我一個同事,我們同事提出了一個屬性:

pointer-events屬性值詳解

  • auto——效果和沒有定義pointer-events屬性相同,鼠標不會穿透當前層。在SVG中,該值和visiblePainted的效果相同。
  • none——元素不再是鼠標事件的目標,鼠標不再監聽當前層而去監聽下面的層中的元素。但是如果它的子元素設置了pointer-events為其它值,比如auto,鼠標還是會監聽這個子元素的。
  • 其它屬性值為SVG專用,這里不再多介紹了。

這個屬性,通過前端觀察/和張鑫旭的博客再深入了解一番過后發現,這個家伙可以消除一個元素的鼠標事件呢!!!自然也包括touchstart了,於是老夫感興趣了,便有了今天這個插曲

是否繼承

我們首先來看看這個屬性是否會被繼承:

http://sandbox.runjs.cn/show/teegz43u

 1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 2 <html xmlns="http://www.w3.org/1999/xhtml">
 3 <head>
 4     <title></title>
 5     <meta name="viewport" content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
 6     <meta content="telephone=no" name="format-detection" />
 7     <meta name="apple-mobile-web-app-capable" content="yes" />
 8     <style>
 9         div { display: block; border: 1px solid black;  margin: 10px; padding: 10px; }
10     </style>
11     <script id="others_zepto_10rc1" type="text/javascript" class="library" src="/js/sandbox/other/zepto.min.js"></script>
12     
13 </head>
14 <body>
15 
16     <div id="p1">
17         p1
18         <div id="p1-1">
19             p1-1
20             <div id="p1-1-1">
21                 p1-1-1
22             </div>
23              <div id="p1-1-2">
24                 p1-1-2
25             </div>
26         </div>
27     </div>
28 
29      <div id="p2">
30         p2
31         <div id="p2-1">
32             2-1
33             <div id="p2-1-1">
34                 p2-1-1
35             </div>
36              <div id="p2-1-2">
37                 p2-1-2
38             </div>
39         </div>
40     </div>
41 
42 </body>
43 <script type="text/javascript">
44     $('div').click(function () {
45         alert($(this).attr('id'))
46 
47     })
48 </script>
49 </html>

首先,現在鼠標點擊會有一個冒泡的過程,所以會一次彈出提示框,現在我們將下面的p2的style加上我們的pointer-events屬性試試點擊是否有效果

結果表明,設置了pointer-events: none; 后,該元素以及下面的元素的click事件全部沒有了

甚至是我們的input框都不會獲取焦點了!!!,所以這個家伙確實夠厲害,但是不會取消事件冒泡

有了這個結論,我們上我們的重量級代碼吧,這個代碼請各位用手機測試

屬性解決點透

 

 1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 2 <html xmlns="http://www.w3.org/1999/xhtml">
 3 <head>
 4     <title></title>
 5     <meta name="viewport" content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
 6     <meta content="telephone=no" name="format-detection" />
 7     <meta name="apple-mobile-web-app-capable" content="yes" />
 8     <style>
 9         #list { display: block; position: absolute; top: 100px; left: 10px; width: 200px; height: 100px; }
10         div { display: block; border: 1px solid black; height: 500px; width: 100%; }
11         #input { width: 80px; height: 200px; display: block; }
12     </style>
13     <script id="others_zepto_10rc1" type="text/javascript" class="library" src="/js/sandbox/other/zepto.min.js"></script>
14 </head>
15 <body>
16     <div id="list" style="background: gray;">
17     </div>
18     <div id="wrapper">
19         <div id="d">
20             <input type="text" id="input" />
21         </div>
22     </div>
23 </body>
24 <script type="text/javascript">
25     var list = $('#list');
26     var d = $('#d');
27     var input = $('#input');
28     input.tap(function (e) {
29         input.val(new Date().getTime());
30     });
31     list.tap(function (e) {
32         //        $('input').css("pointer-events", "none");
33         list.hide();
34         setTimeout(function () {
35             list.show();
36             //            $('input').css("pointer-events", "auto");
37         }, 1000);
38     });
39     d.tap(function () {
40         d.append($('<p>div tap</p>'));
41     });
42     
43 </script>
44 </html>

 

http://sandbox.runjs.cn/show/wub3i7fr

這里各位請使用手機訪問試試,現在這個網頁有幾個問題:

我點擊灰色區域會將灰色區域隱藏,灰色區域消失,一秒后重現,於是可能發生兩個問題:

① 某些瀏覽器中后面的div tap事件會觸發

② input元素必定獲得焦點

div事件有些時候我們可以通過阻止冒泡處理,但是input這個問題基本不可調和,因為其獲得焦點彈出鍵盤十分惱火

元素我們是通過一個蒙版解決,先我們來看看是否可以給我們的容器wrapper加上一個css屬性解決呢???

 1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 2 <html xmlns="http://www.w3.org/1999/xhtml">
 3 <head>
 4     <title></title>
 5     <meta name="viewport" content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
 6     <meta content="telephone=no" name="format-detection" />
 7     <meta name="apple-mobile-web-app-capable" content="yes" />
 8     <style>
 9         #list { display: block; position: absolute; top: 100px; left: 10px; width: 200px; height: 100px; }
10         div { display: block; border: 1px solid black; height: 500px; width: 100%; }
11         #input { width: 80px; height: 200px; display: block; }
12     </style>
13     <script id="others_zepto_10rc1" type="text/javascript" class="library" src="/js/sandbox/other/zepto.min.js"></script>
14 </head>
15 <body>
16     <div id="list" style="background: gray;">
17     </div>
18     <div id="wrapper">
19         <div id="d">
20             <input type="text" id="input" />
21         </div>
22     </div>
23 </body>
24 <script type="text/javascript">
25     var list = $('#list');
26     var d = $('#d');
27     var input = $('#input');
28     input.tap(function (e) {
29         input.val(new Date().getTime());
30     });
31     list.tap(function (e) {
32         $('#wrapper').css("pointer-events", "none");
33         list.hide();
34         setTimeout(function () {
35             $('#wrapper').css("pointer-events", "auto");
36         }, 350)
37         setTimeout(function () {
38             list.show();
39         }, 1000);
40     });
41     d.tap(function () {
42         d.append($('<p>div tap</p>'));
43     });
44     
45 </script>
46 </html>

http://sandbox.runjs.cn/show/1wldtigt

可以看到,我們解決了點透的問題,所以有我有這些厲害的同事是很幸運的,有了這個方案,我們就可以在zepto中封裝我們的代碼了

在tap點擊后為容器標簽設置該屬性,350ms后取消即可,這樣可以最大程度的包裝代碼不會修改

但是這個方案不是沒有問題:

最重要的是他依然有個時間閥值,經過我測試時350ms,意思是我使用tap事件后會有350ms的事件某些區域完全無法點擊

那么容器所占區域小的話還可接受,如果所占區域大的話就是噩夢,因為用戶的點擊明顯會出現阻力

然后,畢竟會點透的情況不是多數,所以此方案仍有缺陷,最后還是得動一些其它力氣

后續

這次tap的研究先到這里,我們我們有機會再繼續,所以回到我們今天的主題吧!!!

瀏覽器檢測手機是否安裝app

這個需求初次提出其實讓人感覺很為難,至少我是很為難的,因為壓根就找不到辦法嘛,經過周四晚上的糾結,基本就放棄了

第二天也給老大說搞不定,老大基本也仍為搞不定,但是這個需求是最大的老大提出的,所以跟進力度很強,這不是,過了沒多久就來了個vip(代表級別高......)

哥來了就寄出了法寶,先是一個國外的網站,然后就是我們傳說中的淘寶了

PS:說實話,雖然電腦的事情與淘寶無關,但是老夫現在對淘寶還是比較怨念的!!!!

淘寶不愧是業內技術領先的技術團隊,我們來看看他的網站:

其它不必關注,我們就看這個“立即打開”!!!各位知道手機上這個立即打開干了什么嗎?

這個家伙不得了,如果按照了app 的話點擊立即打開就會打開app,如果沒有按照的話居然跳向了市場連接

在某些時候這個對等與他有一個a標簽會根據需求而獲得不同的值!!!

但是,我們知道打開app是安裝了app才會打開的,不然就是個死鏈接,死鏈接必然打不開!於是帶着好奇帶着敬畏,我們打開了淘寶的js庫

PS:淘寶壓縮混淆后js確實很小,而且沒有使用類庫哦

 

各位看官直接找到這個目錄吧,於是進去我們一步步跟進去:

① 點擊點

雖然小生本領不行,但是讀代碼還是入門的,所以國內一旦出了什么心技術,基本很快就能普及,這就是國內的技術,不是做不出來,就是不知道做出了是什么樣子

一旦你做出了,那么我也能做出了,並且做的更好,所以我們缺乏創新啊......

我們找到了入口,於是進入install方法

② install

這群代碼一目了然,讀到這里,其實可以很輕易的猜測實現方案了!

③ 猜測實現方案

於是我就開始猜測,猜測的結果就是:

如果安裝app 的情況下,打開鏈接會讓window失去焦點,於是清除了計時器
如果沒有安裝app計時器里面的代碼會執行,所以跳向了app市場

當然,最后發現一個問題:手機上網頁無法失去焦點,這只是我自己的判斷(無法失去焦點),所以最后也放棄了這個猜測

④ 陷入僵局

於是思路再次陷入僵局,任務不能實現,但是將淘寶代碼搞下來,也無法實現,最后就開始以各種漫無目的,垃圾的辦法搞,終於不注意成功了一次!!!

無意義的成功是因為將定時器設置的很大......

⑤ 解決方案

最后發現了方案,安裝app 的情況下,網頁會進入后台打開app!!!

網頁進入后台后會掛起js 的執行,但是這個期間有600-1000ms的時間js仍然會執行

淘寶執行的閥值是600,我們大概是900,所以一直在原地踏步了很久

這個網頁進入后台卻成了解決問題的關鍵,於是新鮮代碼出來了:

 1 var log = function (msg) {
 2     $('body').before('<div class="log">' + msg + '</div>');
 3 };
 4 var timeout, t = 1000, hasApp = true;
 5 setTimeout(function () {
 6     if (hasApp) {
 7         log('安裝了app');
 8         $('#dl_app').hide();
 9 
10     } else {
11         log('未安裝app');
12         $('#dl_app').show();
13         log('開始強制下載');
14         forceDownload();
15     }
16 }, 2000)
17 function testApp() {
18     var t1 = Date.now();
19     var ifr = $('<iframe id="ifr"></iframe>')
20     ifr.attr('src', '您們app的協議');
21     $('body').append(ifr);
22     timeout = setTimeout(function () {
23         try_to_open_app(t1);
24     }, t);
25 }
26 function try_to_open_app(t1) {
27     var t2 = Date.now();
28     if (!t1 || t2 - t1 < t + 200) {
29         hasApp = false;
30     }
31 }
32 testApp();

將這段代碼加入網站首頁1-2秒后hasApp就會告訴我們是否安裝了app,當然問題也很明顯:

缺陷

① 經測試,如果未安裝app的情況下,safari會給出一個alert類似的提示,老夫將它去不掉!!!

PS:如果各位知道怎么去掉,請賜教

② 進入H5站點,如果安裝了app便會打開app,這個是無法避免的

除了上面兩個較明顯的缺陷,其它還好了......

結語

我們今天的學習暫時到此,也不知道對各位有沒有用


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM