路由(router)
从#往后(哈希地址)
前端路由工作方式
-
1.点击页面上路由连接:导致hash地址变化
-
2.前端路由监听hash地址变化:把当前hash地址对应组件渲染到浏览器
hash地址(path)与组件(component)的对应关系
(手动模拟简易路由 自己监听hashchange)
<template>
<div class="app-container">
<h1>App 根组件</h1>
<a href="#/home">首页</a>
<a href="#/movie">电影</a>
<a href="#/about">关于</a>
<hr />
<component :is="curName"></component>
</div>
</template>
<script>
// 导入组件
import Home from '@/components/Home.vue'
import Movie from '@/components/Movie.vue'
import About from '@/components/About.vue'
export default {
name: 'App',
// 注册组件
components: {
Home,
Movie,
About
},
data(){
return {
// 在动态组件的位置 要展示的组件的名字,值必须是字符串
curName:'Home'
}
},
// 只要当前的app组件被创建,就立即监听window对象的onhashchange
created(){
// 用箭头函数不用function ===箭头函数内部this与外部this一致
window.onhashchange=()=>{
console.log(location.hash)
switch(location.hash){
case '#/home':
this.curName='Home'
break
case '#/movie':
this.curName='Movie'
break
case '#/about':
this.curName='About'
break
}
}
}
}
</script>
<style lang="less" scoped>
.app-container {
background-color: #efefef;
overflow: hidden;
margin: 10px;
padding: 15px;
> a {
margin-right: 10px;
}
}
</style>
vue-router
vue-router(vue项目的路由包)
https://router.vuejs.org/zh/htt
起步
1.安装
npm i vue-router@3.5.2 -S //-S 把该包放入dependens目录下
2.创建路由模块
// src/router.index.js就是当前项目的路由模块
// 1.导入vue vue-router包
import vue from 'vue'
import VueRouter from 'vue-router'
// 2.调用Vue.use()函数 把VueRouter安装为Vue插件
vue.use(VueRouter)
// 3.创建路由实例对象
const router=new VueRouter()
// 对外共享路由实例对象
export default router
3.导入并挂载路由模块
//main.js
import Vue from 'vue'
import App from './App.vue'
// 导入 bootstrap 样式
import 'bootstrap/dist/css/bootstrap.min.css'
// 全局样式
import '@/assets/global.css'
// 导入路由模块 拿到路由实例对象
// 在进行模块化导入的时候 如果给定的是文件夹 则默认导入这个文件夹下名字叫做index.js的文件
import router from '@/router'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
// 在Vue项目中想要用路由 就必须把路由实例对象通过下列方式挂载
// router:路由实例对象 路由实例对象为router 可简写为router
router:routerobj
}).$mount('#app')
简单使用
<template>
<div class="app-container">
<h1>App2 组件</h1>
<a href="#/home">首页</a>
<a href="#/movie">电影</a>
<a href="#/about">关于</a>
<hr />
<!-- 只要在项目中安装了vue-router 就可以使用router-view这个组件 占位符 ===一个出口-->
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
<style lang="less" scoped>
.app-container {
background-color: #efefef;
overflow: hidden;
margin: 10px;
padding: 15px;
> a {
margin-right: 10px;
}
}
</style>
// src/router.index.js就是当前项目的路由模块
// 1.导入vue vue-router包
import vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../components/Home.vue'
import Movie from '../components/Movie.vue'
import About from '../components/About.vue'
// 2.调用Vue.use()函数 把VueRouter安装为Vue插件
vue.use(VueRouter)
// 3.创建路由实例对象
const router=new VueRouter({
// routes是一个数组,定义hash地址与组件之间的对应关系
// 路由规则
routes:[
{
path:"/home",
component:Home
},
{
path:'/about',
component:About
},
{
path:'/movie',
component:Movie
}
]
})
// 对外共享路由实例对象
export default router
改进
<template>
<div class="app-container">
<h1>App2 组件</h1>
<!-- 当安装和配置vue-router之后 就可以使用router-link来代替a标签链接 href属性==to属性 (去掉#) -->
<!-- <a href="#/home">首页</a>-->
<router-link to="/home">首页</router-link>
<router-link to="/about">关于</router-link>
<router-link to="/movie">电影</router-link>
<hr />
<!-- 只要在项目中安装了vue-router 就可以使用router-view这个组件 占位符 ===一个出口-->
<router-view></router-view>
</div>
</template>
路由重定向redirect
const router=new VueRouter({
routes:[
// 路由重定向
{
path:'/',
redirect:'/home'
},
{
path:"/home",
component:Home
}
]
})
- 路由重定向:用户在访问地址A时,强制用户跳转到C,从而展示特定的组件页面。通过路由规则的redirect属性,指定一个新的路由地址。
嵌套路由
// 3.创建路由实例对象
const router=new VueRouter({
routes:[
{
path:'/about',
component:About,
// 通过children属性 嵌套声明子级路由规则 子级path不用加/
children:[
// 子路由规则
{
path:'tab1',
component:Tab1
},
{
path:'tab2',
component:Tab2
}
]
}
]
})
路由重定向
const router=new VueRouter({
routes:
{
path:'/about',
component:About,
redirect:'/about/tab1',
// 通过children属性 嵌套声明子级路由规则 子级path不用加/
children:[
// 子路由规则
{
path:'tab1',
component:Tab1
},
{
path:'tab2',
component:Tab2
}
]
}
]
})
默认子路由
- 如果children数组中,某个路由规则的path值为空字符串,则这条路由规则叫做‘默认子路由’
const router=new VueRouter({
routes:[
{
path:'/about',
component:About,
children:[
// 子路由规则
{
path:'',
component:Tab1
},
{
path:'tab2',
component:Tab2
}
]
}
]
})
动态路由匹配
- 动态路由:将Hash地址中可变的部分定义为参数项,从而提高路由规则的复用性
- 在vue-router中使用英文冒号(:)来定义路由参数项
//APP.vue
<template>
<div class="app-container">
<h1>App2 组件</h1>
<!-- 当安装和配置vue-router之后 就可以使用router-link来代替a标签链接 href属性==to属性 (去掉#) -->
<!-- <a href="#/home">首页</a>-->
<router-link to="/home">首页</router-link>
<router-link to="/about">关于</router-link>
<router-link to="/movie/1">电影1</router-link>
<router-link to="/movie/2">电影2</router-link>
<router-link to="/movie/3">电影3</router-link>
<hr />
<!-- 只要在项目中安装了vue-router 就可以使用router-view这个组件 占位符 ===一个出口-->
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
<style lang="less" scoped>
.app-container {
background-color: #efefef;
overflow: hidden;
margin: 10px;
padding: 15px;
> a {
margin-right: 10px;
}
}
</style>
路由规则
//movie路由规则
{
path:'/movie/:id',
component:Movie
}
获取参数(1)--this
//组件movie.vue
<template>
<div class="movie-container">
<!-- this.$route 是路由的'参数对象' -->
<!-- this.$router是路由的'导航对象' -->
<h3>Movie 组件---{{ this.$route.params.id }}</h3>
<button @click="showThis">this</button>
</div>
</template>
<script>
export default {
name: 'Movie',
methods:{
showThis(){
console.log(this);
}
}
}
</script>
路由规则
{
// 为路由规则开启props传参 拿到动态参数
path:'/movie/:id',
component:Movie,
props:true
}
props
<template>
<div class="movie-container">
<!-- this.$route 是路由的'参数对象' -->
<!-- this.$router是路由的'导航对象' -->
<h3>Movie 组件---{{ this.$route.params.id }}---{{id }}</h3>
<button @click="showThis">this</button>
</div>
</template>
<script>
export default {
name: 'Movie',
props:['id'],
methods:{
showThis(){
console.log(this);
}
}
}
</script>
注意 (关于路由参数对象this.$route)
<!--注意1: 在hash地址中 /后面的参数项 叫做‘路径参数’ -->
<!-- 在路由‘参数对象’中(this.$route) 需要使用this.$route.params来访问路径参数 -->
<!-- 注意2: 在hash地址中 ?后面的参数项 叫做‘查询参数’-->
<!-- 在路由‘参数对象中’ 需要使用this.$route.query来访问查询参数 -->
<!-- 注意3:在this.$route中 path只是路径部分 fullPath是完整路径 -->
<!-- 例如 -->
<!-- /movie/2?name=zs&age=20 是fullPath的值 -->
<!-- /movie/2 是path的值 -->
<router-link to="/movie/1">电影1</router-link>
<router-link to="/movie/2?name=zs age=20">电影2</router-link>
<router-link to="/movie/3">电影3</router-link>
导航
声明式导航&编程式导航
在浏览器中点击链接实现导航的方式,叫做声明式导航;调用api实现导航的方式叫做编程式导航。
常用的编程式导航API
<template>
<div class="home-container">
<h3>Home 组件</h3>
<button @click="gotoM">点击跳转push</button>
<button @click="gotoM2">点击跳转replace</button>
</div>
</template>
<script>
export default {
name: 'Home',
methods:{
gotoM(){
// this.$router(带r--导航对象) 通过编程式导航API,导航跳转到指定的页面
this.$router.push('movie/1')
},
gotoM2(){
// 替换当前的历史记录
this.$router.replace('movie/3')
}
}
}
</script>
this.$router.go()
<template>
<div class="movie-container">
<!-- this.$route 是路由的'参数对象' -->
<!-- this.$router是路由的'导航对象' -->
<h3>Movie 组件---{{ this.$route.params.id }}---{{id }}</h3>
<button @click="showThis">this</button>
<button @click="goback">后退</button>
<button @click="forward">前进</button>
</div>
</template>
<script>
export default {
name: 'Movie',
props:['id'],
methods:{
showThis(){
console.log(this);
},
goback(){
this.$router.back()
},
forward(){
this.$router.forward()
}
}
}
</script>
===============行内使用编程式导航跳转=======================
<button @click="$router.back()">后退</button>
<button @click="$router.forward()">前进</button>
导航守卫
- 控制路由的访问权限
声明全局前置守卫
// 为router实例对象 声明全局前置导航守卫
// 只要发生了路由跳转,必然触发beforeEach指定的 function回调函数
router.beforeEach(function(to,from,next){
// to:表示将要访问的路由的信息对象
// from:表示将要离开的路由的信息对象
// next函数表示放行的意思to
console.log(from);
console.log(to);
next()
})
export default router
结:
1.component建立组件页面
2.创建路由模块
<router-link to="/main">Main</router-link>
<router-link to="/login">Login</router-link>
3.配置路由并且声明前置守卫
import vue from 'vue'
import VueRouter from 'vue-router'
import Login from '../components/Login.vue'
import Main from '../components/Main.vue'
vue.use(VueRouter)
const router=new VueRouter({
routes:[
{
path:'/login',
component:Login
},
{
path:'/main',
component:Main
},
]
})
router.beforeEach(function(to,from,next){
// 分析
// 1.拿到用户将要访问的hash地址
// 2.判断hash地址是否等于/main
// 2.1.如果等于/main 需要登录之后 才能访问成功
// 2.2如果不等于/main 则不需要登录 直接放行 next
// 3.如果访问的地址是/main 则需要读取localStorage中的 token值
// 3.1如果有token 则放行
//3.2 如果没有token,则强制跳转到/login登录页
if(to.path==='/main'){
// 判断token
const token=localStorage.getItem('token')
if(token){
next()
}
else{
next('/login')
}
}
else{
next()
}
})
export default router