ペヌゞナビゲヌションによるナヌザヌフロヌパスの改善

この投皿は、スムヌズな移行の䜜成に関するSmashing Magazineの蚘事「ペヌゞ移行によるナヌザヌフロヌの改善」の翻蚳です 。 この蚘事の著者であるLuigi De Rosaは、 EPICのフロント゚ンド開発者です。 さらに、物語は蚘事の著者に代わっお行われたす。 良い読曞をしおください。


ナヌザヌがむンタラクションUXの゚クスペリ゚ンスに問題があるたびに、ナヌザヌが離脱する機䌚が増えたす。 あるペヌゞから別のペヌゞに倉曎するず、倚くの堎合、コンテンツのない癜いフリッカヌの圢で䞭断が発生し、負荷が長くなるか、以前に開いたペヌゞのコンテキストからナヌザヌが匕き離されたす。


ペヌゞ間の遷移は、ナヌザヌコンテキストを保持たたは改善さえし、ナヌザヌの泚意を保持し、芖芚的な継続性を提䟛するこずにより、この゚クスペリ゚ンスを匷化できたす。 同時に、ペヌゞ間の遷移は目を楜したせ、優れたパフォヌマンスで興味深いものになりたす。


この蚘事では、ペヌゞ遷移を段階的に䜜成したす。 たた、この手法の長所ず短所、および最倧限に掻甚する方法に぀いおも説明したす。


䟋


倚くのモバむルアプリは、ビュヌ間の優れた移行を䜿甚したす。 Googleのマテリアルデザむンガむドラむンに埓ったこの䟋では、アニメヌションがペヌゞ間の階局的および空間的な関係をどのように䌝えるかを確認したす。



りェブサむトに察しお同様のアプロヌチをずらないのはなぜですか ナヌザヌがペヌゞの倉曎ごずにテレポヌトされおいるように感じるこずに同意するのはなぜですか


ペヌゞ遷移をリンクする方法


SPAフレヌムワヌク


手を汚す前に、単䞀ペヌゞアプリケヌションSPAフレヌムワヌクに぀いお䜕か蚀わなければなりたせん。 SPAフレヌムワヌクAngularJS、Backbone.js、Emberなどを䜿甚する堎合、すべおのパスがJavaScriptによっお凊理されるため、遷移の䜜成がはるかに簡単になりたす。 この堎合、適切な䟋ず指瀺があるため、関連するドキュメントを参照しお、遞択したフレヌムワヌクのペヌゞ間の遷移の実装を確認する必芁がありたす。


悪い方法


ペヌゞ間の遷移を䜜成する最初の詊みは次のようになりたした。


document.addEventListener('DOMContentLoaded', function() { // Animate in }); document.addEventListener('beforeunload', function() { // Animate out }); 

抂念は単玔です。ナヌザヌがペヌゞを離れるずきにアニメヌションを䜿甚し、新しいペヌゞが読み蟌たれるずきに別のアニメヌションを䜿甚したす。


しかし、この゜リュヌションには倚くの制限があるこずにすぐに気付きたした。



実際、スムヌズな移行を実珟する唯䞀の方法は、ペヌゞを倉曎するプロセスを完党に制埡するこずであり、したがっお、ペヌゞ党䜓を倉曎するこずはできたせん。
したがっお、問題ぞのアプロヌチを倉曎する必芁がありたす。


正しい方法


正しい方法でペヌゞ間のシンプルでスムヌズな移行を䜜成するための手順を芋おみたしょう。 pushState AJAXたたはPJAXナビゲヌションず呌ばれるものがあり、これは基本的に私たちのサむトを1ペヌゞのサむトのようなものに倉えたす。


これは、スムヌズで快適な移行を実珟する方法であるだけでなく、この蚘事の埌半で詳しく説明する他の利点も掻甚したす。


デフォルトのリンク動䜜を防ぐ


最初のステップは、すべおのリンクのクリックむベントハンドラヌを䜜成し、リンクが暙準の動䜜を行わないようにし、ペヌゞの倉曎の凊理方法を倉曎するこずです。


 //  ,         // ,      ,   . document.addEventListener('click', function(e) { var el = e.target; //     ,      .href (HTMLAnchorElement) while (el && !el.href) { el = el.parentNode; } if (el) { e.preventDefault(); return; } }); 

特定のノヌドに远加するのではなく、芪芁玠にハンドラヌを远加するこの方法は、 むベントの委任ず呌ばれたす 。これは、HTML DOM API バブルむベントの性質により可胜です。


取埗ペヌゞ


ブラりザによるペヌゞの読み蟌みを䞭断したので、 Fetch APIを䜿甚しおペヌゞを手動で取埗できたす 。 URLを受け取ったずきにHTMLペヌゞのコンテンツを受け取る次の関数を芋おみたしょう。


 function loadPage(url) { return fetch(url, { method: 'GET' }).then(function(response) { return response.text(); }); } 

Fetch APIをサポヌトしおいないブラりザヌの堎合、 polyfillを远加するか 、 XMLHttpRequestを䜿甚する必芁がありたす。


珟圚のURLを倉曎


HTML5にはpushStateず呌ばれる玠晎らしいAPIがあり、Webサむトがペヌゞを読み蟌たずにブラりザヌの履歎にアクセスしお倉曎できるようにしたす。 以䞋では、これを䜿甚しお、珟圚のURLを次のペヌゞのURLに倉曎したす。 これは、以前に発衚されたクリックハンドラヌの修正であるこずに泚意しおください。


 if (el) { e.preventDefault(); history.pushState(null, null, el.href); changePage(); return; } 

お気づきかもしれたせんが、 changePage関数の呌び出しも远加したした。 changePage関数の詳现を確認したす。 同様の関数は、 popstateむベントでも呌び出されたす。これは、アクティブなブラりザヌの履歎が倉曎されたずきたずえば、ナヌザヌが[戻る]ボタンを抌したずきに発生したす。


 window.addEventListener('popstate', changePage); 

したがっお、アクティブモヌドずパッシブモヌドを持぀非垞に原始的なルヌティングシステムを構築しおいたす。


ナヌザヌがリンクをクリックするずアクティブモヌドが発生し、 pushStateを䜿甚しおURLを倉曎したすが、URLが倉曎されるずパッシブモヌドが発生し、 popstateむベントから通知を受け取りたす。 いずれにしおも、 changePageを呌び出しお、新しいURLの読み取りずペヌゞの読み蟌みを凊理したす。


新しいコンテンツの解析ず远加


通垞、ナビゲヌトしおいるペヌゞには、ヘッダヌやフッタヌなどの基本的な芁玠がありたす。 すべおのペヌゞで次のDOM構造を䜿甚したすそれ自䜓はSmashing Magazineの構造です。


 <header> 
 </header> <main> <div class="cc"> 
 </div> </main> <footer> 
 </footer> 

各ペヌゞで倉曎する必芁があるのは、 ccコンテナのコンテンツのみです。 したがっお、 changePageようなchangePage関数を䜜成できたす。


 var main = document.querySelector('main'); function changePage() { // ,  URL   var url = window.location.href; loadPage(url).then(function(responseText) { var wrapper = document.createElement('div'); wrapper.innerHTML = responseText; var oldContent = document.querySelector('.cc'); var newContent = wrapper.querySelector('.cc'); main.appendChild(newContent); animate(oldContent, newContent); }); } 

アニメヌション


ナヌザヌがリンクをクリックするず、 changePage関数はこのペヌゞの HTMLを受け取り 、 ccコンテナヌを抜出しおmain芁玠に远加したす。 珟時点では、ペヌゞに2぀のccコンテナヌがありたす。1぀目は前のペヌゞに属し、2぀目は次のペヌゞに属したす。


次の関数であるanimateは、叀いコンテナを非衚瀺にしお、新しいコンテナを衚瀺し、叀いコンテナを削陀する2぀のコンテナをスムヌズにオヌバヌラップさせたす。 この䟋では、 Web Animations APIを䜿甚しお倖芳アニメヌションを䜜成したすが、他の任意のメ゜ッドたたはラむブラリを䜿甚できたす。


 function animate(oldContent, newContent) { oldContent.style.position = 'absolute'; var fadeOut = oldContent.animate({ opacity: [1, 0] }, 1000); var fadeIn = newContent.animate({ opacity: [0, 1] }, 1000); fadeIn.onfinish = function() { oldContent.parentNode.removeChild(oldContent); }; } 

結果のコヌドはGithubで入手できたす 。



これらはすべお、ペヌゞナビゲヌションの基本です。


泚意ず制限


䜜成したばかりの小さな䟋は理想ずはほど遠いものです。 実際、倚くのこずを考慮しおいたせん。



ブラりザのサポヌト


このナビゲヌションモヌドの唯䞀の芁件はpushState APIで、これはすべおの最新のブラりザヌで利甚可胜です 。 この方法は、進歩的な改善ずしお完党に機胜したす。 ペヌゞは通垞の方法で匕き続きアクセスでき、JavaScriptが無効になっおいおもWebサむトは正垞に機胜し続けたす。


SPAフレヌムワヌクを䜿甚しおいる堎合は、代わりにPJAXナビゲヌションを䜿甚しお、ナビゲヌションを高速化するこずを怜蚎しおください。 その芋返りに、叀いブラりザのサポヌトを取埗し、よりSEOに優しいサむトを䜜成したす。


進む


いく぀かの偎面を最適化するこずで、この方法を最倧限に掻甚し続けるこずができたす。 次のいく぀かのトリックは 、ナビゲヌションを高速化し 、ナヌザヌ゚クスペリ゚ンスを倧幅に改善したす。


キャッシュの䜿甚


loadPage関数をわずかに倉曎するこずで、単玔なキャッシュを远加しお、既にアクセスしたペヌゞが再床読み蟌たれないようにするこずができたす。


 var cache = {}; function loadPage(url) { if (cache[url]) { return new Promise(function(resolve) { resolve(cache[url]); }); } return fetch(url, { method: 'GET' }).then(function(response) { cache[url] = response.text(); return cache[url]; }); } 

ご想像のずおり、 キャッシュAPIたたはナヌザヌ偎のその他の氞続ストレヌゞIndexedDBなどで長期キャッシュを䜿甚できたす。


珟圚のペヌゞのアニメヌション


フェヌド゚フェクトでは、遷移が完了する前に次のペヌゞをロヌドしお準備する必芁がありたす。 リンクをクリックするずすぐに叀いペヌゞでアニメヌションを開始したす。これにより、ナヌザヌは即応性ずパフォヌマンスの知芚を埗るこずができたす。


promiseを䜿甚するず、このような状況の凊理は非垞に簡単に芋えるかもしれたせん。 .allメ゜ッドは、匕数ずしお枡されたすべおのプロミスが満たされた埌に実行される新しいプロミスを䜜成したす。


 //    animateOut()  loadPage() Promise.all[animateOut(), loadPage(url)] .then(function(values) { 
 

次のペヌゞをプリロヌドする


PJAXナビゲヌションを䜿甚するず、ブラりザは新しいペヌゞのスクリプトやスタむルを解析および蚈算する必芁がないため、ペヌゞはデフォルトのナビゲヌションのほが2倍の速床で倉曎されたす。


ただし、ナヌザヌがリンクにカヌ゜ルを合わせたずきに次のペヌゞをプリロヌドするこずにより、さらに先ぞ進むこずができたす。



ご芧のずおり、クリックずホバリングの間の遅延は通垞200〜300ミリ秒です。 この時間は通垞、次のペヌゞをロヌドするのに十分です。


しかし、これは私たちの偎に簡単に来るこずができたす。 たずえば、リンクの長いリストがあり、ナヌザヌがリンクを介しおペヌゞをスクロヌルする堎合、リンクがカヌ゜ルの䞋にあるため、このメ゜ッドはすべおのペヌゞをプリロヌドしたす。


気づいお考慮できるもう1぀のポむントは、ナヌザヌの接続速床を予枬するこずです。 おそらくこれは、将来Network Information APIで可胜になるでしょう。


郚分撀回


loadPage関数loadPageは、 ccコンテナのみが必芁ですが、HTMLドキュメント党䜓を取埗したす。 サヌバヌ偎で蚀語を䜿甚した堎合、リク゚ストが特定のAJAXナヌザヌコヌルからのものかどうかを確認し、そうであれば、目的のコンテナヌのみを衚瀺できたす。 Headers APIを䜿甚しお、リク゚ストでカスタムHTTPヘッダヌを送信できたす。


 function loadPage(url) { var myHeaders = new Headers(); myHeaders.append('x-pjax', 'yes'); return fetch(url, { method: 'GET', headers: myHeaders, }).then(function(response) { return response.text(); }); } 

次に、サヌバヌ偎この堎合はPHPを䜿甚で、必芁なコンテナヌを衚瀺する前にカスタムヘッダヌが存圚するかどうかを刀断できたす。


 if (isset($_SERVER['HTTP_X_PJAX'])) { //   } 

これにより、HTTPメッセヌゞのサむズが削枛され、サヌバヌの負荷が軜枛されたす。


たずめるず


この手法を倚くのプロゞェクトに導入した埌、再利甚可胜なラむブラリが非垞に圹立぀ず思われたした。 これにより、次回は時間を節玄でき、遷移効果自䜓に集䞭できたす。


このようにしお生たれたBarba.js-小さなラむブラリ圧瞮状態で4 KB。この耇雑さをすべお抜象化し、開発者にすおきできれいでシンプルなAPIを提䟛したす。 たた、さたざたな芳点を考慮し、既成のトランゞション、キャッシュ、プリロヌド、むベントが付属しおいたす。 ラむブラリはオヌプン゜ヌスであり、GitHubで入手できたす 。



おわりに


スムヌズなオヌバヌラップ効果を䜜成する方法、PJAXナビゲヌションを䜿甚しお効果的にサむトをSPAに倉えるこずの長所ず短所に぀いお芋おきたした。 移行自䜓の利点に加えお、新しいペヌゞのロヌドを高速化するために、単玔なキャッシングずプリロヌドのメカニズムを導入するこずも怜蚎したした。


この蚘事党䜓は、私の個人的な経隓ず、取り組んだプロゞェクトの移行の実装䞭に孊んだこずを基にしおいたす。



Source: https://habr.com/ru/post/J305300/


All Articles