Open Hugo-seth opened 6 years ago
在单页应用中,通常由前端来配置路由,根据不同的 url 显示不同的内容。想要知道这是如何做到的,首先得了解浏览器提供的两大 API:
window.location
location.href
location.hash
location.search
location.pathname
window.history
history.pushState()
history.replaceState()
history.go()
history.back()
history.forward()
我们先了解 location 对象,location 有很多的属性。我们可以通过改变其属性值修改页面的 url。我们在单页应用中需要做到的是改变 url 不刷新页面,location 接口提供以下两种方式可以做到:
而上面的列出其余两个属性 location.search 会直接刷新页面,这个就不解释了。但 location.pathname 照道理来说只改变 hash 应该是可以的,但实际上浏览器会编码这个属性值,所以无法直接赋带 # 号的值。
history 接口是 HTML5 新增的,它有五个方法可以改变 url 而不刷新页面。
上面只演示了三个方法,因为 history.back() 等价于 history.go(-1),history.forward() 则等价于 history.go(1),这三个接口等同于浏览器界面的前进后退。
history.go(-1)
history.go(1)
现在我们已经知道如何不刷新页面改变页面的 url。虽然页面没刷新,但我们要改变页面显示的内容。这就需要 js 监听 url 的变化从而达到我们的目的。
我们有两个事件可以监听 url 的改变:
hashchange 事件能监听 url hash 的改变。
hashchange
先要加上事件监听的代码:
window.addEventListener('hashchange', function(e) { console.log(e) })
然后就可以在页面的 console 里愉快的实验了:
从上图中我们可以知道不管是通过 location 接口直接改变 hash,还是通过 history 接口前进后退(只是 hash 改变的情况下),我们都可以监听到 url hash 的改变。但这个事件也只能监听 url hash 的变化。所以我们需要一个更强大的事件:popstate。
popstate
popstate 事件能监听除 history.pushState() 和 history.replaceState() 外 url 的变化。
先加上事件监听的代码:
window.addEventListener('popstate', function(e) { console.log(e) })
然后又可以在页面的 console 里愉快的实验了:
其实不止 history.pushState() 和 history.replaceState() 对 url 的改变不会触发 popstate 事件,当这两个方法只改变 url hash 时也不会触发 hashchange 事件。
我们都知道单页应用的路由有两种模式:hash 和 history。如果我们在 hash 模式时不使用 history.pushState() 和 history.replaceState() 方法,我们就只需要在 hashchange 事件回调里编写 url 改变时的逻辑就行了。而 history 模式下,我们不仅要在 popstate 事件回调里处理 url 的变化,还需要分别在 history.pushState() 和 history.replaceState() 方法里处理 url 的变化。而且 history 模式还需要后端的配合,不然用户刷新页面就只有 404 可以看了😆
所以 hash 模式下我们的工作其实是更简单的,但为什么现在都推荐用 history 模式呢?总不是 hash 模式下的 url 太丑了,毕竟这是个看脸的世界😂
不过 vue-router 在浏览器支持 pushState() 时就算是 hash 模式下也是用 history.pushState() 来改变 url,不知道有没什么深意?还有待研究...
vue-router
pushState()
在单页应用中,通常由前端来配置路由,根据不同的 url 显示不同的内容。想要知道这是如何做到的,首先得了解浏览器提供的两大 API:
window.location
location.href
location.hash
location.search
location.pathname
window.history
history.pushState()
history.replaceState()
history.go()
history.back()
history.forward()
window.location
我们先了解 location 对象,location 有很多的属性。我们可以通过改变其属性值修改页面的 url。我们在单页应用中需要做到的是改变 url 不刷新页面,location 接口提供以下两种方式可以做到:
location.href
赋值时只改变 url 的 hashlocation.hash
而上面的列出其余两个属性
location.search
会直接刷新页面,这个就不解释了。但location.pathname
照道理来说只改变 hash 应该是可以的,但实际上浏览器会编码这个属性值,所以无法直接赋带 # 号的值。window.history
history 接口是 HTML5 新增的,它有五个方法可以改变 url 而不刷新页面。
history.pushState()
history.replaceState()
history.go()
上面只演示了三个方法,因为
history.back()
等价于history.go(-1)
,history.forward()
则等价于history.go(1)
,这三个接口等同于浏览器界面的前进后退。如何监听 url 的变化
现在我们已经知道如何不刷新页面改变页面的 url。虽然页面没刷新,但我们要改变页面显示的内容。这就需要 js 监听 url 的变化从而达到我们的目的。
我们有两个事件可以监听 url 的改变:
hashchange
hashchange
事件能监听 url hash 的改变。先要加上事件监听的代码:
然后就可以在页面的 console 里愉快的实验了:
从上图中我们可以知道不管是通过 location 接口直接改变 hash,还是通过 history 接口前进后退(只是 hash 改变的情况下),我们都可以监听到 url hash 的改变。但这个事件也只能监听 url hash 的变化。所以我们需要一个更强大的事件:
popstate
。popstate
popstate 事件能监听除
history.pushState()
和history.replaceState()
外 url 的变化。先加上事件监听的代码:
然后又可以在页面的 console 里愉快的实验了:
其实不止
history.pushState()
和history.replaceState()
对 url 的改变不会触发popstate
事件,当这两个方法只改变 url hash 时也不会触发hashchange
事件。hash 模式和 history 模式
我们都知道单页应用的路由有两种模式:hash 和 history。如果我们在 hash 模式时不使用
history.pushState()
和history.replaceState()
方法,我们就只需要在hashchange
事件回调里编写 url 改变时的逻辑就行了。而 history 模式下,我们不仅要在popstate
事件回调里处理 url 的变化,还需要分别在history.pushState()
和history.replaceState()
方法里处理 url 的变化。而且 history 模式还需要后端的配合,不然用户刷新页面就只有 404 可以看了😆所以 hash 模式下我们的工作其实是更简单的,但为什么现在都推荐用 history 模式呢?总不是 hash 模式下的 url 太丑了,毕竟这是个看脸的世界😂
不过
vue-router
在浏览器支持pushState()
时就算是 hash 模式下也是用history.pushState()
来改变 url,不知道有没什么深意?还有待研究...