Możemy użyć, window.location.replace
aby ominąć historię i celować w kotwice na stronie bez przeładowań strony, ale nie w ramkach iframe?
Problemem jest naruszenie CSP (polityka bezpieczeństwa treści), które script-src 'unsafe-inline'
muszą być włączone. Tyle że nie mam zdefiniowanego CSP, a nawet jeśli go zdefiniuję i pozwolę, script-src 'unsafe-inline'
że nadal daje ten sam błąd naruszenia. Ten sam wynik w ie11 / chrome / ff.
Element iframe w tej samej domenie (w tym samym katalogu).
- Skieruj ramkę iframe w konsoli i użyj
window.location.replace('/samepage.html#onpage_anchor')
w konsoli. - to działa. Kieruje na kotwicę na stronie bez ponownego ładowania strony i bez historii.
- Umieść ten sam kod w linii na linkach zakotwiczenia i działa.
- Użyj tego samego kodu w skrypcie zewnętrznym, uzyskaj błąd naruszenia csp. Działa to dobrze, jeśli nie w ramce iframe.
Próbowałem tworzenia CSP , aby umożliwić działanie, ale nie nawet te najbardziej liberalne zasady zabezpieczeń zawartości możliwe by to umożliwić.
Edycja: więc zestawiłem przykłady na temat narzędzia plunker, które pozwala na wiele plików, aby móc użyć odpowiednich hrefów, które odwołują się do stron nadrzędnych / podrzędnych.
Uwagi na temat przykładów plunkera:
Problem nie został odtworzony w tych przykładach. Skrypt działa doskonale, nawet w ramce iframe. Jednak ten sam kod nie działa na moim serwerze lokalnym lub po uruchomieniu go na żywo na VPS.
Podejrzewam, że naruszenie CSP nie jest wywoływane przez plunker, ponieważ plunker przedstawia zawartość przeglądarce za pomocą pewnego rodzaju warstwy abstrakcji.
Pierwsze kliknięcie łączy akordeonu w rodzicu powoduje odświeżenie. Jest tak, ponieważ sposób, w jaki strona początkowo się ładuje, nie odwołuje się do index.html. Kolejne kliknięcia działają zgodnie z oczekiwaniami bez ponownego ładowania strony. Nie stanowi to problemu w ramce iframe, ponieważ początkowo odnosi się do child.html
Są to dobre przykłady pokazania kodu bez konieczności wprowadzania zmian, aby działał (jak potrzeba zmiany hrefów, aby działały we fragmentach przepełnienia stosu, wymienionych poniżej). Jest również dobry, ponieważ pokazuje javascript działający tak, jak powinien. Ale to nie pokazuje rzeczywistego problemu. Nadal będziesz musiał załadować go do edytora i uruchomić na lokalnym serwerze lub na żywo, aby zobaczyć prawdziwy problem.
Przykłady plunkera
Ze skryptem: Bez historii
Bez skryptu: Z historią
Przykład kodu uproszczonego
Prosty akordeon z jednym wejściem. Wystarczające do odtworzenia problemu.
Kliknięcie przycisku otwórz / zamknij spowoduje rozwinięcie / zwinięcie akordeonu, nie wymaga JS. JS powinien zrobić dokładnie to samo, ale bez historii. Działa dobrze, ale nie w ramce iframe.
Uwagi do fragmentu kodu:
Możesz uruchomić fragment kodu, aby zorientować się, co opisuję, ale tak naprawdę nie pokazuje on problemu.
Fragment kodu nie działa tak, jak w prawdziwej przeglądarce, JavaScript nie działa.
Fragment pokazuje kod, ale należy go uruchomić w elemencie iframe, aby zobaczyć problem. Uruchom go poza ramką iframe, aby zobaczyć różnicę i sposób działania.
- Ze względu na to, w jaki sposób łącza działają z JS (zastępując cały adres URL), tak naprawdę muszą być takie,
href="https://stackoverflow.com/thispage.html#ac1"
a nie tylkohref="#ac1"
takie, jakie pojawiają się we fragmencie (nie mogą być kierowane na rzeczywistą stronę HTML w fragmencie). Więc jeśli spróbujesz tego w swoim edytorze (zrób to), pamiętaj o zmianie linków do tego formatu,this_document.html#anchor
aby nadal były tymi samymi kotwicami strony, ale page.html jest zawarty w linku.
Scenariusz
$(document).ready(function() {
// anchor links without history
$.acAnch = function(event) {
event.preventDefault();
var anchLnk = $(event.target);
var anchTrgt = anchLnk.attr('href');
window.location.replace(anchTrgt);
}
// listen for anchor clicks
$('.accordion').on('click', 'a', $.acAnch);
});
Jest to bardzo proste:
1. Funkcja acAnch bierze href
atrybut i upuszcza go window.location.replace()
.
2. Nasłuchuj kliknięć zakotwiczeń w akordeonie, aby uruchomić funkcję acAnch.
Wszystko, co robi skrypt, jest uruchamiane window.location.replace('/this_same_page.html#on_page_anchor')
Jeśli umieścisz to w konsoli, będzie działać, bez naruszenia CSP. Ale uruchomienie go z zewnętrznego skryptu nie działa.
Inline na linkach działa dobrze:
onclick="event.preventDefault();window.location.replace('/thispage.html#acc0');"
onclick="event.preventDefault();window.location.replace('/thispage.html#acc1');"
Umieszczenie tego w odpowiednich linkach działa idealnie , ale naprawdę wolę nie używać takiego wbudowanego skryptu. Musi istnieć sposób na to za pomocą zewnętrznego skryptu.
Próbowałem uruchomić javascript na obiekcie nadrzędnym zamiast w ramce iframe (oczywiście z modyfikacjami umożliwiającymi wybór łączy w obrębie potomka). Ten sam wynik błędu CSP.
Dlaczego to robię?
Cóż, strona jest znacznie bardziej złożona niż przykład. Zakotwiczenia w elementach iframe działają dobrze, ale dodają historię. Jeśli uruchomisz powyższy kod bez javascript (lub po prostu uruchomisz fragment kodu), otworzysz i zamkniesz akordeon kilka razy, a następnie użyjesz przycisku Wstecz, nastąpi powrót do stanu otwartego zamknięcia.
Nie miałbym nic przeciwko historii, ale jeśli jest w ramce iframe, kiedy opuścisz stronę nadrzędną, a następnie do niej wrócisz, historia w ramce iframe jest zepsuta. Cofanie się nie wraca już przez stany akordeonu, ale po prostu ciągle ładuje iframe. Początkowo kotwice nie powodują przeładowania iframe, a jedynie przechodzą przez historię stanu akordeonu, która działa dobrze, dopóki nie opuścisz strony i nie wrócisz. Potem powrót nie przechodzi już przez stany akordeonu, ale po prostu przechodzi przez stos identycznych przeładowań iframe. Jest to bardzo nieprzyjazne zachowanie użytkownika.
Nie muszę używać location.replace, jeśli istnieje inna metoda, która będzie działać. Próbowałem jednak wielu innych podejść i odkryłem, że metody, które mogą osiągnąć ten sam wynik, generalnie powodują ten sam błąd.
Celem jest po prostu aktywowanie linków zakotwiczenia na stronie bez ponownego ładowania i bez historii w ramce iframe.
Skrypt wbudowany działa. Czy możemy sprawić, by działał w zewnętrznym pliku .js?
<a href="#ac0" class="ac-close">Close</a>
powinno działać.