详解Vue Router的要点知识

路由

1.router-link

  • <router-link to="/路由路径/参数" tag="button">xxx</router-link>:用于跳转路由;
    to代表跳转的路由;
    tag代表router-link被渲染成什么标签;默认会被渲染成一个a标签;
  • <router-view></router-view>:用于显示组件;
    当组件进行切换时,会将组件销毁;

创建路由四步

<body>
<div id="app">
    <router-link to="/home" tag="button">首页</router-link>
    <router-link to="/login" tag="button">登录</router-link>
    <router-view></router-view>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script src="node_modules/vue-router/dist/vue-router.js"></script>
<script>
    //1.创建(路由)组件;
    let home = {
        data(){
            return{con:'首页'}
        },
        template:'<div>{{con}}</div>'
    }
    let login = {
        data(){
            return{logo:'登录'}
        },
        template:'<div>{{logo}}</div>'
    }
    //2.配置路由映射表:根据路由不同,显示不同的组件;
    let routes = [
        { path: '/home', component: home },
        { path: '/login', component: login }
    ]
    //3.注册映射表:创建 router 实例,然后传 `routes` 配置;
    let router = new VueRouter({
        //routes:routes //名字相同可以写一个,简化
        routes
    })
    //4.路由挂载到根实例
    let vm = new Vue({
        el:'#app',
        router
    })
</script>
</body>

通过注入路由器,我们可以在任何组件内通过 this.$router 访问路由器,也可以通过 this.$route 访问当前路由:

let list = {
    methods:{
        goBack(){
            this.$router.go(-1);
        }
    },
    computed:{
	    username () {
			return this.$route.params.username;
	    }
    }
}

2. 路由的方法

  1. $router.push("路径") :直接跳转到当前路径对应的路由上;
    this.$router.push("/list");
  2. $router.back() : 回退到上一次路由上;
    this.$router.back();
  3. $router.go() : 返回上一级;
    this.$router.go(-1);

back和go的区别

  • back():只能一级一级地返回;
  • go(n):当go的参数n为正数时,表示前进n级;当n为负数时,表示返回n级;

replace和push的区别
router.replace跟 router.push 很像,唯一的不同就是,replace不会向 history 添加新记录,而是替换掉当前的 history 记录。

<div id="app">
    <router-link to="/home">首页</router-link>
    <router-link to="/list">列表页</router-link>
    <router-view></router-view>
</div>
<script src="../vue.js"></script>
<script src="../vue-router.js"></script>
<script>
let home = {
    methods: {
        goList(){
            console.log(this);//this指向当前的组件
            this.$router.push("/list");
        }
    },
    template:`<div><button @click="goList">去列表页</button></div>`
}
let list = {
    methods:{
        goBack(){
            this.$router.go(-1);//this.$router.back();
        }
    },
    template:`<div><button @click="goBack">去首页</button></div>`
}
const routes = [{path:'/home',component:home},
				{path:'/list',component:list}];
const router = new VueRouter({
    routes
})
let vm = new Vue({
    el:'#app',
    router
})
</script>

3. 嵌套路由

  • 在组件中,有children属性属性值是一个数组;里面配置了子路由;routes中子路由不需要带父路由的路径地址,同时不需要加/;当子路由进行匹配时,会自动将父路由和/添加到子路由的前面,进行匹配;
  • 二级路由不能直接配置到routes表下面,应该找到它的父路由,配置到父路由的children属性上;否则,父路由也会消失;
 let routes = [
        {path:"/",component:home},
        {path:"/home",component:home},
        {path:"/list",component:list,children:[
            {path:"detail",component:detail},
            {path:"login",component:login}
        ]}
    ];

4. 命名路由

通过一个名称来标识一个路由显得更方便一些,特别是在链接一个路由,或者是执行一些跳转的时候。你可以在创建 Router 实例的时候,在 routes 配置中给某个路由设置名称。

const routes = [
	{path:"/home",component:home,name:"first"}
]

要链接到一个命名路由,可以给 router-link 的 to改成动态的属性:to={name:组件的name名称}

<router-link :to="{name:'first'}">首页</router-link>

5. 编程式导航

在 Vue 实例内部,可以通过 $router 访问路由实例。因此可以调用 this.$router.push
在 Vue 实例外部通过router.push来访问路由;

$router.push(“路径”)这个方法会向 history 栈添加一个新的记录,所以当用户点击浏览器后退按钮时,则回到之前的 URL。

push()参数的类型

  1. 字符串路径
    this.$router.push("/list");

  2. 对象
    this.$router.push({path:"/list"});

  3. 命名的路由
    1)router.push({name:“list”,params:{id:‘123’}});
    params传参在地址栏看不到id,但是其实参数已经传过去了;

2)router.push({name:“list”,query:{id:‘123’}});
query传参会拼接在地址栏中,可以看到id

  1. 带查询参数
    1)router.push({path:"/list",query:{id:100}});

2)router.push({path:"/list",params:{id:100}}); 参数会被省略,传不过去

注意:同时使用path和params的时候,会导致params的参数会被忽略,参数传不过去;所以最好name和params一起使用;

或者使用下面的方式也可以传递参数:

router.push({ path: `/user/${id}` }) // -> /user/123

点击 <router-link :to="...">等同于调用 router.push(...);所以上面同样的规则也适用于 router-link 组件的 to 属性。

6. 动态路由

动态路径参数

const routes = [{path:"/home/:id",component:home}]

路径冒号后面的是一个变量,这就是动态的路由;而且该路由会把对应的id放到$route的params属性上;属性值是路径实际的值;

<div id="app">
    <router-link to="/home/1">第一页</router-link>
    <router-link to="/home/2">第二页</router-link>
    <router-link to="/home/abc">第三页</router-link>
    <router-view></router-view>
</div>
<script src="../vue.js"></script>
<script src="../dist/vue-router.js"></script>
<script>
let home = {
    beforeUpdate (to,from,next) { //校验这个用户是否有权限访问这个组件
     if(to.params.id==1){
            next('/home/2');
            return;
        }
        next()
    },
    template:`<div>这是第{{$route.param.id}}页</div>`
}
const routes = [{path:"/home/:id",component:home}]
const router = new VueRouter({
    routes
})
let vm = new Vue({
    el:'#app',
    router
}) 
</script>

当使用路由参数时,例如从/home/1导航到 /home/2,原来的组件实例会被复用,原来的组件实例会被复用。由于渲染的都是同一个home组件,所以组件不再销毁,当然也不再创建,复用了之前的组件,性能高; 但是生命周期钩子函数也不再执行;

复用组件时,想对路由参数的变化作出响应的话,可以简单地 watch (监测变化) $route 对象:

let home={
	template:`<div>这是第{{$route.params.id}}本书</div>`,
	watch:{
	    '$route'(to,from){
	        //to :要到达的当前的$route
	        // from : 上一个$route;
	        console.log(to);
	        console.log(from);
	    }
	}

或者使用 beforeRouteUpdate 导航守卫
beforeRouteUpdate()的参数:

  • to : 即将进入的目标路由对象
  • from : 离开的路由对象
  • next : 函数
  1. next();会立即进入目标路由
  2. next(false) : 中断当前的导航;

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

{path:"*",redirect:"/person"},

7. 命名视图

有时候想同时 (同级) 展示多个视图,而不是嵌套展示;
例如创建一个布局,有 sidebar (侧导航) 和 main (主内容) 两个视图,这个时候命名视图就派上用场了。你可以在界面中拥有多个单独命名的视图,而不是只有一个单独的出口。
如果 router-view 没有设置名字,那么默认为 default。

<!-- 如果该视图没有name,会显示default对应的组件 -->
<router-view></router-view>
<!--name="a"会显示components中属性名是a对应的组件-->
<router-view name="b"></router-view>
<router-view name="c"></router-view>

一个视图使用一个组件渲染,因此对于同个路由,多个视图就需要多个组件。确保正确使用 components 配置 (带上 s):

const routes = [
        {path:"/home",component:zoo},
        {path:"/list",components:{
                default:foo,
                b:bar,
                c:zoo
            }
        }]

8. 重定向

通过配置routes中的redirect来设置重定向;
重定向:当用户访问 /a时,URL 将会被替换成 /b,然后匹配路由为 /b;
重定向的3种方式

//1.重定向
let routes = [{path:"*",redirect:"/home"}]
//2.重定向的目标也可以是一个命名的路由
let routes = [{path:"/a",redirect:{name:'home'}}]
//3.重定向的目标也可以是一个方法,动态返回重定向目标
let routes = [{path:"/a",redirect:to=>{
	//方法接收 目标路由 作为参数
	// return 重定向的 字符串路径/路径对象
}}]

9. 路由传参

路由的传参方式:

  1. route-link的方式
<!-- 直接在路径后面拼接参数 -->
<router-link to="/home/12">首页</router-link>
//动态绑定路由
const routes = [{path:"/home/:id",component:home}]
  1. push
$router.push(`/list/5566`)

const routes = [{path:"/list/:id",component:list}]
  1. name组件params传参
this.$router.push({name:"list",params:{id:999}})

const routes = [{path:"/list",component:list,name:"list"}]
  1. path路径query传参
this.$router.push({path:'/list',query:{id:100}})

10. 导航守卫

全局前置守卫

使用 router.beforeEach 注册一个全局前置守卫:
router.beforeEach():全局的路由钩子函数;只要有路由发生改变,就会触发该函数;

router.beforeEach((to,from,next) => {
    next()
})

当一个导航触发时,全局前置守卫按照创建顺序调用。
守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于等待中。

router.beforeEach((to,from,next) => {
	console.log(100)
    next()
})
router.beforeEach((to,from,next) => {
	console.log(200)
    next()
})
console.log(88) 
//执行顺序是88、100、200 <-- 先执行同步,再执行异步;
//100和200都会同时执行,不会被覆盖;

每个守卫方法接收三个参数:

  1. to: Route:即将要进入的目标路由对象;
  2. from: Route:当前导航正要离开的路由;
  3. next:是一个函数,一定要调用next方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。
  • next():进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。
  • next(false):中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。
  • next(’/’) 或者 next({ path: ‘/’ }):跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向 next 传递任意位置对象,且允许设置诸如 replace: true、name: ‘home’ 之类的选项以及任何用在 router-link 的 to prop 或 router.push 中的选项。
  • next(error): (2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。

全局解析守卫

可以用 router.beforeResolve 注册一个全局守卫。

router.beforeResolve((to,from,next) => {
    next()
})

这和 router.beforeEach 类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用。

全局的守卫先执行,然后再执行组件内部的守卫,再执行beforeResolve的守卫;

全局后置钩子

router.afterEach((to, from) => {
  // ...
})

钩子和守卫不同的是:钩子不会接受 next 函数也不会改变导航本身

组件内的守卫

在路由组件内定义的路由导航守卫:

  • beforeRouteEnter
  • beforeRouteUpdate
  • beforeRouteLeave
let home = {
  template: `<div>home</div>`,
  beforeRouteEnter(to,from,next) {
    //这个钩子函数执行前组件实例还没被创建,所以这个钩子函数中不能使用this
    //this-->window
  },
  beforeRouteUpdate(to,from,next) {
	//当组件被复用时,才会被调用;参数不一样,复用同一个组件时,会执行这个函数;这个可以使用this;this指向当前的实例;
    // 举例来说,对于一个带有动态参数的路径/foo/:id,在/foo/1和 /foo/2之间跳转的时候,由于会渲染同样的Foo组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
  },
  beforeRouteLeave(to,from,next) {
    //当离开这个组件时,钩子函数才会被调用;
    // 可以访问组件实例 `this`
  }
}

beforeRouteEnter守卫不能访问 this,因为守卫在导航确认前被调用,因此即将登场的新组件还没被创建。
不过,可以通过传一个回调给 next来访问组件实例。在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数。

beforeRouteEnter(to,from,next) {
    next(vm=>{
	    //当执行next时,该回调函数没有立即执行,等到当前组件实例创建好之后,再次触发的这个回调;
    });
  },

beforeRouteEnter 是支持给 next 传递回调的唯一守卫。对于 beforeRouteUpdate 和 beforeRouteLeave 来说,this 已经可用了,所以不支持传递回调,因为没有必要了。

beforeRouteUpdate (to, from, next) {
	this.name = to.params.name
	next()
}

离开守卫通常用来禁止用户在还未保存修改前突然离开。该导航可以通过 next(false) 来取消

beforeRouteLeave (to, from , next) {
	const answer = window.confirm('Do you really want to leave? you have unsaved changes!')
	if (answer) {
		next()
	} else {
		next(false)
	}
}

路由独享的守卫

在路由配置上直接定义 beforeEnter 守卫;

const routes = [{
		path: '/home',
		component: home,
		beforeEnter: (to,from,next) => {}
}]

特点:当前home组件独享的守卫,只有调用home组件才会执行beforeEnter 守卫;

完整的导航解析流程

  1. 导航被触发。
  2. 在失活的组件里调用离开守卫。
  3. 调用全局的 beforeEach 守卫。
  4. 在重用的组件里调用 beforeRouteUpdate 守卫。
  5. 在路由配置里调用 beforeEnter。
  6. 解析异步路由组件。
  7. 在被激活的组件里调用 beforeRouteEnter。
  8. 调用全局的 beforeResolve 守卫 。
  9. 导航被确认。
  10. 调用全局的 afterEach 钩子。
  11. 触发 DOM 更新。
  12. 用创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数。
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值