在做小程序項目的時候不難發現,使用navigateTo進行頁面跳轉后,點擊左上角或使用navigateBack返回,總是會按照之前的頁面進入倒序來展示頁面,那么問題來了,它們的跳轉規則是什么樣的呢?結合到實際業務中如何靈活運用呢?
什么是頁面棧?
首先先來了解一下小程序的運行環境: 小程序的運行環境分成渲染層和邏輯層,其中 WXML 模板和 WXSS 樣式工作在渲染層,JS 腳本工作在邏輯層。 小程序的渲染層和邏輯層分別由2個線程管理:渲染層的界面使用了WebView 進行渲染;邏輯層采用JsCore線程運行JS腳本。一個小程序存在多個界面,所以渲染層存在多個WebView線程,這兩個線程的通信會經由客戶端做中轉,邏輯層發送網絡請求也經由Native轉發,小程序的通信模型下圖所示。
我們可以看到,一個頁面使用一個 WebView 線程進行渲染。如果打開10個頁面,則會開啟 10 個 WebView 線程,此時內存中的十個webView線程我們稱之為頁面棧。當然小程序也會對這塊內存做限制,目前頁面棧的限制是不能超過十條。在小程序中頁面的路由是小程序框架本身控制的我們不要去手動管理, 小程序框架通過一個頁面棧的設計來管理所有的界面,當發生路由跳轉時,頁面棧就會做出相應的變化,在小程序頁面中通過 getCurrentPages() 就可以獲取到當前的頁面棧。
舉個栗子: 在父頁面中先獲取頁面棧:
const page = getCurrentPages(); // 父頁面 console.log('父頁面', page); //父頁面 復制代碼
通過wx.navigateTo跳轉子頁面,在子頁面中再獲取頁面棧:
const page = getCurrentPages(); // 子頁面 console.log('子頁面', page); //子頁面 復制代碼
輸出:
通過上面的例子可以看到,我們可以在頁面中通過 getCurrentPages() 方法來獲取當前頁面棧,并且獲取到的是一個數組,其中每個item都是每個頁面的Page對象(也就是在頁面中的this對象),由此我們引發一些思考……
路由跳轉時頁面棧表現?
當發生路由切換的時候,頁面棧的表現如下: 當發生路由切換的時候,頁面棧的表現如下:
情景頁面棧表現對應路由跳轉API小程序初始化新頁面入棧打開新頁面新頁面入棧wx.navigateTo 或使用組件頁面重定向當前頁面出棧,新頁面入棧wx.redirectTo 或使用組件頁面返回頁面不斷出棧,直到目標頁wx.navigateBack 或使用組件或用戶按左上角返回按鈕Tab 切換頁面全部出棧,只留下新的 Tab 頁面wx.switchTab 或使用組件 或用戶切換 Tab重加載頁面全部出棧,只留下新的頁面wx.reLaunch 或使用組件
我們在做項目的時候,巧妙運用路由跳轉和頁面棧會節省很多代碼,用戶體驗也會得到相應的提升,所以,在開始項目之前,定好頁面跳轉規則相當重要。
頁面棧的實際運用分析
下面我們分析一下頁面棧的變化過程,從分析中,我們需要明白的一個重要問題就是,當客戶按返回按鈕的時候究竟會跳轉到那個界面,這是我們分析頁面棧變化的的意義。 首先我們在頁面中調用兩次navigateTo,頁面棧情況如下
這時顯示的界面是pageC ,如果客戶在此時返回則會一切正常,回退的第一個界面是pageB,然后是pageA。但是如果在pageC 界面調用 wx.redirectTo({url:'pageD'}) 則情況就會不一樣,我們先看一下跳轉到pageD后頁面棧的情況如何。
根據棧的情況,我們可以分析出。如果使用 wx.redirectTo跳轉到pageD頁面,然后在回退的時候是不能再次回退到pageC的,而會直接回退到pageB。 通過上面對頁面棧的分析,我們可以看到棧的變化是會影響客戶回退頁面的順序的,所以根據自己的需求合理的使用不同的跳轉方法是非常重要的。如果使用不當就會導致跳轉混亂讓人摸不清頭腦 下面分析一種調轉重復頁面的情況:
如圖所示棧中出現了兩個相同的pageB界面,這個時候如果用戶按退出鍵就會出現一個頁面出現2次的情況,而且有一個界面的數據也是舊的數據。因此為了避免這個問題,我們應該在 PageC 頁面避免將 PageB重復壓入棧中,所以在pageC頁面使用wx.navigateBack({delta:1}); 進行頁面回退。而數據刷新的問題則在頁面的onShow函數中進行即可。
情景:確認訂單頁用戶點擊左上角返回
假設場景:用戶在商品詳情頁直接點擊“立即購買”下單購買,進入確認訂單頁,付款成功后跳轉到付款成功頁面,此時用戶點擊左上角箭頭進行了返回…… 處理:此時理應進入商品詳情頁,所以在確認訂單頁付款成功跳轉時應當將確認訂單頁出棧,新頁面入棧,那么就不可以使用wx.navigateTo來進行頁面跳轉,應當使用wx.redirectTo
情景:確認訂單頁用戶選擇已有收貨人
假設場景:在確認訂單頁,用戶需要選擇已有的收貨人,而已有收貨人列表在另一個頁面,那么用戶點擊“選擇收貨人”之后,使用wx.navigateTo跳轉到收貨人列表,點擊某個收貨人,帶參數返回確認訂單頁…… 處理:在確認訂單頁使用wx.navigateTo跳轉到收貨人列表,然后在收貨人列表里click事件中獲取頁面棧,直接往上一個頁面setData,然后退回上一個頁面,show code:
const page = getCurrentPages() if (page.length > 1) { page[page.length - 2].setData({ 收貨人: 選中的某個收貨人詳情 //[object] }) wx.navigateBack({ delta: 1 }) } 復制代碼
上面例子中提到過,在頁面中通過 getCurrentPages() 方法來獲取當前頁面棧,并且獲取到的是一個數組,其中每個item都是每個頁面的Page對象,那么我們就可以使用 setData 方法直接改變上一個頁面展示的數據,并且直接退回上一個頁面。
此時官方提醒:
雖然這種方法簡便,但是官方也給出提醒,頁面棧數據可以自行修改,但是!一定要慎重,否則會導致頁面狀態錯誤。
總結: 總覺得漏了點啥,又想不起來…… 官方文檔應有盡有,多研究官方文檔,多引發思考并手寫demo嘗試,總會有一些新的發現,另外,方法千萬條,隨便選一條,根據自己業務邏輯選用合適的方法。