Vue 前端路由基础

Vue 前端路由基础


何为路由?
在现代前端开发中,路由是非常重要的一环。但路由到底是什么呢?
对于前后端来说,路由就是URL到函数的映射。通俗地来说,这是从路由的实现原理上来解释路由的(就好比计算机网络中的路由器)。
前端路由应用场景:
前端路由更多地应用在单页面富应用上, 也即SPA(single page web application)
路由的不同发展阶段:
1.后端渲染阶段(如JSP网页设计)
2.前后端分离阶段(Ajax等技术)
3.前端路由阶段
前端路由主要有的实现方案:
1.Hash
2.history API

前端路由的基本实现原理:

1.Hash

打开浏览器控制台,输入:

location.hash = 'home'

在这里插入图片描述

结果显示网页URL已经发生改变,但是未发生页面刷新,即未发生新的请求。

2.History

打开浏览器控制台,输入:

history.pushState({},'','home')

在这里插入图片描述
结果同样显示网页URL已经发生改变,但是未发生页面刷新,即未发生新的请求。


通过Vue-CLI来创建项目:

vue create [项目文件名称]

在根目录下创建Components文件夹,其文件夹下创建两个vue文件:

Home.vue:

<template>
  <div>
    <h1>我是Home页标题</h1>
    <p>我是Home页段落</p>
  </div>
</template>

<script>
  export default {
    name: "Home"
  }
</script>

<style scoped>

</style>

About.vue:

<template>
  <div>
    <h1>我是About页标题</h1>
    <p>我是About页段落</p>
  </div>
</template>

<script>
  export default {
    name: "About"
  }
</script>

<style scoped>

</style>

创建router文件夹以及相应目录下的index.js文件,index.js内容为:

// 配置路由相关信息
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../components/Home'
import About from '../components/About'

// 配置相关路由映射信息
const routes = [
 {
    // 默认缺省值
    path:"/",
    // 重定向到/home的路径下
    redirect: '/home'
  },
  {
    path: '/home',
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    component: About
  }
]

// 创建前端路由对象
const router = createRouter({
  // 采用History方式实现前端路由
  history: createWebHistory(process.env.BASE_URL),
  routes
})

// 将router对象传入实例中
export default router

修改App.vue内容:

<template>
  <div id="app">
    <!-- replace不会留下浏览历史(和history.pushState有关) -->
    <router-link  to="/home" repalce active-class="active"><button class="font">首页</button></router-link>
    <router-link  to="/about" replace active-class="active"><button class="font">关于</button></router-link>
  </div>
  <router-view></router-view>
</template>

<script>
  export default{
    name:'App'
  }
</script>

<style>
  .font{
    font-size: 20px;
  }
  .active .font{
    color:red;
  }
</style>

main.js文件保持不变

启动服务:

npm run serve

在这里插入图片描述

在这里插入图片描述

同时还有另一种方式(通过修改App.vue)也能达到类似以上的效果:

<template>
  <div id="app">
    <button class="font" @click="homeClick">首页</button>
    <button class="font" @click="aboutClick">关于</button>
  </div>
  <router-view></router-view>
</template>

<script>
  export default{
    name:'App',
    methods:{
      homeClick(){
        // this.$router.push('/home')
        this.$router.replace('/about')
      },
      aboutClick(){
        // this.$router.push('/about')
        this.$router.replace('/about')
      }
    }
  }
</script>

<style>
  .font{
    font-size: 20px;
    color:blue;
  }
</style>

一个简单的前端路由就完成了。

动态路由

为了满足某种模式匹配到的所有路由,全都映射到相同组件的需求。这个时候就需要动态路由匹配。例如,我们有一个 User 组件,对于所有 ID 各不相同的用户,都要使用这个组件来渲染。

User.vue:

<template>
  <div>
    <h1>用户 {{$route.params.userId}} 界面</h1>
    <p >你好,{{userId}}</p>
  </div>
</template>

<script>
  export default {
    name: "User",
    computed:{
      userId(){
        // 返回当前激活路由的用户ID
        return this.$route.params.userId
      }
    }
  }
</script>

<style scoped>

</style>

在index.js的routes数组中添加如下路由路径:

  {
    path:'/user/:userId', // 这里':'后面的userId要和$route.userId一致
    name: 'userId',
    component: User
  }

修改App.vue:

<template>
  <div id="app">
    <button class="font" @click="homeClick">首页</button>
    <button class="font" @click="aboutClick">关于</button>
    <button class="font" @click="userClick">用户界面</button>
  </div>
  <router-view></router-view>
</template>

<script>
  export default{
    name:'App',
    data(){
      return {
        user:'Tomcat'
      }
    },
    methods:{
      homeClick(){
        // this.$router.push()
        this.$router.replace('/home')
      },
      aboutClick(){
        // this.$router.push()
        this.$router.replace('/about')
      },
      userClick(){
        // 动态决定路由路径
        this.$router.replace('/user/'+this.user)
      }
    }
  }
</script>

<style>
  .font{
    font-size: 20px;
    color:blue;
  }
</style>

npm run serve 启动,显示如下结果:

在这里插入图片描述
注:以上使用了ElementPlus添加组件效果

路由懒加载

当打包构建应用时,JavaScript包会变得非常大,影响页面加载,之所以如此,是因为它是一次性将所有组件的JavaScript代码全部打包的。但是如果我们能把不同的路由对应的组件分割成不同的代码块,然后当路由被访问的时候在加载对应组件,这样响应速度就会变得更加迅速。

在懒加载之前,项目打包的目录结构为:

在这里插入图片描述

修改index.js,即可为懒加载:

// import Home from '../components/Home'
// import About from '../components/About'
// import User from '../components/User'
const Home = () => import('../components/Home')
const About = () => import('../components/About')
const User = () => import('../components/User')

重新用npm run build打包,项目结构为:

在这里插入图片描述

三个chunk文件代表具有三个路由组件

嵌套路由

通俗地说,就是一个路径映射一个组件,该组件继续进行路径映射组件

分别创建组件HomeBook.vue和HomeMusic.vue:

<template>
  <div>
    <ul>
      <li v-for="book in books" class="font">书籍名称:{{book.name}},书籍价格:{{book.price}}</li>
    </ul>
  </div>

</template>

<script>
  export default {
    name: "HomeBook",
    data(){
      return {
        books:[{name:"三体I",price:101.5},
          {name:"三体II",price:202.5},
          {name:"三体III",price:303.5}]
      }
    }
  }
</script>

<style scoped>
  .font {
    font-size:20px;
    color:dodgerblue;
  }
</style>
<template>
  <div>
    <ul>
      <li v-for="m in music" class="font">音乐:{{m}}</li>
    </ul>
  </div>
</template>

<script>
  export default {
    name: "HomeMusic",
    data(){
      return {
        music:['游京','麻雀','亦是此间少年']
      }
    }
  }
</script>

<style scoped>
  .font{
    font-size:20px;
    color:dodgerblue;
  }
</style>

index.js:

// 配置路由相关信息
import { createRouter, createWebHistory } from 'vue-router'
// 懒加载方式
const Home = () => import('../components/Home')
const HomeBook = () => import('../components/HomeBook')
const HomeMusic = () => import('../components/HomeMusic')
const About = () => import('../components/About')
const User = () => import('../components/User')


// 配置相关路由映射信息
const routes = [
  {
    // 默认路径
    path:"",
    // 重定向到/home的路径下
    redirect: '/home'
  },
  {
    path: '/home',
    name:"Home",
    component: Home,
    children:[
      {
      	// 默认路径
        path:'',
        redirect: '/home/book'
      },
      {
        // 这里记得不能添加'/'
        path:'book',
        name:'Book',
        component:HomeBook
      },
      {
        path:'music',
        name:'Music',
        component:HomeMusic
      }
    ]
  },
  {
    path: '/about',
    name:"About",
    component: About
  },
  {
    path:'/user/:userId',
    name:"UserID",
    component: User
  }
]

// 创建前端路由对象
const router = createRouter({
  // 采用History方式实现前端路由
  history: createWebHistory(process.env.BASE_URL),
  routes
})

// 将router对象传入实例中
export default router

Home.vue:

<template>
  <div>
    <h1>我是Home页标题</h1>
    <p>我是Home页段落</p>
    <el-button type="primary" @click="bookClick" round>书籍</el-button>
    <el-button type="primary" @click="musicClick" round>音乐</el-button>
    <hr/>
    <!-- 别忘记添加视图标签 -->
    <router-view></router-view>
  </div>
</template>

<script>
  export default {
    name: "Home",
    methods:{
      bookClick(){
        this.$router.replace('/home/book')
      },
      musicClick(){
        this.$router.replace('/home/music')
      }
    }
  }
</script>

<style scoped>

</style>

npm run serve显示结果:

在这里插入图片描述
在这里插入图片描述

传递参数

传递参数主要有两种方式:

1.params
  • 配置路由格式:/path/:id
  • 传递方式:path+’/’+id(路径后跟上对应的id,字符串拼接)
  • 传递后形成的路径:/path/id
  • 参数使用:this.$route.params.id
2.query
  • 配置路由格式:/path
  • 传递方式:key作为传递方式
  • 传递后形成的路径:/path?key=…
  • 参数使用:this.$route.query.key

App.vue:

<template>
  <div id="app">
    <el-button type="primary" @click="homeClick" plain>首页</el-button>
    <el-button type="primary" @click="aboutClick" plain>关于</el-button>
    <el-button type="primary" @click="profileClick" plain>归档</el-button>
    <el-button type="primary" @click="userClick" plain>用户界面</el-button>
  </div>
  <router-view></router-view>
</template>

<script>
  export default{
    name:'App',
    data(){
      return {
        user:'Tomcat'
      }
    },
    methods:{
      homeClick(){
        // this.$router.push()
        this.$router.replace('/home')
      },
      aboutClick(){
        // this.$router.push()
        this.$router.replace('/about')
      },
      userClick(){
        // 动态决定路由路径
        this.$router.replace('/user/'+this.user)
      },
      profileClick(){
        // replace可以传递对象(query方式)
        this.$router.replace(
            {
              path:'/profile',
              query:{
                name:'张三',
                age:21
          }})
      }
    }
  }
</script>

<style>
</style>

index.js:

// 配置路由相关信息
import { createRouter, createWebHistory } from 'vue-router'
// 懒加载
const Home = () => import('../components/Home')
const HomeBook = () => import('../components/HomeBook')
const HomeMusic = () => import('../components/HomeMusic')
const About = () => import('../components/About')
const User = () => import('../components/User')
const Profile = () => import('../components/Profile')

// 配置相关路由映射信息
const routes = [
  {
    // 默认缺省值
    path:"",
    // 重定向到/home的路径下
    redirect: '/home'
  },
  {
    path: '/home',
    name:"Home",
    component: Home,
    children:[
      {
        path:'',
        redirect: '/home/book'
      },
      {
        // 这里记得不能添加'/'
        path:'book',
        name:'Book',
        component:HomeBook
      },
      {
        path:'music',
        name:'Music',
        component:HomeMusic
      }
    ]
  },
  {
    path: '/about',
    name:"About",
    component: About
  },
  {
    path:'/user/:userId',
    name:"UserID",
    component: User
  },
  {
    path:'/profile',
    name:'Profile',
    component:Profile
  }
]

// 创建前端路由对象
const router = createRouter({
  // 采用History方式实现前端路由
  history: createWebHistory(process.env.BASE_URL),
  routes
})

// 将router对象传入实例中
export default router

Profile.vue:

<template>
  <div>
    <h1>我是Profile界面</h1>
    <h3>我的姓名是:{{$route.query.name}}</h3>
    <h3>我的年龄是:{{$route.query.age}}</h3>
  </div>
</template>

<script>
  export default {
    name: "Profile"
  }
</script>

<style scoped>

</style>

结果显示:

在这里插入图片描述

导航(路由)守卫

全局守卫
// 全局路由守卫
router.beforeEach((to,from,next) => {})
router.afterEach((to,from) => {})

修改index.js:

// 配置相关路由映射信息
const routes = [
  {
    // 默认缺省值
    path:"",
    // 重定向到/home的路径下
    redirect: '/home'
  },
  {
    path: '/home',
    name:"Home",
    meta:{
      title:'首页',
    },
    component: Home,
    children:[
      {
        path:'',
        redirect: '/home/book'
      },
      {
        // 这里记得不能添加'/'
        path:'book',
        name:'Book',
        component:HomeBook
      },
      {
        path:'music',
        name:'Music',
        component:HomeMusic
      }
    ]
  },
  {
    path: '/about',
    name:"About",
    meta:{
      title:'关于',
    },
    component: About
  },
  {
    path:'/user/:userId',
    name:"UserID",
    meta:{
      title:'用户',
    },
    component: User
  },
  {
    path:'/profile',
    name:'Profile',
    meta:{
      title:'归档',
    },
    component:Profile
  }
]

// 全局导航守卫(每次组件路由事件发生之前) 前置守卫(guard)
router.beforeEach((to,from,next) =>{
  document.title = to.meta.title; // 这里实现网页标题
  console.log("前置守卫执行");
  next()
})
// 全局导航守卫(每次组件路由事件发生之后) 后置守卫(guard)
router.afterEach((to,from) => {
  console.log("后置守卫执行");
})

打开浏览器,点击某一路由组件,进入控制台,如下改变:

在这里插入图片描述

在这里插入图片描述

路由独享守卫
// 路由独享守卫
beforeEnter:(to,from,next){}

修改index.js中routes:

{
    path: '/home',
    name:"Home",
    meta:{
      title:'首页',
    },
    // 独享守卫
    beforeEnter(to,from,next){
      console.log("从路径:",from.fullPath,"到路径:",to.fullPath);
      next();
    },
    component: Home,
    children:[
      {
        path:'',
        redirect: '/home/book'
      },
      {
        // 这里记得不能添加'/'
        path:'book',
        name:'Book',
        component:HomeBook
      },
      {
        path:'music',
        name:'Music',
        component:HomeMusic
      }
    ]
  }

首先进入后,点击关于按钮,最后点击首页按钮,控制台显示为:

在这里插入图片描述

组件内守卫

与上方的的守卫差不多

修改User.vue:


<script>
  export default {
    name: "User",
    computed:{
      userId(){
        // 返回当前激活路由的用户ID
        return this.$route.params.userId
      }
    },
    beforeRouteEnter(to,from,next){
      console.log("进入路由组件之前:",from.fullPath,to.fullPath);
      next()
    },
    beforeRouteUpdate(to,from,next){
      console.log("更新路由路径(后面的id)之前:",from.fullPath,to.fullPath);
      next()
    },
    beforeRouteLeave(to,from,next){
      console.log("离开路由组件之前:",from.fullPath,to.fullPath);
      next()
    }
  }
</script>

在这里插入图片描述

keep-alive可以使路由组件默认不会立即销毁

meta: {
  keepAlive: true,
  title: '首页'
 }

有疑问请查看官网

  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值