vue-router

vue-router

一、简述

理解: 一个路由(route)就是一组映射关系(key - value),多个路由需要路由器(router)进行管理。

前端路由:key是路径,value是组件。

安装vue-router

// vue2.x	==	vue-router 3.x			vue3.x	==>	vue-router	4.x

yarn add vue-router

路由的两种模式:
hash:监听url中hash值的改变,也就是使用href的锚点来改变location.href属性

<a href="#/home">home</a>
<a href="#/about">about</a>
<div class="container">
</div>
<script>
    const contentEl = document.querySelector('.container');

    window.addEventListener('hashchange', () => {
        let content = '';
        const hash = window.location.hash.slice(1);
        switch (hash) {
            case '/home':
                content = '<h1>home</h1>';
                break;
            case '/about':
                content = '<h1>about</h1>';
                break;
            default:
                content = '<h1>404</h1>';
                break;
        }
        contentEl.innerHTML = content;
    });
</script>

history模式:使用h5新出的api完成url的改变,而不刷新页面

<a href="/home">home</a>
<a href="/about">about</a>
<div class="container">
</div>
<script>
    const contentEl = document.querySelector('.container');

    const aEls = document.getElementsByTagName('a');
    for (let aEl of aEls) {
        aEl.addEventListener('click', function (e) {
            e.preventDefault();
            const path = this.getAttribute('href');
            // 修改url,而不刷新页面
            // history.pushState({},'',path) // push,可popstate
            history.replaceState({},'',path) // replace,不可popstate

            switch (location.pathname) {
                case '/home':
                    contentEl.innerHTML = 'home';
                    break;
                case '/about':
                    contentEl.innerHTML = 'about';
                    break;
                default:
                    contentEl.innerHTML = '404';
            }
        })
    }

</script>

二、基本路由

1.基本使用

main.js文件中配置

import VueRouter from 'vue-router'
import router from './router'

Vue.use(VueRouter);

new Vue({
    render: h => h(App),
    router
}).$mount('#root')

创建src/router/index.js文件并配置

import VueRouter from 'vue-router';
import Home from '../components/Home';
import About from '../components/About';

const routes = [
    {
        path: '/home',
        component: Home
    },
    {
        path: '/about',
        component: About,
        meta: {  // 配置路由的元数据,自定义数据配置在这里
            isAuth: true,
            title:'消息'
        }
    },
]

export default new VueRouter({
    routes
})

在页面中使用路由标签

<!-- 原链接
<a class="list-group-item active" href="./about.html">About</a>
<a class="list-group-item" href="./home.html">Home</a> -->

<!-- 路由链接 router-link 后续会渲染成a标签 -->
<router-link class="list-group-item" active-class="active" to="/about">About</router-link>
<router-link class="list-group-item" active-class="active" to="/home">Home</router-link>

<!-- active-class 激活选中时添加的类名 -->


 <!-- 路由组件展示的位置 -->
<router-view></router-view>

router-link标签属性:
在这里插入图片描述

2.注意点

1. 路由组件通常存放在 pages 文件夹,一般组件通常存放在 components 文件夹。
2. 通过切换,“隐藏”了的路由组件,默认是被销毁掉的,需要的时候再去挂载。
3. 每个组件都有自己的 $route 属性,里面存储着自己的路由信息。
4. 整个应用只有一个router,可以通过组件的 $router 属性获取到。

3.路由懒加载

使用webpack的分包,建议所有路由都使用懒加载:

import { createRouter,createWebHistory} from 'vue-router'

const routes = [
    {
        path: '/',
        redirect:'/home'
    },
    {
        path: '/home',
        name: 'home',
        // magic comment 魔法注释,分包后的名字
        component: ()=>import(/* webpackChunkName:"home-chunck" */'../views/Home.vue')
    }
]

4.router-link的v-slot

可以决定router-link到底渲染成什么元素,我们需要使用custom表示我们整个元素要自定义
如果不写,那么自定义的内容会被包裹在一个 a 元素中
使用:

<router-link to="/home" v-slot="props" custom>
<!-- 
  custom: 取消a标签的包裹
  props: href 跳转的连接
  props: route route对象
  props: navigate 导航函数
  props: isActive 是否当前处于活跃状态
  props: isExactActive 是否当前处于精确活跃状态
 -->
<button>{{ props.route}}</button> <!-- 点击没效果了就 -->
<button @click="props.navigate" :class="props.isActive?'custom_active':''">toHOme</button>
</router-link>

5.router-view的v-slot

使用router-view的v-slot可达到路由页面切换时,有动画的效果,依赖于依赖于动态组件
使用用于 和 组件来包裹你的路由组件,
作用域插槽的传递的参数:
Component:要渲染的组件;
route:解析出的标准化路由对象
综合使用:

<div class="container">
  <router-view v-slot="{ Component }">
    <transition name="zpj" appear mode="out-in">
      <keep-alive max="5">
        <component :is="Component"></component>
      </keep-alive>
    </transition>
  </router-view>
</div>
<style>

@keyframes show {
  0% {
    opacity: 0;
  }
  50% {
    transform: scale(1.1);
  }
  100% {
    opacity: 1;
  }
}

.zpj-enter-active {
  transform-origin: left top;
  animation: show 0.3s;
}
.zpj-leave-active {
  transform-origin: left top;

  animation: show 0.3s reverse;
}
.container {
  overflow: hidden;
}
</style>

6.动态添加路由

在生成路由时,时动态添加的
使用:

// 添加顶级路由
router.addRoute({
  path: "/dynamic",
  name: "dynamic",
  component: () => import("../views/DynamicComponent.vue"),
});

// 添加二级路由
router.addRoute('home',{
  path:'/home/moment',
  name:'moment',
  component:()=>import('../views/Home/Moment.vue')
})


/**
 * 动态删除路由
 * 方法一: 添加一个与已经有路由的相同name的路由
 * 方法二: 删除一个已经存在的路由,传入路由的name
 * 方法三: 执行添加路由方法返回的函数
 */
const removeThisRoute =  router.addRoute({path:'/home/time',name:'moment',component:()=>import('../views/Home/Moment.vue')})  // 方法一
router.removeRoute('dynamic');  // 方法二
removeThisRoute();  // 方法三

/**
 * router方法
 * hasRoute(name) 检查路由是否存在
 * getRoutes() 获取所有路由表
 */ 

三、嵌套路由

配置路由规则,使用children配置项:

const routes = [
	{
		path:'/',
		redirect:'/home'
	},
    {
        path: '/home',
        component: Home,
        children:[	//通过children配置子级路由
        	{
	       		path: "",
	        	redirect: "/home/message",
	      	},
            {
                path:'news',	//此处一定不要写:/news
                component:News
            },
            {
                path:'message',
                component:Message
            }
        ]
    },
    {
        path: '/about',
        component: About
    },
]

跳转(要写完整路径):

<!-- 写完整路径 -->
<router-link to="/home/news">News</router-link>

四、路由传参

1.query参数

传递参数:

<!-- 跳转路由并携带query参数,to的字符串写法 -->
<!-- <router-link :to="`/home/message/detail?id=${message.id}&title=${message.title}`"> -->

<!-- 跳转路由并携带query参数,to的对象写法 -->
<router-link :to="{
                  path:'/home/message/detail',
                  query:{
                  	id:message.id,
                  	title:message.title
                  }
}">
{{ message.title }}
</router-link>

接收参数:

<li>消息编号:{{$route.query.id}}</li>
<li>消息标题:{{$route.query.title}}</li>

2.命名路由

简化路由的跳转

给路由命名:

  {
        name:'shouye',   		// 路由命名
        path: '/home',
        component: Home,
        children: [
            {
                path: 'news',
                component: News
            },
            {
                path: 'message',
                component: Message,
                children: [
                    {
                        name:'xiangqing',	// 路由命名
                        path: 'detail',
                        component: Detail
                    }
                ]
            }
        ]
    },

简化路由跳转:

<!--简化前,需要写完整的路径 -->
<router-link to="/demo/test/welcome">跳转</router-link>

<!--简化后,直接通过名字跳转 -->
<router-link :to="{name:'hello'}">跳转</router-link>

<!--简化写法配合传递参数 -->
<router-link 
	:to="{
		name:'hello',
		query:{
		   id:666,
            title:'你好'
		}
	}"
>跳转</router-link>

3.params参数

传递参数:

<!-- 跳转路由并携带params参数,to的字符串写法 -->
<!-- <router-link :to="`/home/message/detail/${message.id}/${message.title}`"> -->

<!-- 跳转路由并携带params参数,to的对象写法,必须使用路由命名 -->
<router-link :to="{
    name:'xiangqing',   
    params:{
        id:message.id,
        title:message.title
    }
}">
    {{ message.title }}
</router-link>

接收参数:

// 路由配置
{
    name:'xiangqing',
    path: 'detail/:id/:title',		// 占位符声明接收
    omponent: Detail
}

// 在组件中使用
<li>消息编号:{{$route.params.id}}</li>
<li>消息标题:{{$route.params.title}}</li>

4.路由的props配置

让路由组件更方便的收到参数

{
    name:'xiangqing',
        path: 'detail/:id/:title',
            component: Detail,

                // props的第一种写法,值为对象,该对象中的所有ke-value都会以props的形式传给Detail组件
                // props:{
                //     a:1,
                //     b:'hello'
                // }


                // props的第二种写法,值为布尔值,若布尔值为真,就会把该路由组件收到的所有params参数,一props的形式传递给Detail组件
                // props:true

                // props的第三种写法,值为函数,参数为route,可以同时处理query参数与params参数
                props($route){
                console.log($route);
                return {
                    ...$route.params
                }
            }

}

5.<router-link>的replace属性

简述:

控制路由跳转时操作浏览器历史记录的模式
浏览器的历史记录有两种写入方式:分别为 push 和 replace , push 是追加历史记录, replace 是替换当前记录。路由跳转时候默认为 push 

切换跳转模式:

<router-link replace .......>News</router-link>

6.编程式路由导航

不借助<router-link> 实现路由跳转,让路由跳转更加灵活

编码:

this.$router.push({
    name: "xiangqing",
    params: {
        id: m.id,
        title: m.title,
    },
});
this.$router.replace({
    name: "xiangqing",
    params: {
        id: m.id,
        title: m.title,
    },
});

this.$router.forward();
this.$router.back();
this.$router.go(-2)

7.缓存路由组件

作用:让不展示的路由组件保持挂载,不被销毁。

编码:

<!-- 缓存全部 -->
<!-- <keep-alive> -->


<!-- 缓存一个 -->
<!-- <keep-alive include="News"> -->

<!-- 缓存多个 -->
<keep-alive :include="['News', 'Message']">
    <router-view></router-view>
</keep-alive>

8.路由钩子activeddeactived

作用:路由组件所独有的两个钩子,用于捕获路由组件的激活状态。
编码:

activated() { // 组件激活
    this.timer = setInterval(() => {
        this.opacity -= 0.1;
        console.log('jkfdsjk')
        if (this.opacity < 0) this.opacity = 1;
    }, 16);
},
deactivated(){ // 组件失活
    clearInterval(this.timer);
}

9.路由守卫

a.前置路由守卫
//全局前置守卫:初始化时执行、每次路由切换前执行
router.beforeEach((to,from,next)=>{
// router 4.x之后不推荐使用next了,根据返回值决定是否跳转,没有返回值时,可以跳转
	console.log('beforeEach',to,from)
	if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制
		if(localStorage.getItem('school') === 'JIang'){ //权限控制的具体规则
			next() //放行
		}else{
			alert('暂无权限查看')
			// next({name:'guanyu'})
		}
	}else{
		next() //放行
	}
})

//全局后置守卫:初始化时执行、每次路由切换后执行
router.afterEach((to,from)=>{
	console.log('afterEach',to,from)
	if(to.meta.title){ 
		document.title = to.meta.title //修改网页的title
	}else{
		document.title = 'vue_test'
	}
})

router 4.x之后使用:

/**
 * 返回值:
 * 1.返回false,取消默认导航
 * 2.返回一个对象,指定路由跳转 {paht:'/home/message',params:{id:123},query:{name:'张三'}}
 * 3.返回一个字符串,指定路由跳转
 * 4.不返回或者undefined:进行默认导航
 */
router.beforeEach((to, from)=>{
  return true;
})

b.独享路由守卫

进入路由组件之前,的守卫

 beforeEnter: (to, from, next) => {
     if (to.meta.isAuth) {
         if (localStorage.getItem('school') == 'JIng') {
             next();
         } else {
             alert('学校名称不对,无权查看');
         }
     } else {
         next();
     }
 }
c.组件内路由守卫
//进入守卫:通过路由规则,进入该组件时被调用
beforeRouteEnter (to, from, next) {
},
    
//离开守卫:通过路由规则,离开该组件时被调用
beforeRouteLeave (to, from, next) {
}

10.路由器工作模式

  1. hash模式:
    1. 地址中永远带着#号,不美观 。
    2. 若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法。
    3. 兼容性较好。
  2. history模式:
    1. 地址干净,美观 。
    2. 兼容性和hash模式相比略差。
    3. 应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题。
    4. 在node服务器中可使用 connect-history-api-fallback 中间件解决

修改路由器工作模式:

const router = new VueRouter({
    routes,
    mode:'hash'
});
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值