Ứng dụng iPhone Safari Web mở các liên kết trong cửa sổ mới


155

Tôi gặp sự cố với web sau khi thêm biểu tượng vào Màn hình chính. Nếu web được khởi chạy từ Màn hình chính, tất cả các liên kết sẽ mở trong cửa sổ mới trong Safari (và mất chức năng toàn màn hình). Làm thế nào tôi có thể ngăn chặn nó? Tôi không thể tìm thấy bất kỳ trợ giúp, chỉ có câu hỏi chưa được trả lời.


3
Bây giờ bạn có thể sử dụng scopetham số trong manifest.json. Xem câu trả lời của tôi để biết thêm chi tiết. Tôi đã thử nghiệm nó trong iOS 11.3 và nó hoạt động.
Amir Raminfar

3
Để nhắc lại, đối với bất kỳ ai đang vật lộn với Safari mở iOS 11.3, vui lòng xem câu trả lời của @ AmirRaminfar tại đây: stackoverflow.com/a/49604315/32055
Chris Haines

Câu trả lời:


110

Tôi đã tìm thấy giải pháp JavaScript trong khung iWebKit :

var a=document.getElementsByTagName("a");
for(var i=0;i<a.length;i++)
{
    a[i].onclick=function()
    {
        window.location=this.getAttribute("href");
        return false
    }
}

25
Để nói rõ và làm rõ điều này: iOS coi các liên kết trong Ứng dụng web là thứ gì đó nên được mở trong Safari và thay đổi vị trí javascript dưới dạng một hành động trong ứng dụng được phép châm biếm trong ứng dụng web. Đoạn mã trên hoạt động vì nó ngăn chặn hành vi liên kết mặc định, thay thế nó bằng một cuộc gọi điều hướng js.
Oskar Austegard

6
Có một ví dụ về điều ngược lại? Buộc một ứng dụng web iPhone mở một trang trong Safari mặc dù đó là thay đổi vị trí javascript?
tkahn

1
@Pavel cảm ơn bạn đã nhắc đến iwebkit :). Giúp nhận được một số lưu lượng truy cập: D
cmplieger

3
[].forEach.call(document.links, function(link) { link.addEventListener("click", function(event) { event.preventDefault(); window.location = this.href; }) });
alex

1
Điều này có bất kỳ tác dụng phụ?
pingu

94

Các giải pháp khác ở đây không chiếm tài khoản cho các liên kết bên ngoài (mà bạn có thể muốn mở bên ngoài trong Safari) hoặc không tính đến các liên kết tương đối (không có tên miền trong đó).

Dự án nồi hơi di động html5 liên kết đến ý chính này có một cuộc thảo luận tốt về chủ đề này: https://gist.github.com/1042026

Đây là mã cuối cùng họ nghĩ ra:

<script>(function(a,b,c){if(c in b&&b[c]){var d,e=a.location,f=/^(a|html)$/i;a.addEventListener("click",function(a){d=a.target;while(!f.test(d.nodeName))d=d.parentNode;"href"in d&&(d.href.indexOf("http")||~d.href.indexOf(e.host))&&(a.preventDefault(),e.href=d.href)},!1)}})(document,window.navigator,"standalone")</script>

Điều này hoạt động rất tốt ngoại trừ một trang, trang "Liên hệ với chúng tôi" cho công ty chúng tôi. Thay vì hiển thị trang, nó sẽ mở ứng dụng "Bản đồ" và xác định chính xác văn phòng của chúng tôi. Điều gì có thể gây ra điều này, và làm thế nào chúng ta có thể khắc phục nó?
Jonathan

@Jonathan Tôi không chắc. Nó không xảy ra nếu bạn loại bỏ tập lệnh này? Có thể gửi một liên kết đến trang web của bạn? Hoặc mở một câu hỏi mới, điều đó có thể tốt hơn.
rmarscher

@rmarscher Điều này chỉ xảy ra khi chạy mã bạn cung cấp và không phải không có nó. Bản thân tôi là một nhà phát triển web và tôi không hiểu tại sao nó lại xử lý liên kết theo cách này. Tôi không có URL trang vì hiện tại nó không chạy mã nên bạn sẽ không chú ý đến nó. Ngoài ra, nó cũng ảnh hưởng đến Safari thông thường và không chỉ độc lập. Cảm ơn câu trả lời của bạn!
Jonathan

Đây phải là câu trả lời được chấp nhận và làm say mê ứng dụng khách toàn màn hình iPad1 của tôi được tạo bằng PHPRunner bằng cách đặt mã trong tiêu đề. Không chắc tại sao nó lại bị xáo trộn như vậy vì nó có vẻ như một đoạn mã khá ngắn gọn có thể được viết một cách rõ ràng mà không cần nhiều chi phí BW ... điều đó chỉ là rất kén chọn và nói chung thực sự muốn nói lời cảm ơn.
sradforth

4
Điều này phá vỡ các thứ Bootstrappy như các liên kết href = "#" được sử dụng bởi các hàm js
Sean

47

Nếu bạn đang sử dụng jQuery, bạn có thể làm:

$("a").click(function (event) {
    event.preventDefault();
    window.location = $(this).attr("href");
});

1
Hãy giải thích tại sao .live () có thể tốt hơn?
ajcw

8
trực tiếp sẽ liên kết sự kiện với tất cả các liên kết bao gồm cả các liên kết chưa tồn tại, nhấp sẽ chỉ liên kết với các liên kết hiện đang tồn tại
msaspence

cảm ơn! phao cứu sinh. Tôi chỉ mất hàng giờ để cố gắng tìm ra lý do tại sao safari luôn tải.
Steve

1
+1 từ tôi - được sử dụng this.hrefthay vì truyền vào đối tượng jQuery, nhưng cảm ơn vì câu trả lời này. Hoạt động trên iOS6.
Fenton

17
.live () không được dùng nữa trong jQuery 1.7bị xóa kể từ 1.9 . Sử dụng $ (tài liệu) .on ('nhấp', 'a', function () {...}) để thay thế.
Tom Davies

21

Điều này hoạt động với tôi trên iOS 6.1 và với các liên kết Bootstrap JS (ví dụ: menu thả xuống, v.v.)

$(document).ready(function(){
    if (("standalone" in window.navigator) && window.navigator.standalone) {
      // For iOS Apps
      $('a').on('click', function(e){
        e.preventDefault();
        var new_location = $(this).attr('href');
        if (new_location != undefined && new_location.substr(0, 1) != '#' && $(this).attr('data-method') == undefined){
          window.location = new_location;
        }
      });
    }
  });

1
+1. Điều này thực sự kiểm tra xem bạn có đang sử dụng webapp hay không trước khi sửa các liên kết.
Xe đẩy

1
Hoạt động trong iOS 8.0.2! Cảm ơn
Joel Murphy

1
@sean Tôi có một ứng dụng web khác đang chạy trong iPad đang sử dụng bản đồ hình ảnh as href và mã này không hoạt động .. Nó hoạt động tốt cho tất cả các liên kết khác. Bất kỳ ý tưởng làm thế nào để làm cho mã này hoạt động với bản đồ hình ảnh? Tôi đã thử sao chép toàn bộ khối và thay thế $('a').on('click', hàm (e) {`với $('area').on('click', hàm (e) {` nhưng có vẻ như nó cũng không hoạt động. Có ý kiến ​​gì không?
tuyến trùng

Trong trường hợp bạn đã có chức năng nhấp chuột xác định trên avới href="#"sau đó bạn có thể cụ thể hơn về các selector jquery, ví dụ:$('a[href!="#"]')
CJK

13

Đây là một câu hỏi cũ và nhiều giải pháp ở đây đang sử dụng javascript. Kể từ đó, iOS 11.3 đã được phát hành và bây giờ bạn có thể sử dụng thành viên phạm vi . Thành viên phạm vi là một URL giống như "/"nơi tất cả các đường dẫn trong phạm vi đó sẽ không mở một trang mới.

Thành viên phạm vi là một chuỗi đại diện cho phạm vi điều hướng của bối cảnh ứng dụng của ứng dụng web này.

Đây là ví dụ của tôi:

{
  "name": "Test",
  "short_name": "Test",
  "lang": "en-US",
  "start_url": "/",
  "scope": "/",
  ...
}

Bạn cũng có thể đọc thêm về nó ở đây . Tôi cũng khuyên bạn nên sử dụng trình tạo sẽ cung cấp chức năng này.

Nếu bạn chỉ định phạm vi, mọi thứ hoạt động như mong đợi tương tự như Android, các điểm đến ngoài phạm vi sẽ mở trong Safari - bằng nút quay lại (nút nhỏ trong thanh trạng thái) cho PWA của bạn.


7
Thật không may, tôi không tin rằng bạn có thể bao gồm các trang web khác (chẳng hạn như thông tin đăng nhập OAuth trên một tên miền khác) trong phạm vi.
bhollis

Xin chào @Amir, tôi đã tạo ra một pwa bằng Angular và trên Android, tôi nhận được 'Thêm vào lời nhắc trên màn hình chính' vì có vẻ như nó đọc chính xác manfest.json của tôi. Tuy nhiên, trên IOs Chrome / Safari, không có gợi ý ... có ý tưởng nào không?
ustad

5

Dựa trên câu trả lời của Davids và nhận xét của Richards, bạn nên thực hiện kiểm tra tên miền. Nếu không, các liên kết đến các trang web khác cũng sẽ được mở trong ứng dụng web của bạn.

$('a').live('click', function (event)
{      
    var href = $(this).attr("href");

    if (href.indexOf(location.hostname) > -1)
    {
        event.preventDefault();
        window.location = href;
    }
});

Tốt bổ sung cho các giải pháp trên. Cần kiểm tra tên miền để ngăn mọi người mở các trang web bên ngoài trong ứng dụng. Ngoài ra, hoạt động trên iOS 5.
Ian

Tôi cũng làm việc trên iOS 5. Vấn đề đôi khi có thể là với bộ đệm. Trong khi thử nghiệm các cách tiếp cận khác nhau, tôi không thể buộc iOS vô hiệu hóa bộ đệm của nó và truy xuất phiên bản mới của các tệp JS (Safari đã nhận các thay đổi nhưng không còn nữa sau khi thêm ứng dụng vào Màn hình chính). Thay đổi cổng của máy chủ dev của tôi đã giúp. Nếu bạn có max-age = 0 set (hoặc tương đương) thì điều này có thể sẽ không ảnh hưởng đến bạn.
Lukasz Korzybski

5

Nếu sử dụng jQuery Mobile, bạn sẽ trải nghiệm cửa sổ mới khi sử dụng thuộc tính data-ajax = 'false'. Trên thực tế, điều này sẽ xảy ra bất cứ khi nào ajaxEnables bị tắt, bởi và liên kết ngoài, bởi cài đặt $ .mobile.ajaxEnables hoặc bằng cách có thuộc tính target = ''.

Bạn có thể sửa nó bằng cách này:

$("a[data-ajax='false']").live("click", function(event){
  if (this.href) {
    event.preventDefault();
    location.href=this.href;
    return false;
  }
});

(Cảm ơn Richard Poole về phương thức live () - không hoạt động với bind ())

Nếu bạn đã tắt ajaxEnables trên toàn cầu, bạn sẽ cần bỏ [data-ajax = 'false'].

Điều này khiến tôi mất khá nhiều thời gian để nhận ra vì tôi đang mong đợi nó sẽ là một vấn đề cụ thể của jQuery Mobile trong khi thực tế, chính liên kết Ajax đã thực sự cấm cửa sổ mới.


Hoàn hảo, bạn đã cứu tôi :)
saulob

3

Mã này hoạt động cho iOS 5 (nó hoạt động với tôi):

Trong thẻ đầu:

<script type="text/javascript">
    function OpenLink(theLink){
        window.location.href = theLink.href;
    }
</script>

Trong liên kết mà bạn muốn được mở trong cùng một cửa sổ:

<a href="(your website here)" onclick="OpenLink(this); return false"> Link </a>

Tôi đã nhận được mã này từ nhận xét này: thẻ meta ứng dụng web iphone


Đối với một số lý do tôi nghĩ rằng đây là dễ hiểu nhất.
Jerrybibo

3

Có lẽ bạn nên cho phép mở các liên kết trong cửa sổ mới khi mục tiêu cũng được đặt rõ ràng thành "_blank":

$('a').live('click', function (event)
{      
    var href = $(this).attr("href");

    // prevent internal links (href.indexOf...) to open in safari if target
    // is not explicitly set_blank, doesn't break href="#" links
    if (href.indexOf(location.hostname) > -1 && href != "#" && $(this).attr("target") != "_blank")
    {
        event.preventDefault();
        window.location = href;
    }

});

Cảm ơn rất nhiều! Đây là mã duy nhất hoạt động cho iOS5 w / Twitter Bootstrap. Nó không hoạt động trên sản xuất mặc dù.
Chim Kan

Mmm không chắc chắn tại sao nó không hoạt động trong sản xuất nhưng tôi nghĩ đó là một cái gì đó khác. Hãy cho tôi biết!
daformat


2

Bạn cũng có thể thực hiện liên kết gần như bình thường:

<a href="#" onclick="window.location='URL_TO_GO';">TEXT OF THE LINK</a>

Và bạn có thể xóa thẻ băm và href, mọi thứ nó ảnh hưởng đến ngoại hình ..


2

Đây là những gì làm việc cho tôi trên iOS 6 (thích ứng rất nhẹ với câu trả lời của rmarscher's):

<script>                                                                
    (function(document,navigator,standalone) {                          
        if (standalone in navigator && navigator[standalone]) {         
            var curnode,location=document.location,stop=/^(a|html)$/i;  
            document.addEventListener("click", function(e) {            
                curnode=e.target;                                       
                while (!stop.test(curnode.nodeName)) {                  
                    curnode=curnode.parentNode;                         
                }                                                       
                if ("href" in curnode && (curnode.href.indexOf("http") || ~curnode.href.indexOf(location.host)) && curnode.target == false) {
                    e.preventDefault();                                 
                    location.href=curnode.href                          
                }                                                       
            },false);                                                   
        }                                                               
    })(document,window.navigator,"standalone")                          
</script>

2

Đây là phiên bản được điều chỉnh một chút của Sean đã ngăn nút quay lại

// this function makes anchor tags work properly on an iphone

$(document).ready(function(){
if (("standalone" in window.navigator) && window.navigator.standalone) {
  // For iOS Apps
  $("a").on("click", function(e){

    var new_location = $(this).attr("href");
    if (new_location != undefined && new_location.substr(0, 1) != "#" && new_location!='' && $(this).attr("data-method") == undefined){
      e.preventDefault();
      window.location = new_location;
    }
  });
}

});


1

Dành cho những người có Twitter Bootstrap và Rails 3

$('a').live('click', function (event) {
  if(!($(this).attr('data-method')=='delete')){
    var href = $(this).attr("href");
    event.preventDefault();
    window.location = href; 
  }   
});

Xóa liên kết vẫn hoạt động theo cách này.


1

Tôi thích mở tất cả các liên kết bên trong chế độ ứng dụng web độc lập ngoại trừ các liên kết có target = "_ blank". Sử dụng jQuery, tất nhiên.

$(document).on('click', 'a', function(e) {
    if ($(this).attr('target') !== '_blank') {
        e.preventDefault();
        window.location = $(this).attr('href');
    }
});

1

Một cách giải quyết khác mà tôi đã sử dụng cho một ứng dụng web iOS là tôi đã tạo tất cả các liên kết (là các nút bằng CSS) dưới dạng các nút gửi. Vì vậy, tôi đã mở một biểu mẫu được đăng lên liên kết đích, sau đó nhập kiểu = "gửi" Không phải là cách tốt nhất, nhưng đó là những gì tôi đã tìm ra trước khi tôi tìm thấy trang này.



1

Đối với những người sử dụng JQuery Mobile, các giải pháp trên phá vỡ hộp thoại bật lên. Điều này sẽ giữ liên kết trong ứng dụng web và cho phép cửa sổ bật lên.

$(document).on('click','a', function (event) {
    if($(this).attr('href').indexOf('#') == 0) {
        return true;
    }
    event.preventDefault();
    window.location = $(this).attr('href');     
});

Cũng có thể làm điều đó bằng cách:

$(document).on('click','a', function (event){
    if($(this).attr('data-rel') == 'popup'){
        return true;
    }
    event.preventDefault();
    window.location = $(this).attr('href');     
});

0

Đây là những gì tôi sẽ sử dụng cho tất cả các liên kết trên một trang ...

document.body.addEventListener(function(event) {
    if (event.target.href && event.target.target != "_blank") {
        event.preventDefault();
        window.location = this.href;                
    }
});

Nếu bạn đang sử dụng jQuery hoặc Zepto ...

$("body").on("click", "a", function(event) {
   event.target.target != "_blank" && (window.location = event.target.href);
});

-3

Bạn chỉ có thể loại bỏ thẻ meta này.

<meta name="apple-mobile-web-app-capable" content="yes">
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.