Skip to content

4. 路由

4.1. 【对路由的理解】

image-20231018144351536

4.2. 【基本切换效果】

  • Vue3中要使用vue-router的最新版本,截止到2024-02-13日,目前是4版本(4.2.5)。

  • 安装:

sh
npm install vue-router	-S
//或者
cnpm install vue-router	-S
  • 提前定义用于根据路径动态切换的几个组件(此处演示用于介绍html、css、Javascript三个知识点的组件切换)
vue
<!-- 1 定义组件模版 --> 
<template>
    <div class="com">
       介绍CSS的知识,样式,布局,内置函数,important
    </div>
  </template> 
  
  <!-- 2 定义组件逻辑 -->
  <script setup lang="ts" name="CssComponent"> 
  import { ref   } from 'vue'	
          
  
  </script> 
  
  <!-- 3 定义样式 -->
  <style scoped> 
  .com{
    overflow-y:auto;
    min-height:300px
  }
  </style>
vue
<!-- 1 定义组件模版 --> 
<template>
  <div class="com">
     介绍HTML的知识1 <br/>
     介绍HTML的知识2 <br/>
     介绍HTML的知识3 <br/>
     介绍HTML的知识4 <br/>
     介绍HTML的知识5 <br/>
     介绍HTML的知识6 <br/>
  </div>
</template> 

<!-- 2 定义组件逻辑 -->
<script setup lang="ts" name="HTMLComponent"> 
import { ref   } from 'vue'			




</script> 

<!-- 3 定义样式 -->
<style scoped> 
.com{
  overflow-y:auto;
  min-height:300px
}
</style>
vue
<!-- 1 定义组件模版 --> 
<template>
  <div>
     介绍js的知识
  </div>
</template> 

<!-- 2 定义组件逻辑 -->
<script setup lang="ts" name="JSComponent"> 
import { ref   } from 'vue'			

</script> 


<!-- 3 定义样式 -->
<style scoped> 

</style>
  • 定义和使用路由,在 src/router/index.ts中定义路由,在main.js中使用路由
ts
import {createRouter,createWebHistory} from 'vue-router'
import CSS from '@/views/CSS.vue'
import HTML from '@/views/HTML.vue'
import JavaScript from '@/views/JavaScript.vue'

const router = createRouter({
	history:createWebHistory(),
	routes:[
		{
			path:'/html',
			component:HTML
		},
		{
			path:'/css',
			component:CSS
		},
        {
			path:'/js',
			component:JavaScript
		}
	]
})
export default router
js
import { createApp } from 'vue'
import App from './App.vue'

//引入ElementPlus组件库
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import router from './router/index'

const app = createApp(App)

//注册全局组件
app.use(ElementPlus)
app.use(router)
app.mount('#app')
  • 在App中使用路由动态渲染不同的组件
查看代码
vue
<template>
    <div class="app">
        <h2 class="title">Vue路由测试</h2>
        <!-- 导航区 -->
        <div class="navigate">
           <span> <RouterLink to="/html" active-class="active" >HTML知识点</RouterLink></span>
           <span>  <RouterLink to="/css" active-class="active">css知识点</RouterLink></span>
            <span>  <RouterLink to="/js" active-class="active">JavaScript</RouterLink></span>
        </div>
        <!-- 展示区 -->
        <div class="main-content">
            <router-view></router-view>
        </div>
    </div>
</template>
  
<script lang="ts" setup name="App">
//可以不用显示的注册组件,在main.js中使用的app.use(router)已经注册全局组件
import { RouterLink, RouterView } from 'vue-router'

</script>

<style scoped>

.app{
    width: 800px;
    min-height: 500px;
    box-shadow: 0 0 10px inset;
    padding: 20px;
}
.RouterLink{
    line-height: 50px;
}

.navigate{
    height: 50px;
    line-height: 50px;
    background-image: linear-gradient(45deg, rgb(224, 217, 217) 0 33%, rgb(169, 169, 238) 33% 66%, rgb(157, 181, 157) 66% 100%);
    display: flex
   
}

.navigate span{
    flex:1;
    display: flex;
    align-items: center;
    justify-content: center;
}

.navigate span a{
    text-align: center;
}
.navigate span a.active{
    color: red;
}
.navigate span a{
    color:rgb(116, 105, 92);
    font-weight: 900;
    text-decoration: none;
    letter-spacing: 2px;
}

.main-content{
    width: 100%;
    margin: 10px 0;
    border:solid 2px grey;
    box-shadow: 0 0 5px black;
    border-radius: 10px;
}
</style>

实现效果如下:

image-20240212193736893

4.3. 【两个注意点】

  1. 路由组件通常存放在pagesviews文件夹,一般组件通常存放在components文件夹。

  2. 通过点击导航,视觉效果上“消失” 了的路由组件,默认是被卸载掉的,需要的时候再去挂载

4.4.【路由器工作模式】

  1. history模式

    优点:URL更加美观,不带有#,更接近传统的网站URL

    缺点:后期项目上线,需要服务端配合处理路径问题,否则刷新会有404错误。

    js
    const router = createRouter({
      	history:createWebHistory(), //history模式
      	/******/
    })
  2. hash模式

    优点:兼容性更好,因为不需要服务器端处理路径。

    缺点:URL带有#不太美观,且在SEO优化方面相对较差。

    js
    const router = createRouter({
      	history:createWebHashHistory(), //hash模式
      	/******/
    })

4.5. 【to的两种写法】

vue
<!-- 第一种:to的字符串写法 -->
<router-link active-class="active" to="/home">主页</router-link>

<!-- 第二种:to的对象写法 -->
<router-link active-class="active" :to="{path:'/home'}">Home</router-link>

4.6. 【命名路由】

作用:可以简化路由跳转及传参(后面就讲)。

给路由规则命名:

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

import CSS from '@/views/CSS.vue'
import HTML from '@/views/HTML.vue'
import JavaScript from '@/views/JavaScript.vue'
const router = createRouter({
	history:createWebHistory(),
	// history:createWebHashHistory(),
	routes:[
		{
			path:'/',
			redirect:'/html'
		},
		{
			path:'/html',
			component:HTML
		},
		{
			name:"ToCSS",
			path:'/css',
			component:CSS,
			
		},
        {
			path:'/js',
			component:JavaScript,
			
		}
	]
})
export default router

跳转路由:

vue
<!--简化前:需要写完整的路径(to的字符串写法) -->
<router-link to="/css">跳转</router-link>

<!--简化后:直接通过名字跳转(to的对象写法配合name属性) -->
<router-link :to="{name:'ToCSS'}">跳转</router-link>

4.7. 【嵌套路由】

在基本效果图中Javascript章节(组件下)包含多个章节可以采用嵌套路由的方式实现,主要改造如下

  • 准备两个组件用于切换
  • 修改Javascript.vue添加 router-linkrouter-view
  • 修改src/router/index.ts添加children嵌套路由

具体代码如下

vue
<!-- 1 定义组件模版 --> 
<template>
    <div>
        Javascript的基础语法
    </div>
  </template> 
  
  <!-- 2 定义组件逻辑 -->
  <script setup lang="ts" name="JSComponent1"> 
  </script> 
  
  
  <!-- 3 定义样式 -->
  <style scoped> 
  
  </style>
vue
<!-- 1 定义组件模版 --> 
<template>
    <div>
        js的内置对象
    </div>
  </template> 
  
  <!-- 2 定义组件逻辑 -->
  <script setup lang="ts" name="JSComponent1"> 
  </script> 
  
  
  <!-- 3 定义样式 -->
  <style scoped> 
  
  </style>
vue
<!-- 1 定义组件模版 --> 
<template>
  <div>
    介绍js的知识
    <div>
      <div class="left jsblock">
          <ol>
            <li><router-link to="/js/chapter1">第一章节</router-link></li>
            <li><router-link to="/js/chapter2">第二章节</router-link></li>
          </ol>
      </div>

      <div class="right jsblock">
          <router-view></router-view>
      </div>

    </div>

  </div>
</template> 

<!-- 2 定义组件逻辑 -->
<script setup lang="ts" name="JSComponent">
import { ref } from 'vue'

</script> 


<!-- 3 定义样式 -->
<style scoped> .jsblock {
   display: inline-block;

   min-height: 400px;
   border: solid 1px red;
   vertical-align:top;
 }

 .left {
   width: 200px;
   margin-left: 10px
 }

 .right {
   width: 570px;
   margin-left: 10px;
 }
</style>
ts
import {createRouter,createWebHistory} from 'vue-router'

import CSS from '@/views/CSS.vue'
import HTML from '@/views/HTML.vue'
import JavaScript from '@/views/JavaScript.vue'
import JavaScriptChapter1 from '@/views/js/chapter1.vue'
import JavaScriptChapter2 from '@/views/js/chapter2.vue'

const router = createRouter({
	history:createWebHistory(),
	routes:[
		{
			path:'/html',
			component:HTML
		},
		{
			path:'/css',
			component:CSS
		},
        {
			path:'/js',
			component:JavaScript,
			children:[
				{
					path:'/js/chapter1',
					component:JavaScriptChapter1
				},
				{
					path:'/js/chapter2',
					component:JavaScriptChapter2
				},
			]
		}
	]
})
export default router

4.8. 【路由传参】

query参数

  1. 传递参数

    vue
    <!-- 1 定义组件模版 --> 
    <template>
      <div class="com">
        介绍CSS的知识,样式,布局,内置函数,important
    
        <div class="comApp">
          <ul>
            <li v-for="chapter in chapters">
              <!-- <router-link :to="`/css/detail?id=${chapter.id}&title=${chapter.title}&content=${chapter.content}`">
                {{ chapter.title }}
              </router-link> -->
    
              <!-- <router-link :to="{
                path:'/css/detail',
                query:{
                  ...chapter
                }
              }">
                {{ chapter.title }}
              </router-link> -->
    
    
    
              <router-link :to="{
                name:'CssDeatail',
                query:{
                  ...chapter,
                }
              }">
                {{ chapter.title }}
              </router-link>
    
    
            </li>
          </ul>
    
          <div>
            <router-view></router-view>
          </div>
    
    
    
        </div>
      </div>
    </template> 
      
      <!-- 2 定义组件逻辑 -->
    <script setup lang="ts" name="CssComponent">
    import { onUnmounted, onMounted, ref, reactive } from 'vue'
    
    let chapters = reactive([
      { id: "asdfsadf001", title: '布局', content: '使用position属性进行布局' },
      { id: "asdfsadf002", title: '内置函数', content: '内置了calc,xxx等函数' },
      { id: "asdfsadf003", title: '属性(宽高)', content: '宽高的取值有  px cm vh vw等 ' },
    ])
    
    
    
    
    onMounted(() => {
      console.log('CSS挂载')
    })
    onUnmounted(() => {
      console.log('CSS卸载')
    })
    
    
    </script> 
      
      <!-- 3 定义样式 -->
    <style scoped> .com {
       overflow-y: auto;
       min-height: 300px
     }
    
     .comApp>ul,
     .comApp>div {
       margin: 10px;
       display: inline-block;
       vertical-align: top;
     }
    </style>
  2. 接收参数:

    vue
    <!-- 1 定义组件模版 --> 
    <template>
       <div>
           css  详情
            <div>id:{{ query.id }}</div>
            <div>title:{{ query.title }}</div>
            <div>content:{{ query.content}}</div>
    
    
       </div>
    </template> 
    
    <!-- 2 定义组件逻辑 -->
    <script setup lang="ts" name="detail"> 
    import { ref ,toRef,toRefs,onMounted,onUnmounted} from 'vue'			
     import {useRoute} from 'vue-router'
    
     let route  = useRoute();
     let query = toRef(route,'query')
    console.log("query参数")
     onMounted(()=>{
        console.log("CSS Detail 组件 挂载");
        
     })
     onUnmounted(()=>{
        console.log("CSS Detail 组件卸载");
     })
    </script> 
     
    <!-- 3 定义样式 -->
    <style scoped> 
     div{
        margin: 5px;
     }
    </style>

params参数

  1. 传递参数

    vue
    <!-- 跳转并携带params参数(to的字符串写法) -->
    <!--  <router-link           :to="`/css/detail/${chapter.id}/${chapter.title}/${chapter.content}`"></router-link>  -->
    
    <!-- 跳转并携带params参数(to的对象写法) -->   
    <router-link 
                 :to="{
                      name:'CssDeatail', //用name跳转
                      params:{
                      id:chapter.id,
                      title:chapter.title,
                      content:chapter.content
                      }
                      }"
                 >
    
    
        {{ chapter.title }}
    </router-link>
  2. 在路由中进行占位定义

    typescript
    import {createRouter,createWebHistory,createWebHashHistory} from 'vue-router'
    
    import CSS from '@/views/CSS.vue'
    import HTML from '@/views/HTML.vue'
    import JavaScript from '@/views/JavaScript.vue'
    import JavaScriptChapter1 from '@/views/js/chapter1.vue'
    import JavaScriptChapter2 from '@/views/js/chapter2.vue'
    import CSSDetail from '@/views/css/detail.vue'
    const router = createRouter({
    	history:createWebHistory(),
    	// history:createWebHashHistory(),
    	routes:[
    		{
    			path:'/',
    			redirect:'/html'
    		},
    		{
    			path:'/html',
    			component:HTML
    		},
    		{
    			name:"ToCSS",
    			path:'/css',
    			component:CSS,
    			children:[
    				{
    					name:'CssDeatail',
    					path:'detail/:id/:title/:content',  
    					component:CSSDetail,  			  
    				}
    			]
    		},
            {
    			path:'/js',
    			component:JavaScript,
    			children:[
    				{
    					path:'/js/chapter1',
    					component:JavaScriptChapter1
    				},
    				{
    					path:'/js/chapter2',
    					component:JavaScriptChapter2
    				},
    			]
    		}
    	]
    })
    export default router
  3. 接收参数:

    vue
    <!-- 1 定义组件模版 --> 
    <template>
        <div>
            css 详情
            <div>id:{{ params.id }}</div>
            <div>title:{{ params.title }}</div>
            <div>content:{{ params.content }}</div>
    
    
        </div>
    </template> 
    
    <!-- 2 定义组件逻辑 -->
    <script setup lang="ts" name="detail">
    import { ref, toRef, toRefs, onMounted, onUnmounted } from 'vue'
    import { useRoute } from 'vue-router'
    
    let route = useRoute();
    let params = toRef(route, 'params')
    console.log("params参数")
    onMounted(() => {
        console.log("CSS Detail 组件 挂载");
    
    })
    onUnmounted(() => {
        console.log("CSS Detail 组件卸载");
    })
    </script> 
     
    <!-- 3 定义样式 -->
    <style scoped> 
     div {
         margin: 5px;
     }
    </style>

备注1:传递params参数时,若使用to的对象写法,必须使用name配置项,不能用path

备注2:传递params参数时,需要提前在规则中占位。

4.9. 【路由的props配置】传送门

作用:让路由组件更方便的收到参数(可以将路由参数作为props传给组件)

在路由组件中使用props接收数据

vue
<!-- 1 定义组件模版 --> 
<template>
    <div>
        css 详情
        <div>id:{{ id }}</div>
        <div>title:{{ title }}</div>
        <div>content:{{ content }}</div>
    </div>
</template> 

<!-- 2 定义组件逻辑 -->
<script setup lang="ts" name="detail">
   defineProps(['id','title','content'])
</script> 
 
<!-- 3 定义样式 -->
<style scoped> div {
     margin: 5px;
 }
</style>

传参的使用

html
 <router-link 
              :to="{
                name:'CssDeatail',
                name:{
                  id:chapter.id,
                  title:chapter.title,
                  content:chapter.content
                }
              }"
            >

修改路由表中传参方式

json
{
    name:'CssDeatail',
	path:'detail/:id/:title/:content',
	component:CSSDetail,

	//1 props的对象写法,作用:把对象中的每一组key-value作为props传给CssDeatail组件 ,对path没有具体要求,可以不写,写上也不算错
	//props:{id:'test00001',title:'固定的title',content:'详情内容  content....'}

	//2  props的布尔值写法,作用:把收到了每一组params参数,作为props传给CssDeatail组件
	// path:'detail/:id/:title/:content',
	// props:true

	//3  props的函数写法,作用:把返回的对象中每一组key-value作为props传给CssDeatail组件
	// path:'detail', 不能出现 冒号“:”
	// props:(route)=>{
	// 	//此处应该 :to中传递的是 query参数才有意义,否则取不到query参数的值,params参数不需要使用函数也可以获取到,`即props:true`
	// 	return {
	// 		id:route.query.id,
	// 		title:route.query.title,
	// 		content:route.query.content
	// 	}
	// }

	//函数的其他写法
	props(route){
		return route.query
	}

}

4.10. 【 replace属性】

  1. 作用:控制路由跳转时操作浏览器历史记录的模式。

  2. 浏览器的历史记录有两种写入方式:分别为pushreplace

    • push是追加历史记录(默认值)。
    • replace是替换当前记录。
  3. 开启replace模式:

    vue
    <RouterLink replace .......>News</RouterLink>

4.11. 【编程式导航】

路由组件的两个重要的属性:$route$router变成了两个hooks

js
import {useRoute,useRouter} from 'vue-router'

const route = useRoute()
const router = useRouter()

console.log(route.query)
console.log(route.parmas)
console.log(router.push)
console.log(router.replace)

4.12. 【重定向】

  1. 作用:将特定的路径,重新定向到已有路由。

  2. 具体编码:

    js
    {
        path:'/',
        redirect:'/about'
    }

Released under the MIT License.