黑马程序员技术交流社区

标题: Vue的路由及路由钩子函数的实现 [打印本页]

作者: 绮罗    时间: 2020-3-11 18:00
标题: Vue的路由及路由钩子函数的实现

什么是路由

什么是路由?网络原理中,路由指的是根据上一接口的数据包中的IP地址,查询路由表转发到另一个接口,它决定的是一个端到端的网络路径。


web中,路由的概念也是类似,根据URL来将请求分配到指定的一个'端'。(即根据网址找到能处理这个URL的程序或模块)
使用vue.js构建项目,vue.js本身就可以通过组合组件来组成应用程序;当引入vue-router后,我们需要处理的是将组件(components)映射到路由(routes),然后在需要的地方进行使用渲染。

其所包含的功能有:

1、基础路由

当我们通过 vue create 创建项目的的时候,会选择是否安装vue-router,项目创建后,在主组件App.vue中的HTML部分:



<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/>是路由出口,路由匹配到的组件将渲染在这里。

2、在router/index.js文件中



// 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')






3、动态路由

什么是动态路由?动态路由是指路由器能够自动的建立自己的路由表,并且能够根据实际情况的变化实时地进行调整。

1、在vue项目中,使用vue-router如果进行不传递参数的路由模式,则称为静态路由;如果能够传递参数,对应的路由数量是不确定的,此时的路由称为动态路由。动态路由,是以冒号为开头的(:),例子如下:



export default new Router({

routes: [

  {

   path: '/',

   name: 'HelloWorld',

   component: HelloWorld

  }, {

   path: '/RouterComponents/:id',

   name: 'RouterComponents',

   component: RouterComponents

  }

})






一个“路径参数”使用冒号 : 标记。当匹配到一个路由时,参数值会被设置到 this.$route.params,可以在每个组件内使用。

2、路由跳转,执行方式有两大类;

第一大类: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}`,

   })

  }

}






4、路由嵌套

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

    }


  }


})





5、捕获所有路由或404 NotFound路由

常规参数只会匹配被 / 分隔的 URL 片段中的字符。如果想匹配任意路径,我们可以使用通配符 (*):



{

// 会匹配所有路径

path: '*'

}

{

// 会匹配以 `/user-` 开头的任意路径

path: '/user-*'

}






当使用通配符路由时,请确保路由的顺序是正确的,也就是说含有通配符的路由应该放在最后。路由 { path: '*' } 通常用于客户端 404 错误。如果你使用了History 模式,请确保正确配置你的服务器。

6、编程式导航


[td]
声明式
编程式
<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






7、命名路由

由于我们需要通过不同的路由跳转到不同的页面,这时给我们的路由都加一个名字操作起来会比较方便



const router = new VueRouter({

routes: [

  {

   path: '/user/:userId',

   name: 'user',

   component: User

  }


})






1

<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>






8、命名视图

有时候我们需要一个布局,这时候,我们就需要用到命名视图。



<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

   }

  }


})






9、嵌套命名视图



{

path: '/settings',

// 你也可以在顶级路由就配置命名视图

component: UserSettings,

children: [{

  path: 'emails',

  component: UserEmailsSubscriptions

}, {

  path: 'profile',

  components: {

   default: UserProfile,

   helper: UserProfilePreview

  }


}






10、路由组件传参

在组件中使用 $route 会使之与其对应路由形成高度耦合,从而使组件只能在某些特定的 URL 上使用,限制了其灵活性。

使用 props 将组件和路由解耦:

取代与 $route 的耦合



通过 props 解耦




路由钩子

1、路由钩子

在某些情况下,当路由跳转前或跳转后、进入、离开某一个路由前、后,需要做某些操作,就可以使用路由钩子来监听路由的变化

全局路由钩子: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`

}






附:完整的导航解析流程

2、路由元信息

定义路由的时候可以配置 meta 字段:










欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2