hash模式 & history模式
单页应用最强大的地方在于:虽然我们通过点击router-link等方式令文档更新了,但是页面并没有被重新加载。
我们可以用这段代码观察页面有没有重新加载:
mounted() {
(function task(i = 0) {
console.log(i);
setTimeout(() => task(++i), 200);
})();
},
我们知道单页有两种路由模式,在实例化Router对象时指定路由模式:
new Router({
mode: 'history',
routes: [
{path: '/', component: App},
],
});
history模式下,如何保证页面不被重新加载呢?请先了解router-link在history模式下的工作原理。
在 HTML5 history 模式下,router-link 会守卫点击事件,让浏览器不再重新加载页面。
history.pushState(state, title, url)函数
history.pushState用于在浏览历史中添加历史记录,但是并不触发跳转,此方法接受三个参数,依次为:
state 一个与指定网址相关的状态对象,popstate事件触发时,该对象会传入回调函数。如果不需要这个对象,此处可以填null。
title 新页面的标题,但是所有浏览器目前都忽略这个值,因此这里可以填null。
url 新的网址,必须与当前页面处在同一个域。浏览器的地址栏将显示这个网址。
当我们点击router-link时,实际上是调用了router.push()
函数,这个函数就是history.pushState()
实现的。
因此,我们如果需要保留a标签的href实现单页内跳转,可以拦截浏览器默认行为,即在@click.prevent事件中调用router.push()
即可。
<a href="/topath" @click=go>Click Me</a>
methods: {
go(event) {
event.preventDefault();
// const dist = (event.target.href.split(/https?://[^/]+/)[1]);
// console.log(dist);
const dist = event.target.getAttribute('href');
if (dist.match(/^https?:///)) {
return document.location.href = dist;
}
this.$router.push(dist);
},
},
更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。
为了解决这个问题,Vue.js 为 v-on 提供了事件修饰符。之前提过,修饰符是由点开头的指令后缀来表示的。
<a href="/topath" @click.prevent=go>Click Me</a>
methods: {
go(event) {
// event.preventDefault(); 不需要在代码中取消浏览器默认行为
...
this.$router.push(dist);
},
},
webpack-dev-server配合history模式
webpack.config.js
devServer: {
contentBase: home + '/dist',
//
historyApiFallback: {
index: '/index.html',
},
},
/**
ℹ 「wds」: Content not from webpack is served from /home/kasumi/vue/SingePageApp/new/apps/mybrowser/dist
ℹ 「wds」: 404s will fallback to /index.html
*/
rewrites实现路由:
historyApiFallback: {
index: 'build/index.html',
rewrites: [
{ from: /^/admin/, to: 'build/admin.html' },
],
},
<router-link>
与 <a>
的恩怨情仇
router-link默认渲染一个<a>
标签,可以通过tag参数改变,使得span等也具有点击后在页内跳转的能力。
对于子组件写死的<a>
标签,只能在事件中使用js来push跳转了。