對于web開發和移動端開發,兩者在路由上的處理是不同的。對于移動端來說,頁面的路由是相當于棧的結構的。vue-router與keep-alive提供的路由體驗與移動端是有一定差別的,因此常常開發微信公眾號的我想通過一些嘗試來將兩者的體驗拉近一些。
目標
問題
首先一個問題是keep-alive的行為。我們可以通過keep-alive來保存頁面狀態,但這樣的行為對于類似于APP的體驗是有些奇怪的。例如我們的應用有首頁、列表頁、詳情頁3個頁面,當我們從列表頁進入詳情頁再返回,此時列表頁應當是keep-alive的。而當我們從列表頁返回首頁,再次進入列表頁,此時的列表頁應當在退出時銷毀,并在重新進入時再生成才比較符合習慣。
第二個問題是滾動位置。vue-router提供了 scrollBehavior 來幫助維護滾動位置,但這一工具只能將頁面作為滾動載體來處理。但我在實際開發中,喜歡使用flex來布局頁面,滾動列表的載體常常是某個元素而非頁面本身。
使用環境
對于代碼能正確運行的環境,這里嚴格假定為微信(或是APP中內嵌的web頁面),而非通過普通瀏覽器訪問,即:用戶無法通過直接輸入url來跳轉路由。在這樣的前提下,路由的跳轉是代碼可控的,即對應于vue-router的push、replace等方法,而唯一無法干預的是瀏覽器的回退行為。在這樣的前提下,我們可以假定,任何沒有通過vue-router觸發的路由跳轉,是 回退1個記錄 的回退行為。
改造前
這里我列出改造前的代碼,是一個非常簡單的demo,就不詳細說了(這里列表頁有兩個列表,是為了展示改造后的滾動位置維護):
// css* { margin: 0; padding: 0; box-sizing: border-box;}html, body { height: 100%;}#app { height: 100%;}// html<div id="app"> <keep-alive> <router-view></router-view> </keep-alive></div>
// jsconst Index = { name: 'Index', template: `<div> 首頁 <div> <router-link :to="{ name: 'List' }">Go to List</router-link> </div> </div>`, mounted() { console.warn('Main', 'mounted'); },};const List = { name: 'List', template: `<div style="display: flex;flex-direction: column;height: 100%;"> <div>列表頁</div> <div style="flex: 1;overflow: scroll;"> <div v-for="item in list" :key="item.id"> <router-link style="line-height: 100px;display:block;" :to="{ name: 'Detail', params: { id: item.id } }"> {{item.name}} </router-link> </div> </div> <div style="flex: 1;overflow: scroll;"> <div v-for="item in list" :key="item.id"> <router-link style="line-height: 100px;display:block;" :to="{ name: 'Detail', params: { id: item.id } }"> {{item.name}} </router-link> </div> </div> </div>`, data() { return { list: new Array(10).fill(1).map((_,index) => { return {id: index + 1, name: `item${index + 1}`}; }), }; }, mounted() { console.warn('List', 'mounted'); }, activated() { console.warn('List', 'activated'); }, deactivated() { console.warn('List', 'deactivated'); },};const Detail = { name: 'Detail', template: `<div> 詳情頁 <div> {{$route.params.id}} </div> </div>`, mounted() { console.warn('Detail', 'mounted'); },};const routes = [ { path: '', name: 'Main', component: Index }, { path: '/list', name: 'List', component: List }, { path: '/detail/:id', name: 'Detail', component: Detail },];const router = new VueRouter({ routes,});const app = new Vue({ router,}).$mount('#app');
新聞熱點
疑難解答
圖片精選