什么是路由?网络原理中,路由指的是根据上一接口的数据包中的IP地址,查询路由表转发到另外一个接口,它决定的是一个端到端的网络路径。
web中,路由的概念也是相似,根据URL来将请求分配到指定的一个'端'。(即根据网址找到能处理这个URL的程序或模块)
使用vue.js构建项目,vue.js自己就能够经过组合组件来组成应用程序;当引入vue-router后,咱们须要处理的是将组件(components)映射到路由(routes),而后在须要的地方进行使用渲染。javascript
其所包含的功能有:html
当咱们经过 vue create 建立项目的的时候,会选择是否安装vue-router,项目建立后,在主组件App.vue中的HTML部分:vue
<script src="https://unpkg.com/vue/dist/vue.js"></script> <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script> <div id="app"> <h1>Hello App!</h1> <p> <!-- 使用 router-link 组件来导航. --> <!-- 经过传入 `to` 属性指定连接. --> <!-- <router-link> 默认会被渲染成一个 `<a>` 标签 --> <router-link to="/foo">Go to Foo</router-link> <router-link to="/bar">Go to Bar</router-link> </p> <!-- 路由出口 --> <!-- 路由匹配到的组件将渲染在这里 --> <router-view></router-view> </div>
上述代码中,<router-view/>是路由出口,路由匹配到的组件将渲染在这里。java
// 0. 若是使用模块化机制编程,导入Vue和VueRouter,要调用 Vue.use(VueRouter) // 1. 定义 (路由) 组件。 能够从其余文件 import 进来 const Foo = { template: '<div>foo</div>' } // 2. 定义路由每一个路由应该映射一个组件。 其中"component" 能够是经过 Vue.extend() 建立的组件构造器,或者,只是一个组件配置对象。 const routes = [ { path: '/foo', component: Foo }, ] // 3. 建立 router 实例,而后传 `routes` 配置 const router = new VueRouter({ routes }) // 4. 建立和挂载根实例。经过 router 配置参数注入路由,从而让整个应用都有路由功能 const app = new Vue({ router }).$mount('#app')
什么是动态路由?动态路由是指路由器可以自动的创建本身的路由表,而且可以根据实际状况的变化实时地进行调整。
一、在vue项目中,使用vue-router若是进行不传递参数的路由模式,则称为静态路由;若是可以传递参数,对应的路由数量是不肯定的,此时的路由称为动态路由。动态路由,是以冒号为开头的(:),例子以下:web
export default new Router({ routes: [ { path: '/', name: 'HelloWorld', component: HelloWorld }, { path: '/RouterComponents/:id', name: 'RouterComponents', component: RouterComponents } ] })
一个“路径参数”使用冒号 :
标记。当匹配到一个路由时,参数值会被设置到 this.$route.params
,能够在每一个组件内使用。vue-router
二、路由跳转,执行方式有两大类;
第一大类:router-link模式,直接把参数写在to属性里面:编程
<router-link :to="{name:'RouterComponents',params:{id:110}}">跳转</router-link>
第二大类:$router.push()模式,代码以下:浏览器
methods: { changeFuc (val) { this.$router.push({ name: 'RouterComponents', params: {id: val} }) } }
或者:服务器
methods: { changeFuc (val) { this.$router.push({ path: `/RouterComponents/${val}`, }) } }
vue项目中,界面一般由多个嵌套的组件构成;同理,URL中的动态路由也能够按照某种结构对应嵌套的各层组件:网络
const router = new VueRouter({ routes: [ { path: '/user/:id', component: User, children: [ { // 当 /user/:id/profile 匹配成功, // UserProfile 会被渲染在 User 的 <router-view> 中 path: 'profile', component: UserProfile }, { // 当 /user/:id/posts 匹配成功 // UserPosts 会被渲染在 User 的 <router-view> 中 path: 'posts', component: UserPosts } ] } ] })
常规参数只会匹配被 /
分隔的 URL 片断中的字符。若是想匹配任意路径,咱们可使用通配符 (*
):
{ // 会匹配全部路径 path: '*' } { // 会匹配以 `/user-` 开头的任意路径 path: '/user-*' }
当使用通配符路由时,请确保路由的顺序是正确的,也就是说含有通配符的路由应该放在最后。路由 { path: '*' }
一般用于客户端 404 错误。若是你使用了History 模式,请确保正确配置你的服务器。
声明式 | 编程式 |
---|---|
<router-link :to="..."> | router.push(...) |
想要导航到不一样的 URL,则使用 router.push
方法。这个方法会向 history 栈添加一个新的记录,因此,当用户点击浏览器后退按钮时,则回到以前的 URL。
当你点击 <router-link>
时,这个方法会在内部调用,因此说,点击 <router-link :to="...">
等同于调用 router.push(...)
。
// 字符串 router.push('home') // 对象 router.push({ path: 'home' }) // 命名的路由 router.push({ name: 'user', params: { userId: '123' }}) // 带查询参数,变成 /register?plan=private router.push({ path: 'register', query: { plan: 'private' }})
若是提供了 path,params 会被忽略
const userId = '123' router.push({ name: 'user', params: { userId }}) // -> /user/123 router.push({ path: `/user/${userId}` }) // -> /user/123 // 这里的 params 不生效 router.push({ path: '/user', params: { userId }}) // -> /user
因为咱们须要经过不一样的路由跳转到不一样的页面,这时给咱们的路由都加一个名字操做起来会比较方便
const router = new VueRouter({ routes: [ { path: '/user/:userId', name: 'user', component: User } ] })
<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>
有时候咱们须要一个布局,这时候,咱们就须要用到命名视图。
<router-view class="view one"></router-view> <router-view class="view two" name="a"></router-view> <router-view class="view three" name="b"></router-view>
const router = new VueRouter({ routes: [ { path: '/', components: { default: Foo, a: Bar, b: Baz } } ] })
{ path: '/settings', // 你也能够在顶级路由就配置命名视图 component: UserSettings, children: [{ path: 'emails', component: UserEmailsSubscriptions }, { path: 'profile', components: { default: UserProfile, helper: UserProfilePreview } }] }
在组件中使用 $route
会使之与其对应路由造成高度耦合,从而使组件只能在某些特定的 URL 上使用,限制了其灵活性。
使用 props
将组件和路由解耦:
取代与 $route 的耦合
const User = { template: '<div>User {{ $route.params.id }}</div>' } const router = new VueRouter({ routes: [ { path: '/user/:id', component: User } ] })
经过 props 解耦
const User = { props: ['id'], template: '<div>User {{ id }}</div>' } const router = new VueRouter({ routes: [ { path: '/user/:id', component: User, props: true }, // 对于包含命名视图的路由,你必须分别为每一个命名视图添加 `props` 选项: { path: '/user/:id', components: { default: User, sidebar: Sidebar }, props: { default: true, sidebar: false } } ] })
在某些状况下,当路由跳转前或跳转后、进入、离开某一个路由前、后,须要作某些操做,就可使用路由钩子来监听路由的变化
全局路由钩子:router.beforeEach
注册一个全局前置守卫
router.beforeEach((to, from, next) => { //会在任意路由跳转前执行,next必定要记着执行,否则路由不能跳转了 console.log('beforeEach') console.log(to,from) // next() }) // router.afterEach((to, from) => { //会在任意路由跳转后执行 console.log('afterEach') })
单个路由钩子:
只有beforeEnter,在进入前执行,to参数就是当前路由
routes: [ { path: '/foo', component: Foo, beforeEnter: (to, from, next) => { // ... } } ]
路由组件钩子:
beforeRouteEnter (to, from, next) { // 在渲染该组件的对应路由被 confirm 前调用 // 不!能!获取组件实例 `this` // 由于当守卫执行前,组件实例还没被建立 }, beforeRouteUpdate (to, from, next) { // 在当前路由改变,可是该组件被复用时调用 // 举例来讲,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候, // 因为会渲染一样的 Foo 组件,所以组件实例会被复用。而这个钩子就会在这个状况下被调用。 // 能够访问组件实例 `this` }, beforeRouteLeave (to, from, next) { // 导航离开该组件的对应路由时调用 // 能够访问组件实例 `this` }
附:完整的导航解析流程
beforeEach
守卫。beforeRouteUpdate
守卫 (2.2+)。beforeEnter
。beforeRouteEnter
。beforeResolve
守卫 (2.5+)。afterEach
钩子。beforeRouteEnter
守卫中传给 next
的回调函数。定义路由的时候能够配置 meta
字段:
const router = new VueRouter({ routes: [ { path: '/foo', component: Foo, children: [ { path: 'bar', component: Bar, // a meta field meta: { requiresAuth: true } } ] } ] })