七、路由

一、路由的概念

路由的本质就是一种对应关系,根据不同的URL请求,返回对应不同的资源。

路由分为前端路由和后端路由:

  • 前端路由

    • 根据不同的事件来显示页面的内容,是事件与事件处理函数之间的对应关系

    • 本质:事件与事件处理函数之间的对应关系

  • 后端路由

    • 由服务器端进行实现并实现资源映射分发

    • 本质:URL请求地址与服务器资源之间的对应关系

二、前端路由模式

1、hash模式

  • hash路由模式:http://xxx.abc.com/#/xx,带有#号,后面就是hash值的变化

  • 改变后面的hash值,它不会向服务器发出请求,因此也就不会刷新页面

  • 每次hash值发生改变的时候,会触发hashchange事件,通过监听该事件,来知道hash值发生了哪些变化

1 window.addEventListener('hashchange', ()=>{
2   // 通过 location.hash 获取到最新的 hash 值
3   console.log(location.hash);
4 });

2、history模式

HTML5的History API为浏览器的全局history对象增加了该扩展方法。它是一个浏览器(bom)的一个接口,在window对象中提供了onpopstate事件来监听历史栈的改变,只要历史栈有信息发生改变的话,就会触发该事件。

1 history.pushState({},title,url); // 向历史记录中追加一条记录
2 history.replaceState({},title,url); // 替换当前页在历史记录中的信息。
3 window.addEventListener('popstate', function(event) {
4     console.log(event)
5 })

三、vue-router

1、安装vue-router

如果在vue-cli创建项目时没有勾选上vue-router选项,此时就需要手动来安装它(切记,要进入项目中再去运行这个指令):

npm i -S vue-router

package.json文件中dependencies选项中查看是否安装成功

2、路由文件的位置

  • 位置:src/router/index.js

  • 若创建项目时没有选择vue-router选项,需要自行创建

index.js

 1 import Vue from 'vue'
 2 import VueRouter from 'vue-router'
 3 
 4 // 引入组件
 5 import Home from '../views/Home.vue'
 6 
 7 // 使用vue-router
 8 Vue.use(VueRouter)
 9 
10 // 定义路由规则
11 const routes = [
12   {
13     path: '/',
14     name: 'Home',
15     component: Home
16   },
17   {
18     path: '/about',
19     name: 'About',
20     // route level code-splitting
21     // this generates a separate chunk (about.[hash].js) for this route
22     // which is lazy-loaded when the route is visited.
23     component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
24   }
25 ]
26 
27 // 创建路由实例
28 const router = new VueRouter({
29   mode: 'history',
30   base: process.env.BASE_URL,
31   routes
32 })
33 
34 export default router

3、路由懒加载:

需要加载时再加载,而不是一开始全部加载

  • 写法一

 1 import Vue from 'vue'
 2 import VueRouter from 'vue-router'
 3 
 4 // 使用vue-router
 5 Vue.use(VueRouter)
 6 
 7 // 路由懒加载
 8 const Home = () => import{'../views/Home.vue'}
 9 const About = () => import{'../views/About.vue'}
10 
11 // 定义路由规则
12 const routes = [
13   {
14     path: '/',
15     name: 'Home',
16     component: Home
17   },
18   {
19     path: '/about',
20     name: 'About',
21     component: About
22   }
23 ]
24 
25 // 创建路由实例
26 const router = new VueRouter({
27   mode: 'history',
28   base: process.env.BASE_URL,
29   routes
30 })
31 
32 export default router
  • 写法二
 1 import Vue from 'vue'
 2 import VueRouter from 'vue-router'
 3 
 4 // 使用vue-router
 5 Vue.use(VueRouter)
 6 
 7 // 定义路由规则
 8 const routes = [
 9   {
10     path: '/',
11     name: 'Home',
12     component: () => import(/* webpackChunkName: "home" */ '../views/Home.vue')
13   },
14   {
15     path: '/about',
16     name: 'About',
17     component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
18   }
19 ]
20 
21 // 创建路由实例
22 const router = new VueRouter({
23   mode: 'history',
24   base: process.env.BASE_URL,
25   routes
26 })
27 
28 export default router

4、在项目入口文件main.js中引入router

 1 import Vue from 'vue'
 2 import App from './App.vue'
 3 // 路径./router后面的index.js可以省略不写
 4 import router from './router'
 5 import store from './store'
 6 
 7 Vue.config.productionTip = false
 8 
 9 new Vue({
10   router,
11   store,
12   render: h => h(App)
13 }).$mount('#app')

5、App.vue文件中使用路由

 1 <template>
 2   <div id="app">
 3     <div id="nav">
 4       <router-link to="/" tag="button" replace>Home</router-link> |
 5       <router-link to="/about">About</router-link>
 6     </div>
 7     <router-view/>
 8   </div>
 9 </template>
10 
11 <style lang="scss">
12 #app {
13   font-family: Avenir, Helvetica, Arial, sans-serif;
14   -webkit-font-smoothing: antialiased;
15   -moz-osx-font-smoothing: grayscale;
16   text-align: center;
17   color: #2c3e50;
18 }
19 
20 #nav {
21   padding: 30px;
22 
23   a {
24     font-weight: bold;
25     color: #2c3e50;
26 
27     &.router-link-exact-active {
28       color: #42b983;
29     }
30   }
31 }
32 </style>

<router-link></router-link><router-view></router-view>

  • 它俩是vue封装好的组件

  • router-link的to属性匹配跳转的路径

  • router-link的tag属性可以指定渲染成的元素

  • router-link的replace属性不会留下history记录,因此后退返回键无法使用

  • router-view用来显示组件的位置(类似占位的作用)

6、路由重定向

概念:用户在访问地址 A 的时候,强制用户跳转到地址 B ,从而展示特定的组件页面

实现: 通过路由规则的redirect属性,指定一个新的路由地址,可以很方便地设置路由的重定向

 1 const routes = [
 2   { path: '/', redirect: '/user' },
 3   { path: '/user', component: User },
 4   {
 5     path: '/home',
 6     name: 'Home',
 7     component: Home
 8   },
 9   {
10     path: '/about',
11     name: 'About',
12     // route level code-splitting
13     // this generates a separate chunk (about.[hash].js) for this route
14     // which is lazy-loaded when the route is visited.
15     component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
16   }
17 ]

7、嵌套路由

比如我们有一个/user的路由,那么/users下面还可以添加子级路由,

如:/user/name/user/age等等,这样的路由情形称之为嵌套路由。

核心思想:在父路由组件的模板内容中添加子路由链接和子路由填充位(占坑),同时在路由规则处为父路由配置children属性指定子路由规则:

 1 routes: [
 2   { 
 3       path: "/user", 
 4       component: User,     //这个不能丢
 5       // 通过children属性为/user添加子路由规则
 6       children:[
 7           { path: "name", component: Name },
 8           { path: "age", component: Age },
 9       ]
10   }
11 ]
1 <!-- 需要在 User组件中定义一个router-view 用于嵌套路由的渲染显示 -->
2 <router-view></router-view>

8、动态路由

所谓动态路由就是路由规则中有部分规则是动态变化的,不是固定的值,需要去匹配取出数据(即路由参数)。

 1 // 传递参数id
 2 const router = new VueRouter({
 3     // routes是路由规则数组 
 4     routes: [
 5         { path: '/user/:id', component: User },
 6         // 此处的“:”只是在声明的时候写,在使用的时候不需要写“:”
 7     ]
 8 })
 9 
10 // 组件中获取id值(注意拼写)
11 const User = {
12     template: '<div>User ID is {{$route.params.id}}</div>'
13 }

使用:

1 export default{
2     methods: {
3         show: function(id){
4             this.$router.push('/film/showdetail/' + id)
5         }
6     }
7 }
8 // 如果路由规则里声明需要传递参数,但是实际使用的时候没传递参数会影响落地页的显示,显示成白板(但是不报错)。

在实际开发的时候会有可能需要传参也可能不需要传参的情况,这个时候需要用到可选路由参数点,需要在原有的路由参数声明位置后面加上个?即可。

{ path: "showdetail/:id?", component: ShowDetail },

9、命名路由

顾名思义就是给路由起名字(第2小节代码routes数组中对象的name属性)

10、参数传递

父组件

1 <template>
2   <div id="app">
3     <router-link :to="{path: '/profile', query: {name: 'zhangsan', age: 18}}">profile</router-link> 
4     <router-view/>
5   </div>
6 </template>

子组件接收

1 <template>
2   <div id="profile">
3     <div>{{$route.query.name}}</div>
4     <div>{{$route.query.age}}</div>
5   </div>
6 </template>

11、路由守卫

导航守卫就是路由跳转过程中的一些钩子函数,这个过程中触发的这些函数能让你操作一些其它事情时,可以进行过滤操作,这就是导航守卫。

  • 全局守卫

 1 // 全局前置守卫  路由规则文件中定义
 2 // 当一个导航触发时,触发前置守卫,
 3 // to: Route: 即将要进入的目标 路由对象
 4 // from: Route: 当前导航正要离开的路由
 5 // next: Function: 一定要调用该next方法,否则路由不向下执行。
 6 router.beforeEach((to, from, next) => {
 7   // ...
 8 })
 9 
10 // 全局后置钩子
11 // 此钩子不会接受 next 函数也不会改变导航本身
12 router.afterEach((to, from) => {
13   // ...
14 })
  • 组件内守卫
 1 // 可以在路由组件内直接定义以下路由导航守卫,手动更改地址栏中的路由不会触发`beforeRouteUpdate`和`beforeRouteLeave`钩子函数。
 2 const Foo = {
 3   template: `...`,
 4   beforeRouteEnter (to, from, next) {
 5     // 在渲染该组件的对应路由被 confirm 前调用
 6     // 不!能!获取组件实例 `this`(这个时候还没有进入到to对应的组件中,所以拿不到this)
 7     // 因为当守卫执行前,组件实例还没被创建
 8   },
 9   beforeRouteUpdate (to, from, next) {
10     // 在当前路由改变,但是该组件被复用时调用
11     // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
12     // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
13     // 可以访问组件实例 `this`
14   },
15   beforeRouteLeave (to, from, next) {
16     // 导航离开该组件的对应路由时调用
17     // 可以访问组件实例 `this`
18   }
19 }

四、导航方式

1、声明式导航

通过点击链接实现的导航方式,例如HTML中的“<a>”标签,Vue中的“<router-link>”所实现的。

1 <router-link to="path">xxx</router-link>
2 <!-- 
3     to 要跳转到的路由规则  string|object
4     to="users"
5     :to="{path:'path'}"
6 -->

2、编程式导航

通过调用JavaScript形式API实现的导航方式,例如location.href实现的跳转效果

1 this.$router.push("/login");
2 this.$router.push({ path:"/login" });
3 this.$router.replace({ path:"/login" });
4 this.$router.push({ path:"/login", query:{ username:"jack" }});
5 this.$router.push({ name:'user', params: { id:123 }});
6 this.$router.go( n );//n为数字  负数为回退

注:编程式导航在跳转到与当前地址一致的URL时会报错,但这个报错不影响功能,可以在路由入口文件index.js中添加如下代码解决该问题

1 const originalPush = VueRouter.prototype.push;
2 VueRouter.prototype.push = function push(location) {
3     return originalPush.call(this, location).catch((err) => err);
4 };

 

 

posted @ 2022-07-21 22:03  大米饭盖饭  阅读(80)  评论(0)    收藏  举报