背景:
對於一般采用同樣的技術棧開發的多頁面應用來說,可能遇到的狀況如下:
- h5上拉刷新來實現分頁,當有很多頁的話,點擊列表某一頁去詳細,然后從詳情返回上一頁,可能刷新上一頁,位置不能保持,體驗不好
- 列表使用a鏈接過去的,詳情使用window.history.go(-1)返回,有些瀏覽器不刷新上一頁(ios中safari,UC等),有些頁面刷新上一頁(ios中微信等)
- 有說使用單頁的話,可以保持。但是之前用過angular1.X來實現單頁,返回貌似也有這個問題(重新執行了列表js),最近在github看到有用vue實現了這個的效果:https://github.com/lzxb/vue-cnode?from=xitu
- 有說列表用window.open,詳情用window.history.go(-1),h5實踐了,不可以,見上一篇。
- 之前還想過用iframe標簽,但是這只適合用於iframe嵌入的頁面可進入的下級頁面有限,不會再回到列表頁面,或者就是一個預覽性的小頁面。
實際項目中遇到的問題
基於以上背景中的一些方法,除了提到的一些弊端,還只適合於簡單的從詳情頁到列表頁不需要更新列表頁數據的情況,如果是需要更新列表頁數據就需要考慮怎樣把要更新的某一條數據的標志傳到列表頁,列表頁再通過ajax請求最新的數據。
在實際中遇到的項目是原來的php項目用vue重構,列表頁等部分頁面是vue單頁應用,詳情頁因為考慮seo的問題依然是php頁面,這就導致兩個完全不同的技術棧的頁面之間是完全獨立的,背景中提到的打開新窗口的頁面對於pc端和安卓手機的主流瀏覽器都是可行的,但是對於微信瀏覽器和iphone中的大部分國內瀏覽器都是默認不執行新窗口打開的。本來想用直接關掉新窗口重現列表頁的方法還是不夠好,特別是對於微信瀏覽器這種手機端比較大的流量入口來說,無論怎樣都會刷新列表頁,根本達不到我們想要的效果。
因此,后面才想着把當點擊列表頁的時候,把列表頁整個數據都存在客戶端,當再次返回到列表頁的時候,通過判斷是否存在數據來確定是否需要加載新的數據,如果有數據直接將頁面顯示出來,然后定位到之前保存的scrolltop值得位置。
這種方法當然解決了手機各個瀏覽器直接新窗口打開的兼容性問題,唯一的弊端就在於可能要保存的數據量有點大,並且數據保存在客戶端可能存在的一些安全風險。
還有當時遺留的怎樣判斷是從詳情頁返回的問題,后來在github上面看到設置錨點的方法,大體的思路跟我想的一致。只不過我的是vue里面,因此我是把整個data數據轉成字符串保存了下來。錨點的具體實現方式是在列表頁滾動的時候記錄頁面的scroll-top值,然后把scroll-up的值設置錨點如(#scrollY = scroll-top)這樣如果是返回的頁面就可以在列表頁獲取到hash,hash存在就可以判斷是從詳情頁返回的頁面,如果是從其他頁面通過鏈接進入的就直接新請求數據,更新列表頁。
一些說明
- 列表滾動使用錨點獲取scrollTop值,標志是否返回了列表
- localStorage有過期時間,不用sessionStorage主要是因為有些安卓機的瀏覽器,跳頁面會獲取不到sessionStorage值,比如UA:Mozilla/5.0 (Linux; U; Android 5.0.2; zh-CN; Redmi Note 2 Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/40.0.2214.89 UCBrowser/11.2.0.880 Mobile Safari/537.36
- 只有返回列表才執行本地數據,index.html到list.html會重新請求數據。
- 缺點就是會將列表頁的數據都記錄下來,數據的風險性。
https://luchanan.github.io/detail2list/index.html 類似的github上的一個項目示例,非常感謝分享啦
其他的聯想
可能的解決方案:
- 改交互方式,把上拉刷新改為類似美團美食h5那樣,手動點下一頁,稍微簡單些,這樣每次都只記錄頁碼和滾動的位置就好了(但是一般產品不會同意)
- 列表記錄當前頁碼,到頂部請求上一頁,到底部請求下一頁。(好麻煩,先放棄,位置也不准確了)這種就是數據請求很混亂。
最后附上自己測試過的vue頁面中使用的代碼: