vue-router | 青训营

101 阅读3分钟

路由(router)

image-20230717110237434.png

从#往后(哈希地址)

前端路由工作方式

  • 1.点击页面上路由连接:导致hash地址变化

  • 2.前端路由监听hash地址变化:把当前hash地址对应组件渲染到浏览器

hash地址(path)与组件(component)的对应关系

image-20230717111006699.png (手动模拟简易路由 自己监听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