路由中有三个基本的概念 route, routes, router:
1, route,它是一条路由,由这个英文单词也可以看出来,它是单数, Home按钮 => home内容, 这是一条route, about按钮 => about 内容, 这是另一条路由。
2, routes 是一组路由,把上面的每一条路由组合起来,形成一个数组。[{home 按钮 =>home内容 }, { about按钮 => about 内容}]
3, router 是一个机制,相当于一个管理者,它来管理路由。因为routes 只是定义了一组路由,它放在哪里是静止的,当真正来了请求,怎么办? 就是当用户点击home 按钮的时候,怎么办?这时router 就起作用了,它到routes 中去查找,去找到对应的 home 内容,所以页面中就显示了 home 内容。
4,客户端中的路由,实际上就是dom 元素的显示和隐藏。当页面中显示home 内容的时候,about 中的内容全部隐藏,反之也是一样。客户端路由有两种实现方式:基于hash 和基于html5 history api.
路由跳转等都需要vue-router
active-class是vue-router模块的router-link组件中的属性,用来做选中样式的切换;
在router目录下的index.js文件中,对path属性加上/:id
使用router对象的params.id 例如 : this.$route.params.id
vue-router 的导航钩子,主要用来作用是拦截导航,让他完成跳转或取消。
有三种方式可以植入路由导航过程中:
1.全局的
2.单个路由独享的
3组件级的
全局导航钩子主要有两种钩子:前置守卫、后置钩子,
注册一个全局前置守卫:
const router = new VueRouter({ ... });
router.beforeEach((to, from, next) => {
// do someting
});
这三个参数 to 、from 、next 分别的作用:
1.to: Route,代表要进入的目标,它是一个路由对象
2.from: Route,代表当前正要离开的路由,同样也是一个路由对象
3.next: Function,这是一个必须需要调用的方法,而具体的执行效果则依赖 next 方法调用的参数(next函数必须调用)
1).next():进入管道中的下一个钩子,如果全部的钩子执行完了,则导航的状态就是 confirmed(确认的)
2).next(false):这代表中断掉当前的导航,即 to 代表的路由对象不会进入,被中断,此时该表 URL 地址会 被重置到 from 路由对应的地址
3).next(‘/’) 和 next({path: ‘/’}):在中断掉当前导航的同时,跳转到一个不同的地址
4).next(error):如果传入参数是一个 Error 实例,那么导航被终止的同时会将错误传递给 router.onError() 注册过的回调
后置钩子注册:
router.afterEach((to, from) => {
// do someting
});
没有next()函数
在路由配置上定义,其参数的使用,和全局前置守卫是一样的
const router = new VueRouter({
routes: [
{
path: '/file',
component: File,
beforeEnter: (to, from ,next) => {
// do someting
}
}
]
});
组件内的导航钩子主要有这三种:beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave。他们是直接在路由组件内部直接进行定义的
const File = {
template: `<div>This is file</div>`,
beforeRouteEnter(to, from, next) {
// do someting
// 在渲染该组件的对应路由被 confirm 前调用
},
beforeRouteUpdate(to, from, next) {
// do someting
// 在当前路由改变,但是依然渲染该组件是调用
},
beforeRouteLeave(to, from ,next) {
// do someting
// 导航离开该组件的对应路由时被调用
}
}
1、切换路由,路由参数发生了变化,但是页面数据并未及时更新,需要强制刷新后才会变化。
2、不同路由渲染相同的组件时(组件复用比销毁重新创建效率要高),在切换路由后,当前组件下的生命周期函数不会再被调用。
解决方案:
1、使用 watch 监听 $route
watch: {
$route(to, from){
if(to != from) {
console.log("监听到路由变化,做出相应的处理");
}
}
}
2、向 router-view 组件中添加 key
<router-view :key="$route.fullPath"></router-view>
$route.fullPath 是完成后解析的URL,包含其查询参数信息和hash完整路径
vue-router有两种模式,hash模式和history模式
hash模式背后的原理是onhashchange事件,可以在window对象上监听这个事件.
随着history api的到来,前端路由开始进化了,前面的hashchange,你只能改变#后面的url片段,而history api则给了前端完全的自由.
通过history api,我们丢掉了丑陋的#,但是它也有个毛病:
在hash模式下,前端路由修改的是#中的信息,而浏览器请求时是不带它玩的,所以没有问题.但是在history下,你可以自由的修改path,当刷新时,如果服务器中没有相应的响应或者资源,会分分钟刷出一个404来。
vue异步组件
es提案的import()
webpack的require,ensure()
vue异步组件:
/* vue异步组件技术 */
{
path: '/home',
name: 'home',
component: resolve => require(['@/components/home'],resolve)
},{
path: '/index',
name: 'Index',
component: resolve => require(['@/components/index'],resolve)
},{
path: '/about',
name: 'about',
component: resolve => require(['@/components/about'],resolve)
}
es提案的import():
// 下面2行代码,指定了相同的webpackChunkName,会合并打包成一个js文件。 把组件按组分块
const Home = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '@/components/home')
const Index = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '@/components/index')
const About = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '@/components/about')
{
path: '/about',
component: About
}, {
path: '/index',
component: Index
}, {
path: '/home',
component: Home
}
webpack的require,ensure():
/* 组件懒加载方案三: webpack提供的require.ensure() */
{
path: '/home',
name: 'home',
component: r => require.ensure([], () => r(require('@/components/home')), 'demo')
}, {
path: '/index',
name: 'Index',
component: r => require.ensure([], () => r(require('@/components/index')), 'demo')
}, {
path: '/about',
name: 'about',
component: r => require.ensure([], () => r(require('@/components/about')), 'demo-01')
}
和方法一的区别是 使用vue的异步组件技术时一个组件生成一个js文件,webpack提供的require.ensure(),多个路由指定相同的chunkName,会合并打包成一个js文件。