vue-router路由

vue-router文档

vue-router API

vue-router原码

定义

  1. 前端路由:对于单页面应用程序来说,主要通过URL中的hash(#号)来实现不同页面之间的切换,同时,hash有一个特点:HTTP请求中不会包含hash相关的内容;所以,单页面程序中的页面跳转主要用hash实现;
  2. 后端路由:对于普通的网站,所有的超链接都是URL地址,所有的URL地址都对应服务器上对应的资源;
  3. 在单页面应用程序中,这种通过hash改变来切换页面的方式,称作前端路由(区别于后端路由);

在 vue 中使用 vue-router

步骤:

  1. 导入 vue-router 组件类库,当导入vue-router包之后,在 window 全局对象中,就有了一个 路由的构造函数,叫做 VueRouter,在 new 路由对象的时候,可以为 构造函数,传递一个配置对象:
  2. 使用 router-link 组件来导航,默认渲染为一个a 标签;
  3. 使用 router-view 组件来显示匹配到的组件,专门用来当作占位符的,由路由规则匹配到的组件,就会展示到这个 router-view 中去;
  4. 创建组件的模板对象;
  5. 创建一个路由 router 实例,通过 routers 属性来定义路由匹配规则,这个规则对象身上有两个必须的属性:
    (1)属性1 : path, 表示监听哪个路由链接地址;
    (2) 属性2 :component, 表示如果路由是前面匹配到的 path ,则展示 component 属性对应的那个组件,omponent 的属性值,必须是一个 组件的模板对象, 不能是组件的引用名称;
    属性2也可以是:redirect,设置默认的路由地址
  6. 使用 router 将路由规则对象,注册到 vm 实例上,用来监听 URL 地址的变化,然后展示对应的组件。
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <script src="./lib/vue-2.4.0.js"></script>
  <script src="./lib/vue-router-3.0.1.js"></script>
  <style>
  </style>
</head>

<body>
  <div id="app">
    <!-- router-link 默认渲染为一个a 标签 -->
    <router-link to="/login" tag="span">登录</router-link>
    <router-link to="/register">注册</router-link>
    <!-- 这是 vue-router 提供的元素,用来当作占位符的,路由规则匹配到的组件,就会展示到这个 router-view 中去 -->
     <router-view></router-view>
  </div>

  <script>
    var login = {
      template: '<h1>登录组件</h1>'
    }
    var register = {
      template: '<h1>注册组件</h1>'
    }

    var routerObj = new VueRouter({
      routes: [
        // { path: '/', component: login },
        { path: '/', redirect: '/login' }, 
        { path: '/login', component: login },
        { path: '/register', component: register }
      ],
      linkActiveClass: 'myactive'
    })

    var vm = new Vue({
      el: '#app',
      router: routerObj
    });
  </script>
</body>
</html>

获取路由参数

  1. $route:获取当前路由的对象合属性
  • $route.path
    字符串,等于当前路由对象的路径,会被解析为绝对路径,如 “/login/id=12&name=ls” 。
  • $route.params
    对象,包含路由中的动态片段和全匹配片段的键值对{id: “12”, name: “ls”}
  • $route.query
    对象包含路由中查询参数的键值对。例如,对于/login/id=12&name=ls,会得到$route.query.name == ‘ls’ 。
  • $route.matched
    数组,包含当前匹配的路径中所包含的所有片段所对应的配置参数对象。
  • $route.name
    当前路径的名字,如果没有使用具名路径,则名字为空。
    在这里插入图片描述
  1. 传参的方式
  • 使用查询字符串,给路由传递参数,直接在链接?后面传参
    <router-link to="/login?id=10&name=zs">登录</router-link>
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <script src="./lib/vue-2.4.0.js"></script>
  <script src="./lib/vue-router-3.0.1.js"></script>
</head>

<body>
  <div id="app">
     <router-link to="/login?id=10&name=zs">登录</router-link>
     <router-link to="/register">注册</router-link>
     <router-view></router-view>
  </div>

  <script>
    var login = {
      template: '<h1>登录 --- {{ $route.query.id }} --- {{ $route.query.name }}</h1>',
      data(){
        return {
          msg: '123'
        }
      },
      created(){ 
         console.log(this.$route)
        // console.log(this.$route.query.id)
      }
    }

    var register = {
      template: '<h1>注册</h1>'
    }
    
    var router = new VueRouter({
      routes: [
        { path: '/login', component: login },
        { path: '/register', component: register }
      ]
    })

    var vm = new Vue({
      el: '#app',
      // router: router
      router
    });
  </script>
</body>
</html>

配置路由

  1. 在路由中定义参数
  • path:定义路由的地址,后可接 /:+参数名来定义路由的参数
  • component:路由的页面
  • name:定义路由的名字
 var router = new VueRouter({
      routes: [
        { path: '/login/:id/:name', component: Login, name: 'login' },
        { path: '/register', component: register }
        { path: '/home/goodscomment/:id', component: GoodsComment, name: 'goodscomment' }
      ]
    })
  1. 跳转路由的方法
  • 1.html界面中定义:按规定在链接/后面传参

     <router-link to="/login/12/ls">登录</router-link>
    
  • 2.在js中使用路由方法调准路由
    方法1:

     this.$router.push('/login/12/ls');
    

    方法2:

    this.$router.push({ name: "login", params: { id } });
    

    注意:此处的id为变量,如果是第二个参数,用逗号隔开

  1. 案例
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <script src="./lib/vue-2.4.0.js"></script>
  <script src="./lib/vue-router-3.0.1.js"></script>
</head>

<body>
  <div id="app">
    <router-link to="/login/12/ls">登录</router-link>
    <router-link to="/register">注册</router-link>
    <router-view></router-view>
  </div>

  <script>
    var login = {
      template: '<h1>登录 --- {{ $route.params.id }} --- {{ $route.params.name }}</h1>',
      created(){ // 组件的生命周期钩子函数
        console.log(this.$route.params.id)
      }
    }

    var register = {
      template: '<h1>注册</h1>'
    }

    var router = new VueRouter({
      routes: [
        { path: '/login/:id/:name', component: login },
        { path: '/register', component: register }
      ]
    })

    var vm = new Vue({
      el: '#app',
      data: {},
      methods: {},
      router
    });
  </script>
</body>
</html>

使用 children 属性实现路由嵌套

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <script src="./lib/vue-2.4.0.js"></script>
  <script src="./lib/vue-router-3.0.1.js"></script>
</head>
<body>
  <div id="app">
    <router-link to="/account">Account</router-link>
    <router-view></router-view>
  </div>

  <template id="tmpl">
    <div>
      <h1>这是 Account 组件</h1>
      <router-link to="/account/login">登录</router-link>
      <router-link to="/account/register">注册</router-link>
      <router-view></router-view>
    </div>
  </template>

  <script>
    var account = {
      template: '#tmpl'
    }
    var login = {
      template: '<h3>登录</h3>'
    }
    var register = {
      template: '<h3>注册</h3>'
    }

    var router = new VueRouter({
      routes: [
        {
          path: '/account',
          component: account,
          // 使用 children 属性,实现子路由,同时,子路由的 path 前面,不要带 / ,否则永远以根路径开始请求,这样不方便我们用户去理解URL地址
          children: [
            { path: 'login', component: login },
            { path: 'register', component: register }
          ]
        }
      ]
    })

    var vm = new Vue({
      el: '#app',
      router
    });
  </script>
</body>
</html>

一个路由地址放置多个组件

案例:命名视图实现经典布局

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <script src="./lib/vue-2.4.0.js"></script>
  <script src="./lib/vue-router-3.0.1.js"></script>
  <style>
    html,
    body {
      margin: 0;
      padding: 0;
    }

    .header {
      background-color: orange;
      height: 80px;
    }

    h1 {
      margin: 0;
      padding: 0;
      font-size: 16px;
    }

    .container {
      display: flex;
      height: 600px;
    }

    .left {
      background-color: lightgreen;
      flex: 2;
    }

    .main {
      background-color: lightpink;
      flex: 8;
    }
  </style>
</head>

<body>
  <div id="app">
    <router-view></router-view>
    <div class="container">
      <router-view name="left"></router-view>
      <router-view name="main"></router-view>
    </div>
  </div>

  <script>
    var header = {
      template: '<h1 class="header">Header头部区域</h1>'
    }
    var leftBox = {
      template: '<h1 class="left">Left侧边栏区域</h1>'
    }
    var mainBox = {
      template: '<h1 class="main">mainBox主体区域</h1>'
    }

    var router = new VueRouter({
      routes: [
        /* { path: '/', component: header },
        { path: '/left', component: leftBox },
        { path: '/main', component: mainBox } */

        {
        // components,带s,后面跟对象,跟着多个组件
          path: '/', components: {
            'default': header,
            'left': leftBox,
            'main': mainBox
          }
        }
      ]
    })
    
    var vm = new Vue({
      el: '#app',
      router
    });
  </script>
</body>
</html>

linkActiveClass

router-link有一个被选中的默认类样式,为linkActiveClass,若要修改被选中的链接路由样式,则修改此类样式即可,也可以给路由自定义一个linkActiveClass。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <script src="./lib/vue-2.4.0.js"></script>
  <script src="./lib/vue-router-3.0.1.js"></script>
  <style>
    /*2.设置选中样式*/
    .router-link-active,
    .myactive {
      color: red;
      font-size: 80px;
    }
  </style>
</head>

<body>
  <div id="app">
    <router-link to="/login" tag="span">登录</router-link>
    <router-link to="/register">注册</router-link>
    <router-view></router-view>
  </div>

  <script>
    var login = {
      template: '<h1>登录组件</h1>'
    }
    var register = {
      template: '<h1>注册组件</h1>'
    }

    var routerObj = new VueRouter({
      routes: [
        { path: '/', redirect: '/login' },
        { path: '/login', component: login },
        { path: '/register', component: register }
      ],
      linkActiveClass: 'myactive'//1.设置路由被被选中的类样式名
    })

    var vm = new Vue({
      el: '#app',
      router: routerObj
    });
  </script>
</body>

</html>

动态路由匹配

我们经常需要把某种模式匹配到的所有路由,全都映射到同个组件。例如,我们有一个 User 组件,对于所有 ID 各不相同的用户,都要使用这个组件来渲染。那么,我们可以在 vue-router 的路由路径中使用“动态路径参数”(dynamic segment) 来达到这个效果:
router/index.js

{
 path: '/course/:name',
 component: () => import('../views/Detail.vue')
}

About.vue

<router-link :to="`/course/${c.name}`">
	{{ c.name }} - {{ c.price | currency('¥') }}
</router-link>

通配符

适合做404页面路由

{
// 会匹配所有路径
path: '*',
component: () => import('../views/404.vue')
}

路由守卫

  1. 全局守卫
    vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航。有多种机会植入路由导航过程中:全局的, 单个路由独享的, 或者组件级的。

    router.beforeEach((to, from, next) => {
     // ...
     // to: Route: 即将要进入的目标 路由对象
     // from: Route: 当前导航正要离开的路由
     // next: Function: 一定要调用该方法来 resolve 这个钩子。
    })
    

    登录例子:

    //全局守卫定义
    router.beforeEach((to, from, next) => {
      if (to.meta.auth) {
        if (window.isLogin) {
          next()
       } else {  
          next('/login?redirect='+to.fullPath)   //回到登录页,且保存登录后要跳转的页面  
                                                 //fullPath:完成解析后的 URL,包含查询参数和 hash 的完整路径。
       }
     } else {
        next()
     }
    })
    
    //路由配置
    {
      path: '/about',
      meta: {
        auth: true    //meta.auth = true 表示该路由需要登录
     }
    },
    {
      path: '/login',
      component: () => import('../views/Login.vue')
    },
    
    <template>
     <div>
      <button @click="login" v-if="!isLogin">登录</button>
      <button @click="logout" v-else>登出</button>
     </div>
    </template>
    <script>
     export default {
      methods: {
       login() {
        window.isLogin = true    
        this.$router.push(this.$route.query.redirect)  //登录成功跳转redirect的地址
      },
       logout() {
        window.isLogin = false
      }
     },
      computed: {
       isLogin() {
        return window.isLogin
      }
     },
    }
    </script>
    

    注:$route.query表示 URL 查询参数。例如,对于路径 /foo?user=1,则有 $route.query.user == 1,如果没有查询参数,则是个空对象。

  2. 局部守卫
    可以路由配置上直接定义 beforeEnter 守卫:

    {
     path: '/about',
     name: 'about',
     // ...
     beforeEnter(to, from, next) {
      if (to.meta.auth) {
       if (window.isLogin) {
        next()
       } else {
        next('/login?redirect=' + to.fullPath)
       }
      } else {
       next()
       }
     }
    },
    
  3. 组件内守卫
    (1)可以在路由组件内直接定义以下路由导航守卫:
    beforeRouteEnter:进入路由之前,组件还没渲染
    beforeRouteUpdate:参数发生变化的时候
    beforeRouteLeave:离开路由

    // About.vue
    beforeRouteEnter(to, from, next) {
      if (window.isLogin) {
        next();
     } else {
        next("/login?redirect=" + to.fullPath);
     }
    

    (2)路由导航前的数据获取时机

    // 组件未渲染,通过给next传递回调访问组件实例
    beforeRouteEnter (to, from, next) {
      getPost(to.params.id, post => {  //getPost 获取数据的方法
        next(vm => vm.setData(post))   //next可以传回调函数,回调函数的形参是当前组件的实例,调取实例setData的方法去存储获取的异步数据
     })
    },
    
    // 组件已渲染,参数切换的情况,可以访问this直接赋值
    beforeRouteUpdate (to, from, next) {
    this.post = null  //数据置空
    getPost(to.params.id, post => { //重新获取数据
     this.setData(post)
        next()
     })
    },
    

    (3)路由导航后的数据获取时机

    created () {
      this.fetchData()  //正常在created中获取
    },
    watch: {
    	'$route': 'fetchData'  
    }
    

路由的动态配置

通过router.addRoutes(routes)方式动态添加路由

用户登录后根据用户的登录信息为他动态的添加路由,没有添加的路由就跳转到404页面

// 全局守卫修改为:要求用户必须登录,否则只能去登录页
router.beforeEach((to, from, next) => {
	if (window.isLogin) {
		if (to.path === '/login') {
			next('/')
		} else {
			next()
		}
		} else {
			if (to.path === '/login') {
				next()
			} else {
				next('/login?redirect=' + to.fullPath)
		}
	}
})
// Login.vue用户登录成功后动态添加/about
login() {
	window.isLogin = true;
	this.$router.addRoutes([
		{
			path: "/about", //...
		}
	]);
	const redirect = this.$route.query.redirect || "/";
	this.$router.push(redirect);
}

keepalive路由组件缓存

利用keepalive做组件缓存,保留组件状态,提高执行效率

参数:
include - 字符串或正则表达式。只有名称匹配的组件会被缓存。
exclude - 字符串或正则表达式。任何名称匹配的组件都不会被缓存。
max - 数字。最多可以缓存多少组件实例。最多缓存的组件实例,最老的缓存出去,最新的缓存进来。而不是缓存10个后不能缓存,保证资源的合理利用

把切换需要缓存的router-viewkeep-alive包裹起来,其中可以用include指定切换到哪些路由时才需要缓存,也可以exculde排除除这些组件外要缓存的对象,如果没有设置includeexculde则全部缓存。

范例:缓存about组件

<template>
    <div >
		<keep-alive include="about" max="10">
			<router-view></router-view>
		</keep-alive>
    </div>
</template>

<script>	

	export default {
		name:about,
		data() {
			return {
			}
		},
		activated(){
		},
		deactivated(){
		}
      
	}
</script>

注意:
1、使用includeexclude时要给组件设置name,这里的name不是路由配置的name,而是组件的name

<script>
	export default{
		name:"app",
		data(){
			return{
			}
		}
	}
</script>

2、缓存后的路由不再重新执行createdmounted等生命周期,这时候要用到两个特别的生命周期:激活状态activated、取消激活状态deactivated

<script>
	export default{
		activated(){
		
		},
		deactivated(){
		
		}
	}
</script>

在webpack中使用vue-router

  1. 运行npm i vue-router -D安装包;

  2. 导入模块

    import Vue from 'vue'
    import VueRouter from 'vue-router'
    
    Vue.use(VueRouter)
    
  3. 创建.vue组件
    app.vue

    <template>
      <div>
        <h1>这是 App 组件</h1>
    
      
        <router-link to="/account">Account</router-link>
        <router-link to="/goodslist">Goodslist</router-link>
    
        <router-view></router-view>
      </div>
    </template>
    
    <script>
    </script>
    
    
    <style>
    
    </style>
    
    

    account.vue

    <template>
      <div>
        <h1>这是 Account 组件</h1>
      </div>
    </template>
    
    
    <script>
    </script>
    
    <style>
    
    </style>
    
  4. 创建路由对象
    在入口文件main.js中导入.vue组件,然后创建路由对象

    import App from './App.vue'
    import account from './main/Account.vue'
    var router = new VueRouter({
      routes:[
        {path:'/account',compoent:account}
      ]
    })
    
  5. 在main.js中将路由对象挂在对vue实例中去

    var vm = new Vue({
        el: '#app',
        render:  c => c(login),
        router
      })
    

抽离路由模块

main.js

import Vue from 'vue'
// 1. 导入 vue-router 包
import VueRouter from 'vue-router'
// 2. 手动安装 VueRouter 
Vue.use(VueRouter)

// 导入 app 组件
import app from './App.vue'

// 导入 自定义路由模块
import router from './router.js'

var vm = new Vue({
  el: '#app',
  render: c => c(app), // render 会把 el 指定的容器中,所有的内容都清空覆盖,所以 不要 把 路由的 router-view 和 router-link 直接写到 el 所控制的元素中
  router // 4. 将路由对象挂载到 vm 上
})

// 注意: App 这个组件,是通过 VM 实例的 render 函数,渲染出来的, render 函数如果要渲染 组件, 渲染出来的组件,只能放到 el: '#app' 所指定的 元素中;
// Account 和 GoodsList 组件, 是通过 路由匹配监听到的,所以, 这两个组件,只能展示到 属于 路由的 <router-view></router-view> 中去;

router.js

import VueRouter from 'vue-router'

// 导入 Account 组件
import account from './main/Account.vue'
import goodslist from './main/GoodsList.vue'

// 导入Account的两个子组件
import login from './subcom/login.vue'
import register from './subcom/register.vue'

// 3. 创建路由对象
var router = new VueRouter({
  routes: [
    // account  goodslist
    {
      path: '/account',
      component: account,
      name:'account',
      children: [
        { path: 'login', component: login },
        { path: 'register', component: register }
      ]
    },
    { 
    	path: '/goodslist',
    	name:'goodslist',
    	 component: goodslist 		
    },
     { 
     	path: '/about', 
     	name:'about',
     	component: () => import('./main/about.vue')  //路由懒加载
      },
  ]
})

// 把路由对象暴露出去
export default router

路由懒加载

路由组件的懒加载能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。

() => import("../views/About.vue")
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值