iPhone Safari Web App открывает ссылки в новом окне


155

У меня проблема с вебом после добавления значка на главный экран. Если веб-сайт запускается с главного экрана, все ссылки открываются в новом окне в Safari (и теряют полноэкранный режим). Как я могу предотвратить это? Я не мог найти никакой помощи, только тот же вопрос без ответа.


3
Теперь вы можете использовать scopeпараметр в manifest.json. Смотрите мой ответ для более подробной информации. Я протестировал его в iOS 11.3, и он работает.
Амир Раминфар

3
Чтобы повторить, для тех, кто борется с iOS 11.3, открывая Safari, пожалуйста, смотрите ответ @ AmirRaminfar здесь: stackoverflow.com/a/49604315/32055
Крис Хейнс,

Ответы:


110

Я нашел решение JavaScript в рамках 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
Чтобы заявить об очевидном и сделать это явным: iOS рассматривает ссылки в веб-приложениях как нечто, что должно быть открыто в Safari, а расположение javascript изменяется как действие в приложении, которое разрешено выполнять в веб-приложении. Приведенный выше код работает, потому что он предотвращает поведение ссылки по умолчанию, заменяя его на вызов js nav.
Оскар Остегард

6
Есть ли пример обратного? Заставить веб-приложение iPhone открыть страницу в Safari, даже если это изменение местоположения в javascript?
tkahn

1
@Pavel спасибо за упоминание iwebkit :). Помогает получить трафик: D
cmplieger

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

1
Есть ли у этого побочные эффекты?
Пингв

94

Другие решения здесь либо не учитывают внешние ссылки (которые вы, вероятно, хотите открыть внешне в Safari), либо не учитывают относительные ссылки (без домена в них).

Проект html5 mobile-шаблон содержит ссылку на эту суть, которая хорошо обсуждает эту тему: https://gist.github.com/1042026

Вот заключительный код, который они придумали:

<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>

Это прекрасно работает, за исключением одной страницы, страницы "Свяжитесь с нами" для нашей компании. Вместо того, чтобы показывать страницу, он открывает приложение «Карты» и определяет наш офис. Что может быть причиной этого, и как мы можем это исправить?
Джонатан

@ Джонатан, я не уверен. Разве не произойдет, если вы удалите этот скрипт? Может разместить ссылку на свой сайт? Или откройте новый вопрос, который может быть лучше.
rmarscher

@rmarscher Это происходит только при запуске предоставленного вами кода, а не без него. Я сам веб-разработчик, и я не понимаю, почему он так справился со ссылкой. У меня нет URL страницы, потому что в настоящее время он не запускает код, поэтому вы не заметите его. Кроме того, это влияет на обычное Safari, а не только автономно. Спасибо за Ваш ответ!
Джонатан

Это должен быть принятый ответ, и это сработало на моем полноэкранном клиенте iPad1, сделанном с помощью PHPRunner, поместив код в шапку. Не уверен, почему это так запутанно, поскольку кажется, что это довольно лаконичный фрагмент кода, который можно было бы написать разборчиво, без лишних BW-затрат ... это просто придирчиво и, как правило, очень хочется сказать спасибо.
sradforth

4
Это разрушает загрузочные вещи, такие как ссылки href = "#", которые используются функциями js
Шон

47

Если вы используете jQuery, вы можете сделать:

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

1
Пожалуйста, объясните, почему .live () может быть лучше?
ajcw

8
Live будет связывать событие со всеми ссылками, включая те, которые еще не существуют, щелчок будет связывать только те, которые существуют в настоящее время
msaspence

Спасибо! спасатель. Я просто часами пытался понять, почему сафари все время загружается.
Стив

1
+1 от меня - используется this.hrefвместо приведения к объекту jQuery, но спасибо за этот ответ. Работает на iOS6.
Фентон

17
.live () устарела начиная с jQuery 1.7 и удалена с 1.9 . Вместо этого используйте $ (document) .on ('click', 'a', function () {...}).
Том Дэвис,

21

Это работает для меня на iOS 6.1 и со ссылками Bootstrap JS (т.е. выпадающие меню и т. Д.)

$(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. Это фактически проверяет, используете ли вы веб-приложение, прежде чем исправлять ссылки.
Тележка

1
Работает в iOS 8.0.2! Спасибо
Джоэл Мерфи

1
@sean У меня есть еще одно веб-приложение, работающее на iPad, которое использует карту изображений как href, и этот код не работает .. Он отлично работает для всех других ссылок. Есть идеи, как заставить этот код работать с картами изображений? Я попытался скопировать весь блок и заменить $('a').on('click', function (e) {`на $('area').on('click', function (e) {`, но, похоже, это тоже не сработало. Любые идеи?
нематот

В случае, если у вас уже есть определенные функции щелчка, aс помощью которых href="#"вы можете более точно указать селектор jquery, например$('a[href!="#"]')
cjk

13

Это старый вопрос, и многие решения здесь используют javascript. С тех пор iOS 11.3 была выпущена, и теперь вы можете использовать элемент scope . Член области - это URL-адрес, подобный тому, "/"где все пути в этой области не открывают новую страницу.

Член области - это строка, представляющая область навигации контекста приложения этого веб-приложения.

Вот мой пример:

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

Вы также можете прочитать больше об этом здесь . Я также рекомендую использовать генератор, который обеспечит эту функциональность.

Если вы укажете область действия, все будет работать так же, как и в случае с Android, места назначения за пределами области откроются в Safari - с кнопкой «Назад» (маленькая в строке состояния) для вашего PWA.


7
К сожалению, я не верю, что вы можете включить в область действия другие веб-сайты (такие как входы OAuth в другом домене).
Боллис

Привет @Amir, я создал pwa, используя Angular, и на Android я получаю «Добавить в домашний экран», так как похоже, что он правильно читает мой manfest.json. Тем не менее, на IOs Chrome / Safari, нет подсказки ... есть идеи?
Устад

5

На основании ответа Дэвидса и комментария Ричардса, вы должны выполнить проверку домена. В противном случае ссылки на другие сайты также будут открыты в вашем веб-приложении.

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

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

Хорошее дополнение к вышеупомянутым решениям. Необходима проверка домена, чтобы люди не могли открывать сторонние сайты в приложении. Также работает на iOS 5.
Ян

у меня работает на iOS 5 тоже. Проблема иногда может быть с кешем. При тестировании различных подходов я не смог заставить iOS сделать недействительным свой кеш и получить новую версию файлов JS (Safari действительно принял изменения, но не после добавления приложения на главный экран). Помогло изменение порта моего сервера dev. Если у вас установлен max-age = 0 (или эквивалент), это, вероятно, не повлияет на вас.
Лукаш Коржибски

5

При использовании jQuery Mobile вы увидите новое окно при использовании атрибута data-ajax = 'false'. Фактически, это будет происходить всякий раз, когда ajaxEnabled отключается, используя внешнюю ссылку, настройку $ .mobile.ajaxEnabled или имея атрибут target = ''.

Вы можете исправить это используя это:

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

(Спасибо Ричарду Пулу за метод live () - он не работал с bind ())

Если вы отключили ajaxEnabled глобально, вам нужно удалить [data-ajax = 'false'].

Это заняло у меня довольно много времени, чтобы понять, как я ожидал, что это будет специфическая проблема jQuery Mobile, где на самом деле это было соединение с Ajax, которое фактически запретило новое окно.


Отлично, вы меня спасли :)
saulob

3

Этот код работает для iOS 5 (он работал для меня):

В заголовке тега:

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

В ссылке, которую вы хотите открыть в том же окне:

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

Я получил этот код из этого комментария: метатеги веб-приложения iphone


По некоторым причинам я думаю, что это легче всего понять.
Jerrybibo

3

Возможно, вам следует разрешить открывать ссылки в новом окне, когда для цели явно установлено значение "_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;
    }

});

Большое спасибо! Это единственный код, который работал для iOS5 с Twitter Bootstrap. Это не работает на производстве, хотя.
Чим Кан

Ммм, я не совсем уверен, почему это не сработает в производстве, но я думаю, что это нечто другое. Дай мне знать!
Даформат

3

Я нашел один, который является очень полным и эффективным, потому что он проверяет работу только под автономным WebApp, работает без jQuery и также прост, только что протестирован под iOS 8.2:

Оставайтесь автономными: не открывайте ссылки в автономных веб-приложениях, открывая Mobile Safari


2

Вы также можете сделать ссылку почти нормально:

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

И вы можете удалить хеш-тег и HREF, все, что он делает, это влияет на внешний вид ..


2

Вот что у меня сработало на iOS 6 (очень слабая адаптация ответа rmarscher):

<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

Это слегка адаптированная версия Шона, которая мешала вернуться назад.

// 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

Для тех, кто с Twitter Bootstrap и Rails 3

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

Удалить ссылки все еще работают таким образом.


1

Я предпочитаю открывать все ссылки в режиме автономного веб-приложения, кроме тех, которые имеют target = "_ blank". Использование jQuery, конечно.

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

1

Одним из обходных путей, который я использовал для веб-приложения для iOS, было то, что я сделал все ссылки (которые были кнопками по CSS) с кнопок отправки формы. Поэтому я открыл форму, которая отправила ссылку на место назначения, а затем введите type = "submit" Не лучшим образом, но это то, что я понял до того, как нашел эту страницу.



1

Для тех JQuery Mobile, кто использует , вышеупомянутые решения ломают всплывающее диалоговое окно. Это будет держать ссылки в веб-приложении и позволит всплывающие окна.

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

Может также сделать это:

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

0

Вот что я бы использовал для всех ссылок на странице ...

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

Если вы используете JQuery или Zepto ...

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.