Веб-додаток iPhone Safari відкриває посилання у новому вікні


155

У мене виникають проблеми з Інтернетом після додавання піктограми на головний екран. Якщо Інтернет запускається з головного екрану, всі посилання відкриються в новому вікні Safari (і втратять функцію повноекранного режиму). Як я можу це запобігти? Я не міг знайти жодної допомоги, лише те саме питання без відповіді.


3
Тепер ви можете використовувати scopeпараметр в manifest.json. Дивіться мою відповідь для отримання більш детальної інформації. Я протестував його в iOS 11.3, і він працює.
Амір Рамінфар

3
Щоб повторити, для тих, хто бореться із відкриттям Safari iOS 11.3, перегляньте відповідь @ 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
Чи має це побічні ефекти?
pingu

94

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

Проект html5 для мобільних котлів посилається на цю суть, яка добре обговорює тему: 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>

Це чудово працює за винятком однієї сторінки, сторінки "Зв'яжіться з нами" для нашої компанії. Замість того, щоб показувати сторінку, вона відкриває додаток "Карти" та визначає наш офіс. Що може бути причиною цього, і як це можна виправити?
Джонатан

@Jonathan Я не впевнений. Чи не станеться, якщо ви видалите цей скрипт? Можливо, опублікуйте посилання на ваш сайт? Або відкрити нове запитання, що може бути краще.
rmarscher

@rmarscher Це відбувається лише під час запуску вказаного вами коду, а не без нього. Я сам веб-розробник, і не розумію, чому це поводитиметься за посиланням таким чином. У мене немає URL-адреси сторінки, оскільки вона наразі не працює, тому ви її не помітите. Крім того, це впливає і на звичайний Safari, і не тільки в автономному режимі. Дякую за вашу відповідь!
Джонатан

Це має бути прийнятою відповіддю і створило привабливість для мого клієнта на повноекранному екрані iPad1, зробленого разом із PHPRunner, помістивши код у заголовку. Не впевнений, чому це так заплутано, як здається досить стислим біт коду, який можна було б написати розбірливо без особливих накладних витрат ... це просто вибагливо, хоча і взагалі дуже хочеться сказати спасибі.
sradforth

4
Це порушує Bootstrappy речі, такі як href = "#" посилання, які використовуються функціями js
Sean

47

Якщо ви використовуєте jQuery, ви можете:

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

1
Поясніть, будь ласка, чому .live () може бути кращим?
ajcw

8
Live пов'язує подію з усіма посиланнями, включаючи ті, які ще не існують, натискання
посилатиметься

Дякую! рятівник. Я просто витрачав години, намагаючись з’ясувати, чому сафарі весь час завантажується.
Стів

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'функцію (e) {`на $('area').on('click', функцію (e) {`, але це, схоже, не працює. Будь-які ідеї?
нематот

У разі , якщо у вас вже є кліки функція , певну на aз , href="#"то ви можете бути більш конкретним селектор Jquery, наприклад$('a[href!="#"]')
Далекосхідні

13

Це давнє запитання, і багато з вирішень тут використовують JavaScript. З цього моменту iOS 11.3 було випущено, і тепер ви можете використовувати член області . Учасник області - це URL-адреса, подібна до того, "/"коли всі шляхи під цим діапазоном не відкриють нову сторінку.

Член області - це рядок, який представляє область навігації в контексті програми цього веб-додатка.

Ось мій приклад:

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

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

Якщо ви вкажете область застосування, все працює так, як очікувалося, схоже на Android, пункти призначення поза сферою дії відкриються в Safari - кнопкою "назад" (маленька у рядку стану) для вашого PWA.


7
На жаль, я не вірю, що ви можете включити до цього веб-сайту інші веб-сайти (наприклад, вхід в OAuth на іншому домені).
bhollis

Привіт @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 все ж змінив зміни, але не більше після додавання програми на головний екран). Зміна порту мого сервера розробників допомогла. Якщо у вас max-age = 0 set (або еквівалент), це, ймовірно, не вплине на вас.
Лукаш Коржибський

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


Я чомусь думаю, що це найлегше зрозуміти.
Джеррібібо

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 w / Twitter Bootstrap. Хоча це не працює на виробництві.
Чим Кан

Ммм не дуже впевнений, чому це не спрацювало б у виробництві, але я думаю, це щось інше. Дайте мені знати!
daformat

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, вищевказані рішення розбивають діалогове вікно, що з’являється. Це дозволить зберегти посилання в межах webapp і забезпечить появу спливаючих вікон.

$(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.