<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Push on Tarragon</title><link>https://tarrragon.github.io/blog/tags/push/</link><description>Recent content in Push on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Fri, 19 Jun 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/push/index.xml" rel="self" type="application/rss+xml"/><item><title>go vs push vs pushReplacement 的 UX 語意表</title><link>https://tarrragon.github.io/blog/ux-design/05-navigation-patterns/go-push-semantics/</link><pubDate>Fri, 19 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/ux-design/05-navigation-patterns/go-push-semantics/</guid><description>&lt;p>&lt;code>go&lt;/code>、&lt;code>push&lt;/code>、&lt;code>pushReplacement&lt;/code> 三種導航方法改變導航堆疊的方式不同，直接影響使用者按 back 時的行為。選擇哪種方法的依據是使用者的操作意圖 — 使用者期望按 back 時回到哪裡。&lt;/p>
&lt;h2 id="語意對照表">語意對照表&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>方法&lt;/th>
 &lt;th>堆疊行為&lt;/th>
 &lt;th>按 back 回到&lt;/th>
 &lt;th>使用者意圖&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;code>go(path)&lt;/code>&lt;/td>
 &lt;td>替換整個堆疊&lt;/td>
 &lt;td>無（離開 app）&lt;/td>
 &lt;td>切換到另一個工作區&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>push(path)&lt;/code>&lt;/td>
 &lt;td>推入堆疊頂端&lt;/td>
 &lt;td>前一個畫面&lt;/td>
 &lt;td>暫時離開，做完回來&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>pushReplacement&lt;/code>&lt;/td>
 &lt;td>替換堆疊頂端&lt;/td>
 &lt;td>更早的畫面&lt;/td>
 &lt;td>流程中的下一步（不可回退）&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="go切換工作區">go：切換工作區&lt;/h2>
&lt;p>&lt;code>go&lt;/code> 把整個導航堆疊替換成新的路徑。使用者按 back 不會回到操作前的畫面，因為堆疊已經被替換。&lt;/p>
&lt;p>適合場景：&lt;/p>
&lt;ul>
&lt;li>登入成功後到首頁（使用者不應該按 back 回到登入畫面）&lt;/li>
&lt;li>登出後到登入畫面（使用者不應該按 back 回到需要認證的畫面）&lt;/li>
&lt;li>從 onboarding 到主畫面（onboarding 完成後不需要回去）&lt;/li>
&lt;/ul>
&lt;p>誤用 &lt;code>go&lt;/code> 的後果：使用者期望按 back 回到前一個畫面但堆疊已空，按 back 直接離開 app。app_tunnel 修復時選擇 &lt;code>push('/enrollment')&lt;/code> 而非 &lt;code>go('/enrollment')&lt;/code>，讓使用者配對完成後能按 back 回首頁（&lt;a href="https://tarrragon.github.io/blog/ux-design/cases/missing-enrollment-entry-point/" data-link-title="U.C4 首頁缺配對入口按鈕、導航流未完整列出" data-link-desc="Flutter app 首頁只有 Connect Terminal 按鈕、沒有 Enroll Device 入口 — 使用者首次使用時找不到配對功能。根因是導航流設計只考慮了日常操作（UC-02 連線）、遺漏了首次操作（UC-01 配對）的入口">U.C4&lt;/a>）。&lt;/p>
&lt;h2 id="push暫時離開做完回來">push：暫時離開，做完回來&lt;/h2>
&lt;p>&lt;code>push&lt;/code> 在堆疊頂端加入新畫面。使用者按 back 回到前一個畫面。&lt;/p>
&lt;p>適合場景：&lt;/p>
&lt;ul>
&lt;li>從列表到詳細頁（看完回到列表）&lt;/li>
&lt;li>從首頁到配對畫面（配對完回首頁）&lt;/li>
&lt;li>從任何畫面到設定頁（改完設定回原畫面）&lt;/li>
&lt;/ul>
&lt;p>&lt;code>push&lt;/code> 是最常用的導航方法，因為多數導航都是「暫時去另一個畫面做事，做完回來」的模式。&lt;/p>
&lt;h2 id="pushreplacement流程中前進">pushReplacement：流程中前進&lt;/h2>
&lt;p>&lt;code>pushReplacement&lt;/code> 用新畫面替換堆疊頂端。堆疊深度不變，按 back 回到替換前畫面的前一個畫面（跳過被替換的畫面）。&lt;/p>
&lt;p>適合場景：&lt;/p>
&lt;ul>
&lt;li>步驟式流程：步驟 1 → pushReplacement 步驟 2 → pushReplacement 步驟 3。使用者在步驟 3 按 back 回到流程開始前的畫面，不會回到步驟 2 或 1。&lt;/li>
&lt;li>結果頁替換搜尋頁：搜尋結果替換搜尋條件頁，使用者按 back 回到搜尋前的畫面。&lt;/li>
&lt;/ul>
&lt;p>pushReplacement 的語意是「這一步完成後使用者不需要回到這裡」。用於不可回退的流程步驟。&lt;/p>
&lt;h2 id="選擇決策流程">選擇決策流程&lt;/h2>
&lt;p>對每個導航操作問一個問題：&lt;strong>使用者按 back 時，期望回到哪裡？&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>回到前一個畫面 → &lt;code>push&lt;/code>&lt;/li>
&lt;li>離開 app 或回到 app 的根畫面 → &lt;code>go&lt;/code>&lt;/li>
&lt;li>跳過當前畫面，回到更早的畫面 → &lt;code>pushReplacement&lt;/code>&lt;/li>
&lt;/ul>
&lt;p>這個決策應該在 UX 設計階段做，記錄在畫面狀態矩陣的「退出路徑」欄中。開發者實作時對照矩陣選擇正確的導航方法。&lt;/p>
&lt;h2 id="常見誤用">常見誤用&lt;/h2>
&lt;h3 id="用-go-做應該用-push-的導航">用 go 做應該用 push 的導航&lt;/h3>
&lt;p>「首頁 → 配對畫面」如果用 &lt;code>go&lt;/code>，使用者配對完成後按 back 離開 app 而非回到首頁。使用者期望的是「配對完成回首頁」（push 行為）。&lt;/p>
&lt;h3 id="用-push-做應該用-go-的導航">用 push 做應該用 go 的導航&lt;/h3>
&lt;p>「登入 → 首頁」如果用 &lt;code>push&lt;/code>，使用者在首頁按 back 回到登入畫面。使用者已經登入，不應該看到登入畫面。&lt;/p>
&lt;h3 id="用-push-做應該用-pushreplacement-的導航">用 push 做應該用 pushReplacement 的導航&lt;/h3>
&lt;p>步驟式流程中「步驟 1 → 步驟 2」如果用 &lt;code>push&lt;/code>，使用者在步驟 2 按 back 回到步驟 1。如果步驟 1 的操作不可逆（已經提交了資料），回到步驟 1 沒有意義。&lt;/p>
&lt;h2 id="下一步路由">下一步路由&lt;/h2>
&lt;ul>
&lt;li>Flutter GoRouter 的完整導航 API → &lt;a href="https://tarrragon.github.io/blog/ux-design/05-navigation-patterns/flutter-gorouter/" data-link-title="Flutter GoRouter 導航設計" data-link-desc="GoRouter 的路由定義、導航 API（go / push / pushReplacement）、redirect 機制和 ShellRoute 的使用場景">Flutter GoRouter 導航設計&lt;/a>&lt;/li>
&lt;li>導航模式分類 → &lt;a href="https://tarrragon.github.io/blog/ux-design/05-navigation-patterns/mobile-navigation-taxonomy/" data-link-title="Mobile 導航模式分類" data-link-desc="Push/pop stack / declarative router / tab bar / drawer — 四種 mobile 導航模式各自的適用場景和使用者心理模型">Mobile 導航模式分類&lt;/a>&lt;/li>
&lt;li>路由可達性檢查 → &lt;a href="https://tarrragon.github.io/blog/ux-design/01-screen-state-machine/route-reachability/" data-link-title="路由可達性檢查" data-link-desc="Router 定義的路由 vs UI 實際可達的路由 — 路由存在但 UI 不可達等於死程式碼的 UX 版本">ux-design 模組一 路由可達性&lt;/a>&lt;/li>
&lt;li>導航路徑的自動化測試 → &lt;a href="https://tarrragon.github.io/blog/testing/04-ui-automation/" data-link-title="模組四：自動化 UI 驗證" data-link-desc="Widget test 的狀態覆蓋策略、Playwright 驗證流程、螢幕狀態 coverage">testing 模組四 自動化 UI 驗證&lt;/a>&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p><code>go</code>、<code>push</code>、<code>pushReplacement</code> 三種導航方法改變導航堆疊的方式不同，直接影響使用者按 back 時的行為。選擇哪種方法的依據是使用者的操作意圖 — 使用者期望按 back 時回到哪裡。</p>
<h2 id="語意對照表">語意對照表</h2>
<table>
  <thead>
      <tr>
          <th>方法</th>
          <th>堆疊行為</th>
          <th>按 back 回到</th>
          <th>使用者意圖</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>go(path)</code></td>
          <td>替換整個堆疊</td>
          <td>無（離開 app）</td>
          <td>切換到另一個工作區</td>
      </tr>
      <tr>
          <td><code>push(path)</code></td>
          <td>推入堆疊頂端</td>
          <td>前一個畫面</td>
          <td>暫時離開，做完回來</td>
      </tr>
      <tr>
          <td><code>pushReplacement</code></td>
          <td>替換堆疊頂端</td>
          <td>更早的畫面</td>
          <td>流程中的下一步（不可回退）</td>
      </tr>
  </tbody>
</table>
<h2 id="go切換工作區">go：切換工作區</h2>
<p><code>go</code> 把整個導航堆疊替換成新的路徑。使用者按 back 不會回到操作前的畫面，因為堆疊已經被替換。</p>
<p>適合場景：</p>
<ul>
<li>登入成功後到首頁（使用者不應該按 back 回到登入畫面）</li>
<li>登出後到登入畫面（使用者不應該按 back 回到需要認證的畫面）</li>
<li>從 onboarding 到主畫面（onboarding 完成後不需要回去）</li>
</ul>
<p>誤用 <code>go</code> 的後果：使用者期望按 back 回到前一個畫面但堆疊已空，按 back 直接離開 app。app_tunnel 修復時選擇 <code>push('/enrollment')</code> 而非 <code>go('/enrollment')</code>，讓使用者配對完成後能按 back 回首頁（<a href="/blog/ux-design/cases/missing-enrollment-entry-point/" data-link-title="U.C4 首頁缺配對入口按鈕、導航流未完整列出" data-link-desc="Flutter app 首頁只有 Connect Terminal 按鈕、沒有 Enroll Device 入口 — 使用者首次使用時找不到配對功能。根因是導航流設計只考慮了日常操作（UC-02 連線）、遺漏了首次操作（UC-01 配對）的入口">U.C4</a>）。</p>
<h2 id="push暫時離開做完回來">push：暫時離開，做完回來</h2>
<p><code>push</code> 在堆疊頂端加入新畫面。使用者按 back 回到前一個畫面。</p>
<p>適合場景：</p>
<ul>
<li>從列表到詳細頁（看完回到列表）</li>
<li>從首頁到配對畫面（配對完回首頁）</li>
<li>從任何畫面到設定頁（改完設定回原畫面）</li>
</ul>
<p><code>push</code> 是最常用的導航方法，因為多數導航都是「暫時去另一個畫面做事，做完回來」的模式。</p>
<h2 id="pushreplacement流程中前進">pushReplacement：流程中前進</h2>
<p><code>pushReplacement</code> 用新畫面替換堆疊頂端。堆疊深度不變，按 back 回到替換前畫面的前一個畫面（跳過被替換的畫面）。</p>
<p>適合場景：</p>
<ul>
<li>步驟式流程：步驟 1 → pushReplacement 步驟 2 → pushReplacement 步驟 3。使用者在步驟 3 按 back 回到流程開始前的畫面，不會回到步驟 2 或 1。</li>
<li>結果頁替換搜尋頁：搜尋結果替換搜尋條件頁，使用者按 back 回到搜尋前的畫面。</li>
</ul>
<p>pushReplacement 的語意是「這一步完成後使用者不需要回到這裡」。用於不可回退的流程步驟。</p>
<h2 id="選擇決策流程">選擇決策流程</h2>
<p>對每個導航操作問一個問題：<strong>使用者按 back 時，期望回到哪裡？</strong></p>
<ul>
<li>回到前一個畫面 → <code>push</code></li>
<li>離開 app 或回到 app 的根畫面 → <code>go</code></li>
<li>跳過當前畫面，回到更早的畫面 → <code>pushReplacement</code></li>
</ul>
<p>這個決策應該在 UX 設計階段做，記錄在畫面狀態矩陣的「退出路徑」欄中。開發者實作時對照矩陣選擇正確的導航方法。</p>
<h2 id="常見誤用">常見誤用</h2>
<h3 id="用-go-做應該用-push-的導航">用 go 做應該用 push 的導航</h3>
<p>「首頁 → 配對畫面」如果用 <code>go</code>，使用者配對完成後按 back 離開 app 而非回到首頁。使用者期望的是「配對完成回首頁」（push 行為）。</p>
<h3 id="用-push-做應該用-go-的導航">用 push 做應該用 go 的導航</h3>
<p>「登入 → 首頁」如果用 <code>push</code>，使用者在首頁按 back 回到登入畫面。使用者已經登入，不應該看到登入畫面。</p>
<h3 id="用-push-做應該用-pushreplacement-的導航">用 push 做應該用 pushReplacement 的導航</h3>
<p>步驟式流程中「步驟 1 → 步驟 2」如果用 <code>push</code>，使用者在步驟 2 按 back 回到步驟 1。如果步驟 1 的操作不可逆（已經提交了資料），回到步驟 1 沒有意義。</p>
<h2 id="下一步路由">下一步路由</h2>
<ul>
<li>Flutter GoRouter 的完整導航 API → <a href="/blog/ux-design/05-navigation-patterns/flutter-gorouter/" data-link-title="Flutter GoRouter 導航設計" data-link-desc="GoRouter 的路由定義、導航 API（go / push / pushReplacement）、redirect 機制和 ShellRoute 的使用場景">Flutter GoRouter 導航設計</a></li>
<li>導航模式分類 → <a href="/blog/ux-design/05-navigation-patterns/mobile-navigation-taxonomy/" data-link-title="Mobile 導航模式分類" data-link-desc="Push/pop stack / declarative router / tab bar / drawer — 四種 mobile 導航模式各自的適用場景和使用者心理模型">Mobile 導航模式分類</a></li>
<li>路由可達性檢查 → <a href="/blog/ux-design/01-screen-state-machine/route-reachability/" data-link-title="路由可達性檢查" data-link-desc="Router 定義的路由 vs UI 實際可達的路由 — 路由存在但 UI 不可達等於死程式碼的 UX 版本">ux-design 模組一 路由可達性</a></li>
<li>導航路徑的自動化測試 → <a href="/blog/testing/04-ui-automation/" data-link-title="模組四：自動化 UI 驗證" data-link-desc="Widget test 的狀態覆蓋策略、Playwright 驗證流程、螢幕狀態 coverage">testing 模組四 自動化 UI 驗證</a></li>
</ul>
]]></content:encoded></item></channel></rss>