怎麼給新手解釋 react 的 spa 應用錨點跳轉的問題

更多內容在我的語雀:www.yuque.com/xiezhongfu/…css

前言

咱們先區分下「頁面」這個詞:html

  • 單頁面應用(spa)就只有一個頁面
  • 文中所指的頁面是從瀏覽器的 url 角度去理解的,只要 protocol + port + pathname 不一樣,瀏覽器就認爲是新頁面

問題是什麼

<Route path="/foo" componet={Foo} />
<Route path="/bar" componet={Bar} /> // Foo 頁面組件 和 Bar 頁面組件都是靜態化組件(這兩個組件裏面的數據都是不變的) .... <Link to="/foo">foo</Link> <Link to="/bar#test">bar</Link> 複製代碼

單頁面應用,在同一個頁面使用 hash 跳轉到頁面不一樣位置(錨點跳轉)。此功能是不正常的。
還能夠看看前人發的 issue 參見:github.com/ReactTraini…。針對這個問題也有相應解決方案:react

順便說一下,scrollIntoView 和 scrollTo 能夠設置平滑滾動;在滾動區域 css 設置 scroll-behavior 也能夠平滑滾動,粗暴一點咱們給 * 設置 scroll-behavior 吧。git

猜想爲何

讓咱們在看下這段代碼github

<Route path="/foo" componet={Foo} />
<Route path="/bar" componet={Bar} /> // Foo 頁面組件 和 Bar 頁面組件都是靜態化組件(這兩個組件裏面的數據都是不變的) .... <Link to="/foo">foo</Link> <Link to="/bar#test">bar</Link> 複製代碼

在不一樣的頁面跳轉不一樣錨點,history 有更新,初始化渲染組件,功能正常。
在同一個頁面跳轉不一樣錨點,history 有更新,從新渲染原組件,功能不正常。
原生方式下,就算在同一個頁面的不一樣錨點間跳轉,功能正常。web

場景 A
假設咱們這樣路由了 2 個組件,咱們先點擊了 foo,渲染了 Foo 組件。而後咱們點擊 bar ,pathname 從 /foo 路由到 /barBar 組件會初始化渲染,頁面效果是直接定位到了 Bar 組件渲染的頁面中的 test 錨點。
場景 B
假設在 Bar 頁面內有一個本身頁面內的錨點,咱們點擊它,雖然這個錨點就在同一個頁面,錨點跳轉失效。效果是 url 上看到錨點變了,可是沒跳到對應的新錨點。
由於使用了 Link 組件,在 Bar 頁面內點擊了一個新的錨點,Link 組件內使用了 push 或者 replace 產生了新的 window.history 記錄,這個新 window.history 的 pathname 和之前同樣,只是有新的 hash。而後就去 Route 裏去找匹配的組件,發現匹配到了 Bar 組件 。由於已經渲染過了,那就從新渲染吧。
由於 protocol,port,pathname 都沒變,只是 hash 變了,瀏覽器認爲這是老頁面上的一個新錨點,那就在老頁面上跳轉吧。可是頁面組件若是在從新渲染,也許在瀏覽器剛想要跳新錨點的時候重現渲染致使錨點沒了,跳轉失敗。chrome

咱們總結下這個過程:
在 react 應用中的錨點跳轉的實現方案是:Link 組件。跳轉新頁面錨點成功,可是跳轉同頁面錨點失敗。
Link 組件默認行爲包括調用 history 庫的 push 或 replace,組件會初始化渲染或者從新渲染。渲染的過程是 js 對象轉爲 html 的過程。若是這個過程還沒結束,html 還沒及時出現,錨點功能就失效了。
。咱們知道錨點能成功,必定是瀏覽器在跳轉的時候有 html 節點上有對應的 id 或 name(好比:a 標籤可使用 name 用來標記別人能夠跳到它這),若是沒有那就跳轉失敗。瀏覽器

以上推理都是根據經驗猜想,咱們懷疑:
場景 A 在由於是新頁面,在瀏覽器跳轉錨點前 react 組件初始化渲染已經完成, html 已經有對應錨點了。
場景 B 因爲是同一個頁面,在瀏覽器跳轉錨點前 react 組件從新渲染還沒完成,跳轉失敗了。
那瀏覽器究竟是怎麼執行錨點跳轉的呢?開始查材料......react-router

這真的是緣由麼

咱們先看標準文檔是怎麼解釋錨點的:html.spec.whatwg.org/multipage/b…oop

在看 chrome 是怎麼處理的:cs.chromium.org/chromium/sr… (這是巢鵬大佬的解答)

image.png

咱們再來看回顧下遇到的問題:

  • Link 組件新跳轉帶錨點的頁面,組件初始化渲染,錨點功能正常
  • Link 組件在同一個頁面跳轉新錨點,組件從新渲染,錨點功能異常
  • 若是是 a 標籤無論是否是新頁面,錨點功能都正常

從 chrome 的實現和咱們遇到的問題中能體會出關鍵在因而不是新頁面。整個過程說得比較繞,指望是表達清楚了。

最後

在這個過程當中還遇到一些老知識,複習下吧:

相關文章
相關標籤/搜索