> For the complete documentation index, see [llms.txt](https://lizh.gitbook.io/knowledge/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://lizh.gitbook.io/knowledge/research/03h5-ye-mian-tiao-zhuan-he-shua-xin.md).

# H5页面跳转和刷新

本文主要介绍前端 H5 页面的一些刷新、回退、替换、回退 + 刷新的方法。

## 页面跳转

#### a 标签

```html
<a href="https://example.com/path.index.html">跳转</a>
```

**禁止 a 标签跳转的方法：**

* href = "#"：`#` 是有特定意义的，`#` 后面紧接的是一个锚占名称，默认的锚点为 `#top`, 即页面顶部。
* href="###"：`###` 就是一个 `#` 和不存在的锚点 `##` 的组合，页面中找不到命名为 `##` 的锚点不会发生跳转，也就不会突然跳到页面顶部。`###` 只是一种使用者习惯，可以随便找一个跳转不到的标签作为命名。

  **### 会带来一些副作用，** 比如：会改变浏览器地址栏中的 URL；再如：如果 a 标签带了 `target="_blank"` ，会开一个新页面。
* href="javascript:;"：`javascript:` 指定要执行的 JavaScript 语句，`;` 表示为空语句。
* href="javascript: void(0);"：`void` 是一个操作符，该操作符指定要计算一个表达式但是不返回值。
* 直接删掉 href 属性。

#### location.href

一个可读可写的字符串，可设置或返回当前显示的文档的完整 URL。设置值可以跳转新网页。

```js
// 当前页面打开 URL 页面
location.href = ''
window.location.href = ''
this.location.href = ''
self.location.href = ''

// 在父页面打开新页面
parent.location.href = ''

// 在顶层页面打开新页面
top.location.href = ''
```

parent.location.href 和 top.location.href 在特定情况下有差异，如，当页面嵌套多个 iframe 时，parent 指向父窗口，top 指向最顶层的窗口。

#### Meta 标签

Meta 标签可以控制页面自动跳转，比如，5 秒后，自动跳转。

```html
<meta http-equiv="refresh" content="5; url=http://www.example.com">
```

#### location.assign(url)

触发窗口加载并显示指定的 URL 的内容，效果与 `location.href` 相当。

#### location.replace(url)

以给定的URL来替换当前的资源。

\*\*需要注意是：\*\*调用 `replace()` 方法后，当前页面不会保存到会话历史中，这样，用户点击回退按钮时，将不会再跳转到该页面。

#### window\.navigate(url)

非标准的方法，仅 IE 浏览器支持，其他浏览器不提供该方法。

## 页面刷新

#### Meta 标签

每 5 秒自动刷新：

```html
<meta http-equiv="refresh" content="5">
```

#### history.go(0)

history.go(delta) 方法从会话历史记录中加载特定页面。

delta 是负值表示向后移动，正值表示向前移动。如果未向该函数传参或传 0，则该函数与调用 `location.reload()` 具有相同的效果。

**注意：** history.go(0) 直接读取缓存数据，不会从服务器端获取数据。

#### location.reload()

location.reload() 方法用来刷新当前页面，就像刷新按钮一样。

该方法在跨域调用（执行该方法的脚本文件的域和 Location 对象所在页面的域不同）时，将会抛出 SECURITY\_ERROR DOMException 异常。

**location.reload() 没有参数：**

Firefox 对于该方法支持一个非标准的 forceGet boolean 参数 ，当值为 true 时，将强制 Firefox 从服务器加载页面资源。但是在其他浏览器中任何参数都是无效的。

boolean 参数不是标准规范，实际上，它从未成为 location.reload() 的规范。

#### document.execCommand('Refresh')

当一个HTML文档切换到设计模式时，document 暴露 execCommand 方法，该方法允许运行命令来操纵可编辑内容区域的元素。**已废弃，尽量避免使用。**

#### 其他方法

* location.replace(location)
* location.href = location.href
* location = location
* location.assign(location)
* window\.navigate(location)：非标准的方法，仅 IE 浏览器支持，其他浏览器不提供该方法。

## 页面回退

H5 退回前一个页面，或者前几个页面。

#### history.go(-1)、history.back()

history.go(-1)、history.back() 都是用于返回上一页，与用户点击浏览器左上角的返回按钮是一样效果。

回退到原页面，是从浏览器缓存读取，不需要重载页面资源。

#### document.referrer

document.referrer 返回的是一个 URI，当前页面就是从这个 URI 所代表的页面跳转或打开的。

```js
location.href = document.referrer
```

## 页面替换

H5 跳转到一个新页面，但不需要在 History 新增记录，即，跳转出去后，点击回退不需要再回该页面。

```js
history.replaceState(null, null, url)
location.replace(url)
```

replaceState() 方法修改当前会话历史记录：

```js
history.replaceState(stateObj, title, url)
```

* stateObj：是一个 JavaScript 对象，它与传递给 replaceState 方法的历史记录实体相关联。
* title：大部分浏览器忽略这个参数，将来可能有用。
* url：可选。历史记录实体的URL。\*\*新的 URL 跟当前的 URL 必须是同源；\*\*否则抛出异常。

注意：如果不加 `history.replaceState`，部分机型，可能会导致页面无法返回上一页。

## 页面回退+刷新

H5 退回前一个页面，并且刷新页面。比如：A -> B 页面，B 修改了跟 A 页面相关的一些数据，回退到 A 页面时，A 必需刷新页面上的数据。

解决方案如下：

#### document.referrer

```js
location.replace(document.referrer)
```

#### pageshow 事件（推荐）

```js
// persisted：只读属性，代表一个页面是否从缓存中加载的
window.addEventListener('pageshow', function(e) {
    if (e.persisted) {
        location.reload()
    }
})
```

```js
let isPageHide = false
window.addEventListener('pageshow', function () {
    if (isPageHide) {
        location.reload()
    }
})
window.addEventListener('pagehide', function () {
    isPageHide = true
})
```

**注意：** 即使页面刷新了，请求接口也可能有缓存。解决方法是：在 API URL中加上时间戳。如：`../path1/path2?v=${new Date().getTime()}`。

#### History对象

使用 History 对象修改当前历史记录。A -> B页面时，先替换当前历史记录点，然后再打开 B 页面。

```js
const json = {
    time: newDate().getTime()
}
history.replaceState(json, "", location.href + " &t=" + newDate().getTime())
location.href= url
```

#### popstate事件

```js
function(){
    window.addEventListener("popstate", function(e) {
        location.reload()
    }, false)
    const state = {
        title : "",
        url : "#"
    }
    history.replaceState(state, "", "#")
}
```

## 相关问题

### 页面回退不刷新

A -> B 页面，再回退到 A 页面，A页面不刷新。其原因可能是：

* B 页面回退到 A 页面，移动端部分浏览器 (如iphoneX) 默认不执行更新操作。
* B 页面回退到 A 页面，执行了更新操作。但 Ajax 请求从本地缓存中读取数据，导致页面数据不更新。
* App 跳转 B 页面，新开了窗口（类似于浏览器中新开了标签页）

### window\.location 和 document.location 有什么区别？

document 对象是 window 对象的一部分，是浏览器的 html 文档 。

```js
window.document === document
```

window 对象的 location 属性引用的是 location 对象，表示该窗口中当前显示文档的URL；document 对象的 location 属性也是引用了 location 对象。在没有内嵌 iframe 的情况下，两者是等同的：

```js
window.location === document.location //true
location.href === window.location.href === document.location.href
```

在嵌入 iframe 的情况下，最外层是相同的，但在 iframe 里面的 `document.location` 和 `window.location` 不同的。iframe 里面的`document.location` 只改变 iframe 部分。

### 如何禁止页面回退？

消除所有后退动作，包括 键盘、鼠标手势等产生的后退动作：

```js
history.pushState(null, null, document.URL)
window.addEventListener('popstate', function () {
    history.go(-1)
    history.pushState(null, null, document.URL)
})
```

### history.go、history.back 在 safari 无效？

`history.go` 加上 ?? `return false` 或者 `event.preventDefault()` ??：

```js
history.go(-1)
return false
```

`history.go(0)` 可改用 `window.location.reload()`。

## 参考资料

[MDN Location](https://developer.mozilla.org/zh-CN/docs/Web/API/Location)

[javascript刷新页面的几种方法](http://www.uxys.com/html/JavaScript/20190812/79345.html)

[window.location.href和window.open的几种用法和区别](https://www.cnblogs.com/Qian123/p/5345298.html)
