如今的前端框架都会配备一个路由框架,vue有vue-router,react有react-router,angular也有angular-route,固然还有一些优秀插件来完善这些router的作更多的事情
npm i vue-router -S
import Vue from './view-global'; import VueRouter from 'vue-router' import App from './micro/app.vue' import Home from './micro/home' import Login from './micro/login' import About from './micro/about' import User from './micro/user' const router = new VueRouter({ mode: 'hash', routes: [ { path: '/home', name: 'Home', component: Home, meta: { title: "主页" } }, { path: '/login', name: 'Login', component: Login, meta: { title: "登陆" } }, { path: '/about', name: 'About', component: About, meta: { title: "关于" } }, { path: '/user', name: 'User', component: User, meta: { title: "用户" } } ] }) Vue.use(VueRouter) new Vue({ router, render: h => h(App), }).$mount('#app')
// app.vue <template> <div> <router-link to="/home" class="default-styles"> Home </router-link><br> <router-link to="/login" class="default-styles">Login</router-link><br> <router-link :to="{ path: '/about' }" class="default-styles">About</router-link><br> <router-link :to="{ name: 'User'}" class="default-styles">User</router-link> <router-view/> </div> </template> <style lang="less" scoped> .default-styles{ color: gray; font-size: 14px; } .router-link-active{ color: red; font-size: 26px; } </style>
vueRouter
会自动添加这个类,当点击Home和Login来回切换时,发现html结构,a 标签有一个样式类 .router-link-active
也在来回切换, 原来这是当router-link 处于选中状态时,所以咱们也能够利用这个类来改变选中时的状态,如选中时,让它变成红色,字体放大,若是未选中的也可在 router-link
直接给它添加一个 class
就能够了,好比自定义一个default-styles
html
属性有 to 、replace、 append、 tag、 active-class、 exact 、 event、 exact-active-class
前端
//字符串形式 <router-link to="/home">Home</router-link> //动态绑定 v-bind <router-link :to="'/home'">Home</router-link> <router-link :to="{ path: '/home' }">Home</router-link> <router-link :to="{ name: 'User'}">User</router-link> // 带参数 参数在url 获取参数 this.$route.query <router-link :to="{ name: 'User', query: {color: 'red' }}">query带参数</router-link> // 带参数 获取参数 this.$route.params <router-link :to="{ name: 'User', params: { color: 'red' }}">params带参数</router-link><br>
string
,默认值a
// 若是想要 <router-link> 渲染成某种标签,例如 <li> <router-link :to="'/home'" tag="li">Home</router-link> // 若是此时咱们想要在这个li标签中添加a标签,以下所示,能够不为a标签添加href属性便可哦 <router-link :to="{ name: 'User', params: { color: 'red' }}" tag="li"> <a>User</a> </router-link>
能够看渲染结果,在这种状况下,<a>
将做为真实的连接 (它会得到正确的 href 的),而 "激活时的CSS类名" 则设置到外层的 li
,看下方图片渲染结果:vue
string
默认值:router-link-active
// 修改激活选中的class类名 <router-link :to="{ name: 'User', query: {color: 'red' }}" active-class="activeClass">带参数</router-link>
// 全局修改 const router = new VueRouter({ mode: 'hash', linkActiveClass: 'activeClass', // 全局配置 routes: [ { path: '/home', name: 'Home', component: Home, meta: { title: "主页" } }, { path: '/login', name: 'Login', component: Login, meta: { title: "登陆" } }, { path: '/about', name: 'About', component: About, meta: { title: "关于" } }, { path: '/user', name: 'User', component: User, meta: { title: "用户" } } ] })
string
默认值:router-link-exact-active
配置当连接被精确匹配的时候应该激活的 class。注意默认值也是能够经过路由构造函数选项 linkExactActiveClass 进行全局配置的,看起来有点模糊,举个栗子,例如:react
<router-link to="/article" active-class="router-active"></router-link> // 当用户访问 /article/1 时会被激活为 <a href="#/article" class="router-active"></a> // 修改一下 <router-link to="/article" exact-active-class="router-active"></router-link> // 当用户访问 /article/1 时会被激活为,不会激活这个link的class <a href="#/article"></a>
router-link 默认状况下的路由是模糊匹配webpack
boolean
默认值:false
"是否激活" 默认类名的依据是 inclusive match (全包含匹配), 举个例子git
<li><router-link to="/">全局匹配</router-link></li> <li><router-link to="/" exact>exact严格匹配</router-link></li>
简单点说,第一个的话,若是地址是/a,或/a/b,……都会匹配成功,
但加上exact,只有当地址是/时被匹配,其余都不会匹配成功github
click
<router-link to="/article" event="mouseover">article</router-link>
若是咱们不加event
,那么默认状况下是当咱们点击article
的时候,跳转到相应的页面,但当咱们加上event
的时候,就能够改变触发导航的事件,好比鼠标移入事件web
boolean
默认值: false
设置 replace 属性的话,当点击时,会调用 router.replace() 而不是 router.push(),因而导航后不会留下 history 记录
push replace go 之间的区别ajax
router.push() :导航跑到不一样的URL,这个方法会向history栈添加一个新的记录,因此,当用户点击浏览器后退按钮时,则回到以前的url router.replace(): 跟router.push做用是同样的,可是,它不会向history添加新记录,而是跟它的方法名同样替换掉当前的history记录 router.go(n): 这个方法的参数是一个整数,意思是在history记录中向前或者后退多少步,相似window.history.Go(n)
boolean
默认值: false
设置 append 属性后,则在当前 (相对) 路径前添加基路径vue-router
<router-link to="a" append>Home</router-link>
设置append属性后,则在当前路径前添加基路径,例如,咱们从/a导航到一个相对路径b,若是没有配置append,则路径为/b,若是配了,则为/a/b
Router.beforeEach((to,from,next) => { window.document.title= to.meta.title })
使用前端路由,当切换到新路由时,想要页面滚到顶部,或者是保持原先的滚动位置,就像从新加载页面那样。 vue-router 能作到,并且更好,它让你能够自定义路由切换时页面如何滚动
// 2.8.0 新增 const router = new VueRouter({ scrollBehavior (to, from, savedPosition) { return new Promise((resolve, reject) => { setTimeout(() => { resolve({ x: 0, y: 0 }) }, 500) }) } })
利用路由元信息更细颗粒度地控制滚动,能够查看github官方列子
官方描述:当打包构建应用时,JavaScript 包会变得很是大,影响页面加载。若是咱们能把不一样路由对应的组件分割成不一样的代码块,而后当路由被访问的时候才加载对应组件,这样就更加高效了
{ path: '/user', name: 'User', component:require(['./micro/user'], resolve), meta: { title: "用户" } }
{ path: '/user', name: 'User', component: (resolve) => require(['./micro/user'], resolve), meta: { title: "用户" } } // 或者使用webpack的require.ensure技术 { path: '/user', name: 'User', component: resolve => require.ensure([], () => resolve(require('./micro/user')), 'user'), meta: { title: "用户" } }
按需加载会在页面第一次请求的时候,把相关路由组件块的js添加上;非按需加载则会把全部的路由组件块的js包打在一块儿。
当业务包很大的时候建议用路由的按需加载(懒加载),能够看我网站,打开控制台,当点击左侧菜单,会发现加载相对应的js包
require.ensure
参数解释第一个参数的依赖关系是一个数组,表明了当前须要进来的模块的一些依赖 第二个参数回调就是一个回调函数其中须要注意的是,这个回调函数有一个参数要求,经过这个要求就能够在回调函数内动态引入其余模块值得注意的是,虽然这个要求是回调函数的参数,理论上能够换其余名称,可是其实是不能换的,不然的的的的WebPack就没法静态分析的时候处理它 第三个参数errorCallback比较好理解,就是处理错误的回调 第四个参数chunkName则是指定打包的组块名称
// setTimeout 演示ajax const User= Vue.component('later', function (resolve) { setTimeout(function () { require(['./user.vue'], resolve) }, 3000); }); components: { User },
注意异步组件页面渲染的时候会跳动,使用下方高级异步组件,解决体验问题
// 更高级的异步组件 const AsyncComponent = () => ({ // 须要加载的组件 (应该是一个 `Promise` 对象) component: import('./MyComponent.vue'), // 异步组件加载时使用的组件 loading: LoadingComponent, // 加载失败时使用的组件 error: ErrorComponent, // 展现加载时组件的延时时间。默认值是 200 (毫秒) delay: 200, // 若是提供了超时时间且组件加载也超时了, // 则使用加载失败时使用的组件。默认值是:`Infinity` timeout: 3000 })
在浏览器中符号“#”,#以及#后面的字符称之为hash,用window.location.hash读取; 特色:hash虽然在URL中,但不被包括在HTTP请求中;用来指导浏览器动做,对服务端安全无用,hash不会重加载页面。 hash 模式下,仅 hash 符号以前的内容会被包含在请求中,如 https://www.vipbic.com,所以对于后端来讲,即便没有作到对路由的全覆盖,也不会返回 404 错误
简单实现hash
<div id="app"> <a class="hash a">#a.html</a> <a class="hash b">#b.html</a> </div> <script> // 再点击时注意观看浏览器地址栏 document.querySelectorAll('.hash').forEach( function(item, index) { item.addEventListener('click',(e)=>{ e.preventDefault() var link = item.textContent; location.hash= link; },false) }); //每点一下都会触发-hashchange window.addEventListener('hashchange', (e)=>{ console.log({ location: location.href, state: location.hash, e:e }) }); </script>
history采用HTML5的新特性;且提供了两个新方法:pushState(),replaceState()能够对浏览器历史记录栈进行修改,以及popState事件的监听到状态变动。 history 模式下,前端的 URL 必须和实际向后端发起请求的 URL 一致,如 http://www.xxx.com/items/id。后端若是缺乏对 /items/id 的路由处理,将返回 404 错误。Vue-Router 官网里如此描述:“不过这种模式要玩好,还须要后台配置支持……因此呢,你要在服务端增长一个覆盖全部状况的候选资源:若是 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面。
简单实现history
<div id="app"> <a class="api a">a.html</a> <a class="api b">b.html</a> </div> <script> // 再点击时注意观看浏览器地址栏 document.querySelectorAll('.api').forEach( function(item, index) { item.addEventListener('click',(e)=>{ e.preventDefault() var link = item.textContent; window.history.pushState({name:'api'},link,link); },false) }); // 下面说一下replaceState,其实跟pushState差很少,只是replaceState()修改当前历史记录条目,而不是建立一个新的。 // 在点击浏览器的后腿前进按钮时会触发-popstate window.addEventListener('popstate', (e)=>{ console.log({ location: location.href, state: e.state, e:e }) }); </script>
一、全局守卫
二、路由独享守卫
三、路由组件内的守卫
router.beforeEach 全局前置守卫 进入路由以前 router.beforeResolve 全局解析守卫(2.5.0+) 在beforeRouteEnter调用以后调用 router.afterEach 全局后置钩子 进入路由以后
例如从 /Home 页面跳转到 /User,全局导航守卫执行顺序大概是这样的
router.beforeEach((to, from, next) => { console.log('全局前置守卫: beforeEach') next() }) router.beforeResolve((to, from, next) => { console.log('全局解析守卫: beforeResolve') next() }) router.afterEach((to, from) => { console.log('全局后置钩子: afterEach') })
beforeRouteEnter 进入路由前, 在路由独享守卫后调用 不能 获取组件实例 this,组件实例还没被建立 beforeRouteUpdate (2.2) 路由复用同一个组件时, 在当前路由改变,可是该组件被复用时调用 能够访问组件实例 this beforeRouteLeave 离开当前路由时, 导航离开该组件的对应路由时调用,能够访问组件实例 this
beforeRouteEnter(to, from, next) { console.log('进入前:beforeRouteEnter') next() }, beforeRouteUpdate(to, from, next) { console.log('路由改变时:beforeRouteUpdate') // 好比user/123,切到user/456,才会触发 next() }, beforeRouteLeave(to, from, next) { console.log('离开前:beforeRouteLeave') next() }
例如从 /Home 页面跳转到 /User 而后在跳到Home,执行顺序大概是这样的
当我点击User
时回调用路由组件内守卫的beforeRouteEnter
,而后当我点击About
时,会调用beforeRouteLeave
也能够先获取数据,等数据获取出来才真正的显示页面。
须要注意:这里是拿不到组件this,由于没有经过next以前,组件没有被建立,因此用this === undefined
,不能调用上的任何东西
对于user/123,切到user/456 这样的路由页面,通常在mounted获取数据,第二次进来的时候,不会被触发(数据不会更新),因此数据的初始化获取不要用mounted,最好使用beforeRouteUpdate
,或者使用watch,watch相对比较麻烦,并且不能控制路由跳转的行为
beforeRouteLeave:能够用来表单填写成功,是否保存提示等
const router = new VueRouter({ mode: 'history', routes: [ { path: '/user', component: User, beforeEnter: function guardRoute(to, from, next) { // 参数用法什么的都同样,调用顺序在全局前置守卫后面,因此不会被全局守卫覆盖 console.log('导航路由独享守卫:beforeEnter') next() } } ] })
好比从User
组件跳转到About
组件所执行的顺序
一、beforeRouteLeave //路由组件内守卫
二、beforeEach // 全局前置守卫-路由进入开始
三、beforeEnter // 导航路由独享守卫
四、beforeRouteEnter // 路由组件内前置守卫
五、beforeResolve //全局解析守卫
六、afterEach // 全局后置钩子