aboutsummaryrefslogtreecommitdiff
path: root/files/zh-tw/web/api/history_api/index.html
blob: 2554fe6801776cce4a89f68ae22f2f4045263ddf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
---
title: 操控瀏覽器歷史紀錄
slug: Web/API/History_API
tags:
  - DOM
  - HTML5
  - History
translation_of: Web/API/History_API
---
<p>DOM {{ domxref("window") }} 物件透過 {{ domxref("window.history", "history") }} 物件,提供了進入瀏覽歷史的方式。他透過一些方便的屬性與方法,讓你可以在歷史紀錄中往上一步或往下一步移動,並且讓你——從 HTML5 開始——能操作歷史紀錄堆疊(history stack)的內容。</p>

<h2 id="在歷史紀錄中移動">在歷史紀錄中移動</h2>

<p>往前往後歷史紀錄可以用 <code>back()</code>, <code>forward()</code>, 和 <code>go()</code> 的方法。</p>

<h3 id="往前往後">往前往後</h3>

<p>要在歷史紀錄中往上一步移動,可以:</p>

<pre class="brush: js">window.history.back();
</pre>

<p>這完全等同於用戶在瀏覽器上點選「上一頁」按鈕。</p>

<p>同樣的,你也可以往下一步移動(等同於用戶點擊往後一頁的按鈕):</p>

<pre class="brush: js">window.history.forward();
</pre>

<h3 id="移動到特定的歷史紀錄">移動到特定的歷史紀錄</h3>

<p>你可以用 <code>go()</code> 方法來從頁面的 session history 紀錄中載入特定紀錄,以目前頁面的相對位置而定(目前的頁面想當然爾是 index 0)。</p>

<p>往前一頁(等同於呼叫 <code>back()</code>):</p>

<pre class="brush: js">window.history.go(-1);
</pre>

<p>往後一頁(等同於呼叫 <code>forward()</code>):</p>

<pre class="brush: js">window.history.go(1);
</pre>

<p>同樣的你也可以傳入 2,讓頁面直往後兩頁,依此類推。</p>

<p>你可以查看 length 這個屬性來取得目前瀏覽歷史的總數我:</p>

<pre class="brush: js">var numberOfEntries = window.history.length;
</pre>

<div class="note"><strong>備註:</strong>Internet Explorer 支援在 <code>go()</code> 中以 URL 的值作為參數;這不在標準中,Gecko 也不支援。</div>

<h2 id="加入和修改歷史紀錄">加入和修改歷史紀錄</h2>

<p>{{ gecko_minversion_header("2") }}</p>

<p>HTML5 加入了 <a href="/zh-TW/docs/Web/API/History/pushState"><code>history.pushState()</code></a><a href="/zh-TW/docs/Web/API/History_API#The_replaceState()_method"><code>history.replaceState()</code></a> 方法,讓你可以加入或修改歷史紀錄。這些方法都可以跟 {{ domxref("window.onpopstate") }} 事件一同應用。</p>

<p>使用 <code>history.pushState()</code>後,會改變 <a href="/zh-TW/docs/Web/API/XMLHttpRequest"><code>XMLHttpRequest</code></a> 時 HTTP 標頭中 referrer 的值。referrer 會是創造 <a href="/zh-TW/docs/Web/API/XMLHttpRequest"><code>XMLHttpRequest</code></a> 物件時的當前視窗文件(<code>this</code>)的 URL。</p>

<h3 id="pushState()_方法範例">pushState() 方法範例</h3>

<p>假設 <span class="nowiki">http://mozilla.org/foo.html</span> 執行了下面的 JavaScript:</p>

<pre class="brush: js">var stateObj = { foo: "bar" };
history.pushState(stateObj, "page 2", "bar.html");
</pre>

<p>這會讓網址列顯示 <span class="nowiki">http://mozilla.org/bar.html</span>,但不會讓瀏覽器去載入 <code>bar.html</code>,甚或去檢查 <code>bar.html</code> 存在與否。</p>

<p>假設現在使用者瀏覽到 <span class="nowiki">http://google.com</span>,然後點擊上一頁鈕。這時網址列會顯示 <span class="nowiki">http://mozilla.org/bar.html</span>,頁面會獲得 <code>popstate</code> 的事件(<em>state object</em> 會包含一份 <code>stateObj</code> 的副件)。頁面長得跟 <code>foo.html</code> 很像,但是可能在 <code>popstate</code> 事件執行中被修改。</p>

<p>如果我再點一次上一頁鈕, 網址會改變成為 <span class="nowiki">http://mozilla.org/foo.html</span>,且文件會得到另外一個 <code>popstate</code> 事件,此次會包含一個 null state object。同樣的,回上頁鈕不會改變文件的內容,只是文件可能會在 <code>popstate</code> 事件中被手動更新。</p>

<h3 id="pushState()_方法">pushState() 方法</h3>

<p><code>pushState()</code> 取用三個參數:一個 state 物件、title(目前忽略)與 URL(可選用)。我們來看看三個參數的細節之處:</p>

<ul>
 <li>
  <p><strong>state object</strong>——state object 是與 <code>pushState()</code> 建立的新瀏覽歷史紀錄有關的一個 JavaScript 物件。只要使用者到了新的 state ,一個 <code>popstate</code> 的事件就會被觸發,然後該事件的 <code>state</code> 屬性會包含一個複製的歷史紀錄的 state object。</p>

  <p>state 物件可以是任何可序列化的東西。因為 Firefox 儲存 state 物件到使用者的硬碟,當瀏覽器被重新啟動的時候,他們是可以被恢復的,因此我們加上了 640k 個字元的長度限制在一個以序列化表示的 state object。如果你傳送一個比這個更大的序列化表示的 state object 到 <code>pushState()</code>,這個方法會丟出一個例外事件。如果你需要更多空間的話,你可以試著用 <code>sessionStorage</code> 和/或 <code>localStorage</code></p>
 </li>
 <li>
  <p><strong>title</strong>——Firefox 目前忽略了這個參數,雖然他以後有可能會採用。如果以後改變了這個作法,傳送空白的字串應該還會是安全的。另外,你可以傳送一個短的標題來敘述你想要到的 state。</p>
 </li>
 <li>
  <p><strong>URL</strong>——這個新歷史紀錄的 URL 從這個參數做設定。值得注意的是,在 <code>pushState()</code> 被呼叫之後,瀏覽器並不會馬上嘗試載入這個 URL ,但是它可能在以後嘗試載入這個 URL ,例如使用者重新開啟瀏覽器之後。新的 URL 不一定需要為一個絕對的路徑;如果是相對路徑,會依據目前的URL來解析。新的 URL 需要與目前 URL 的 origin 是一樣的;否則,pushState() 會丟出一個錯誤的例外。這個參數是選擇性的;如果沒有被指定的話,他會設定為目前文件的 URL。</p>
 </li>
</ul>

<div class="note"><strong>備註:</strong>在 Gecko 2.0 {{ geckoRelease("2.0") }} 到 Gecko 5.0 {{ geckoRelease("5.0") }},是採用 JSON 來序列化這個傳送的物件。從 Gecko 6.0 {{ geckoRelease("6.0") }} 開始,這個物件是以 <a href="/zh-TW/DOM/The_structured_clone_algorithm">the structured clone algorithm</a> 序列化。這會允許更多種不同的物件可以被安全的傳送。</div>

<p>從某種意義上,呼叫 <code>pushState()</code> 與設定 <code>window.location = "#foo"</code> 是類似的,兩個都會去建立和啟用另一個和目前文件有關的歷史紀錄。但是 <code>pushState()</code> 有一些優勢:</p>

<ul>
 <li>新的 URL 可以是任何一個與目前的 URL 在同一個 origin 的 URL。相對來說,只有你設定 <code>window.location</code> 只修改 hash 時,才讓你保持在同一個 {{ domxref("document") }}</li>
 <li>如果你不想要的話,你可以不必去改變 URL 。相對來說,設定 <code>window.location = "#foo";</code> 只有在目前的 hash 不是 <code>#foo</code> 的時候,會建立一個新的歷史紀錄。</li>
 <li>你可以將任意的資料與你的新的歷史紀錄做關聯。用 hash-based 的方法,你需要將所有相關的資料編碼成一個短字串。</li>
 <li>If <code>title </code>is subsequently used by browsers, this data can be utilized (independent of, say, the hash).</li>
</ul>

<p>注意 <code>pushState()</code> 永遠不會造成一個 <code>hashchange</code> 事件被觸發,即使新的 URL 和舊的 URL 的不同處只有 hash 的部份也不會。</p>

<p>In a <a href="/en-US/docs/Mozilla/Tech/XUL">XUL</a> document, it creates the specified XUL element.</p>

<p>In other documents, it creates an element with a <code>null</code> namespace URI.</p>

<h3 id="replaceState()_方法">replaceState() 方法</h3>

<p><code>history.replaceState()</code> 的執行就像 <code>history.pushState()</code> ,除了 <code>replaceState() </code>是修改目前的歷史紀錄而不是創造一個新的。</p>

<p><code>replaceState() </code>很實用的時機是當你要更新目前歷史紀錄的 state object 或是URL來反應一些使用者的動作時。</p>

<div class="note"><strong>備註:</strong>在 Gecko 2.0 {{ geckoRelease("2.0") }} 到 Gecko 5.0 {{ geckoRelease("5.0") }},是採用 JSON 來序列化這個傳送的物件。從 Gecko 6.0 {{ geckoRelease("6.0") }} 開始, 這個物件是以 <a href="/zh-TW/DOM/The_structured_clone_algorithm">the structured clone algorithm</a> 序列化。這會允許更多種不同的物件可以被安全的傳送。</div>

<h3 id="replaceState()_方法範例">replaceState() 方法範例</h3>

<p>Suppose <span class="nowiki">http://mozilla.org/foo.html</span> executes the following JavaScript:</p>

<pre class="brush: js">var stateObj = { foo: "bar" };
history.pushState(stateObj, "page 2", "bar.html");
</pre>

<p>The explanation of these two lines above can be found at "Example of pushState() method" section. Then suppose <span class="nowiki">http://mozilla.org/bar.html</span> executes the following JavaScript:</p>

<pre class="brush: js">history.replaceState(stateObj, "page 3", "bar2.html");
</pre>

<p>This will cause the URL bar to display <span class="nowiki">http://mozilla.org/bar2.html</span>, but won't cause the browser to load <code>bar2.html</code> or even check that <code>bar2.html</code> exists.</p>

<p>Suppose now that the user now navigates to <span class="nowiki">http://www.microsoft.com</span>, then clicks back. At this point, the URL bar will display <span class="nowiki">http://mozilla.org/bar2.html. If the user now clicks back again, the URL bar will display http://mozilla.org/foo.html, and totaly bypass bar.html.</span></p>

<h3 id="popstate_事件">popstate 事件</h3>

<p>每次 active 的歷史紀錄被更動的時候,一個 <code>popstate</code> 事件會被發送到目前的 window。如果被啟用的歷史紀錄是由於呼叫 <code>pushState</code> 建立的或是呼叫 <code>replaceState</code> 所影響的,這個 <code>popstate</code> 事件的 <code>state</code> 屬性會含有一個歷史紀錄的 state object 的副本。</p>

<p>使用範例參閱 {{ domxref("window.onpopstate") }}</p>

<h3 id="讀取目前的_state">讀取目前的 state</h3>

<p>當你讀取頁面的時候,可能會有 non-null state 的物件。這會發生在,例如說,如果設定一個 state 物件(用 <code>pushState()</code> 或是 <code>replaceState()</code>),然後使用者重新啟動他的瀏覽器。當重新讀取你的頁面的時候,頁面會得到一個 <code>onload</code> 事件,但是沒有 <code>popstate</code> 事件。然而,如果你讀取了 <code> history.state</code> 屬性,你會得到像是 <code>popstate</code> 被觸發時,你會得到的 state object 。</p>

<p>像這樣使用 <code>history.state</code> 屬性,你可以讀取目前的歷史紀錄的<code>狀態</code>而不需要等待一個 <code>popstate</code> 事件:</p>

<pre class="brush: js">var currentState = history.state;
</pre>

<h2 id="範例">範例</h2>

<p>完整的 AJAX 網站範例 ,請參閱:<a href="/zh-TW/docs/DOM/Manipulating_the_browser_history/Example">Ajax navigation example</a></p>

<h2 id="規範">規範</h2>

<table class="standard-table">
 <tbody>
  <tr>
   <th scope="col">Specification</th>
   <th scope="col">Status</th>
   <th scope="col">Comment</th>
  </tr>
  <tr>
   <td>{{SpecName('HTML WHATWG', "browsers.html#history", "History")}}</td>
   <td>{{Spec2('HTML WHATWG')}}</td>
   <td>No change from {{SpecName("HTML5 W3C")}}.</td>
  </tr>
  <tr>
   <td>{{SpecName('HTML5 W3C', "browsers.html#history", "History")}}</td>
   <td>{{Spec2('HTML5 W3C')}}</td>
   <td>Initial definition.</td>
  </tr>
 </tbody>
</table>

<h2 id="瀏覽器相容性">瀏覽器相容性</h2>

<p>{{ CompatibilityTable() }}</p>

<div id="compat-desktop">
<table class="compat-table">
 <tbody>
  <tr>
   <th>Feature</th>
   <th>Chrome</th>
   <th>Edge</th>
   <th>Firefox (Gecko)</th>
   <th>Internet Explorer</th>
   <th>Opera</th>
   <th>Safari</th>
  </tr>
  <tr>
   <td>replaceState, pushState</td>
   <td>5</td>
   <td>{{CompatVersionUnknown}}</td>
   <td>{{ CompatGeckoDesktop("2.0") }}</td>
   <td>10</td>
   <td>11.50</td>
   <td>5.0</td>
  </tr>
  <tr>
   <td>history.state</td>
   <td>18</td>
   <td>{{CompatVersionUnknown}}</td>
   <td>{{ CompatGeckoDesktop("2.0") }}</td>
   <td>10</td>
   <td>11.50</td>
   <td>6.0</td>
  </tr>
 </tbody>
</table>
</div>

<div id="compat-mobile">
<table class="compat-table">
 <tbody>
  <tr>
   <th>Feature</th>
   <th>Android</th>
   <th>Edge</th>
   <th>Firefox Mobile (Gecko)</th>
   <th>IE Mobile</th>
   <th>Opera Mobile</th>
   <th>Safari Mobile</th>
  </tr>
  <tr>
   <td>replaceState, pushState</td>
   <td>{{ CompatUnknown() }}</td>
   <td>{{CompatVersionUnknown}}</td>
   <td>{{ CompatUnknown() }}</td>
   <td>{{ CompatUnknown() }}</td>
   <td>{{ CompatUnknown() }}</td>
   <td>{{ CompatUnknown() }}</td>
  </tr>
  <tr>
   <td>history.state</td>
   <td>{{ CompatUnknown() }}</td>
   <td>{{CompatVersionUnknown}}</td>
   <td>{{ CompatUnknown() }}</td>
   <td>{{ CompatUnknown() }}</td>
   <td>{{ CompatUnknown() }}</td>
   <td>{{ CompatUnknown() }}</td>
  </tr>
 </tbody>
</table>
</div>

<p><strong style="font-size: 2.143rem; font-weight: 700; letter-spacing: -1px; line-height: 1;">參見</strong></p>

<ul>
 <li>{{ domxref("window.history") }}</li>
 <li>{{ domxref("window.onpopstate") }}</li>
</ul>

<p>{{ languages( { "ja": "ja/DOM/Manipulating_the_browser_history"} ) }}</p>