Vue-Router 前端路由

本文详细介绍了前端路由的概念,对比了后端路由的优缺点,并重点讲解了Vue-Router的使用,包括动态路由、路由懒加载、嵌套路由、导航守卫及其在滚动行为上的应用,旨在帮助开发者深入理解并掌握Vue-Router在单页面应用中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 概述

  1. 路由是一个网络工程里面的术语
  2. 路由就是通过互联的网络把信息从源地址传输到目的地址的活动
  3. 后端路由:后端处理URL和页面之间的映射关系
  4. 前端路由:前端处理URL和页面之间的映射关系

2. 后端路由阶段

  1. 早期的网站开发整个HTML页面是由服务器来渲染的。服务器直接生产渲染好对应的HTML页面,返回给客户端进行展示

  2. 但是,一个网站,这么多页面,服务器如何处理呢?
    ●. 每个页面都有自己对应的网址,也就是URL
    ●. URL会发送到服务器,服务器通过正则对该URL进行匹配,并且最后交给一个Controller处理
    ●. Controller进行各种处理,最终生成HTML或者数据,返回给前端
    ●. 这就完成了一个IO操作

  3. 上面的这种操作就是后端路由,当我们页面中需要请求不同的路径内容时,交给服务器来进行处理,服务器渲染好整个页面,并且将页面返回给客户端,这种情况下渲染好的的页面,不需要单独加载任何的js和css,可以直接交给浏览器展示,这样也有利于SEO的优化

  4. 后端路由的缺点:
    ●. 一种情况是整个页面的模块由后端人员来编写和维护
    ●. 另一种情况是前端开发人员如果要开发页面,需要通过PHPjava等语言来编写页面代码
    ●. 而且通常情况下HTML代码和数据以及对应的逻辑会混在一起,编写和维护都是非常糟糕的事情

3. 前端路由阶段

  1. 前后端分离阶段:
    ●. 随着Ajax的出现,有了前后端分离的开发模式
    ●. 后端只提供API来返回数据,前端通过Ajax获取数据,并且可以通过javaScript将数据渲染到页面
    ●. 这样做最大的优点就是前后端责任的清晰,后端专注于数据上,前端专注于交互和可视化上
    ●. 并且当移动端(IOS/Android)出现后,后端不需要进行任何处理,依然使用之前的一套API即可
    ●. 目前很多网站依然采用这种模式开发

  2. 单页面富应用(SPA)阶段:
    ●. 其实SPA最主要的特点就是在前端分离的基础上加了一层前端路由
    ●. 也就是前端来维护一套规则

  3. 前端路由的核心:
    ●. 改变URL,但是页面不进行整体的刷新

4. 认识vue-router

  1. 目前前端流行的三大框架,都有自己的路由实现
    ●. AngularngRouter
    ●. ReactReactRouter
    ●. Vuevue-router

  2. vue-routerVue.js 官方的路由插件,它和Vue.js是深度集成的,适用于构建单页面应用vue-router官网:https://router.vuejs.org/zh/

  3. vue-router 是基于路由和组件的,路由用于设定访问路径,将路径和组件映射起来,在vue-router的单页面应用中,
    页面的路径的改变就是组件的切换

5. 安装和使用vue-router

  1. 安装vue-router:

    npm install vue-router --save
    // 这是运行时依赖
    
  2. 配置路由:

    // 在 src/router/index.js 文件中
    // 1. 导入路由模块:
    	import VueRouter from 'vue-router'
    // 2. 导入Vue模块:
    	import Vue from 'vue' 
    // 3. 导入组件
    	import Home from '../components/Home.vue'   // 这里的 .vue 后缀可以省略
    	import Home from '../components/Avout.vue'
    	
    // 4. 安装路由插件: 
        Vue.use(VueRouter)
    // 5. 创建路由实例,并且传入路由映射配置
    	const router = new VueRouter({
         		// 配置路由和组件之间的应用关系
                    routes:[
                    	{   
        					// 网页重定向:当请求路径为空或者为为某些特点值,可以设置网页显示哪些东西。
           		 			path:'/',         // path:'/' 和 path:'' 一个意思 
            				redirect:'./home'
        				},
                        {
                            path:'/home',   // 当文路径文 /home 的时候,显示下面的组件
                            component:Home
                        },
                        {
                            path:'/about',
                            component:About
                        }
        			]
    	})
    // 5. 导出路由对象:
    	export default router
    
  3. 使用路由:

    // 1. 在入口文件 main.js 中导入路由模块
    import router from './router'  // 会自动去 router 文件夹中找 index.js 文件
    // 2. 在 Vue 实例中挂载创建的路由实例
    	new Vue({
         	el: '#app',
         	router,
         	render: h => h(App)
    	})
    //============================================================================
    // 3. 使用路由:在 Vue 实例的的模板组件 App.vue 中,创建对应的组件标签
            <div id="app">
                <router-link to="/home">首页</router-link>   // router-link 是 vue-router 插件内置的一个标签
                <router-link to="/about">关于</router-link>  // router-link 最终会被渲染成 a 标签
                <router-view></router-view>          // router-view 是占位标签,会被需要显示的页面替换掉
            </div>
    
  4. 路径改变的模式:hash 与 history

    // 1. 默认情况下路径改变都是通过hash值:http://localhost:8080/#/about 
    // 2. 如果想改成history模式,路径的改变方式,在路由对象中添加一个属性mode
            const router = new VueRouter({
                routes,
                mode:'history'
            })
    // 注:改变之后的路径显示:http://localhost:8080/about
    
  5. router-link 组件标签的属性

    <router-link to="/home" tag='button'>首页</router-link> 
    // 1. to='/home' 属性用于指定跳转路径 
    // 2. tag='button'属性可以指定标签渲染成什么组件,默认是a标签
    // 3. replace 属性没有值,设置之后网页没有历史记录,也就是没有后退、前进
    // 4. 处于活跃的 router-link 标签,会有一个默认类名: router-link-active
    //    可以在用此类名修改活跃标签的一些样式,活跃标签的默认类名也可以修改
    //    修改当前router-link标签的活跃类名:给当前标签添加属性active-class='新类名'
    //    修改所有router-link标签的活跃类名:路由对象中添加一个属性linkActiveClass:'新类名'
    
    
  6. 如果不想用router-link 标签来跳转页面。也可以通过其他方式:

    // 例如:把router-link标签换成button,然后监听button的点击事件,
    //      在script标签的导出对象中,添加组件方法methods
          methods:{
          	click () {
    			this.$router.push('/home')
    		} 
          }    
    // 注:每个组件中都会有一个路由对象$router,通过当前组件对象this调用
    //    用phsh方法更改页面路径,或者replace方法也行
        push()  // 有历史记录
        replace() //没有历史记录
    

6. 动态路由

6.1 什么是动态路由

  1. 在某些情况下,一个页面的path路径可能是不确定的,比如我们进入用户界面时,希望是如下路径:
    // 1. /user/aaa 或者 /user/bbb
    // 2. 除了前面的/user之外,后面还跟上了用户的ID
    // 3. 这种path和Component的匹配关系,我们称之为动态路由(也是路由传递数据的一种方式)
    // 4. 动态路由绑定映射关系的语法:
    	   {
                path:'/user/:userId',
                component:User
           }
    // 注::userId 是 /user/aaa中的aaa部分,只要是/user/aaa、/user/bbb都可以映射到这个路由
    //     在组件中this.$route.params.userId可以获取动态路由的动态路径
    
    

6.2 $router$route的区别

  1. $router: 是路由对象,在每个组件中都可以用this.$router访问路由对象
  2. $route: 是处于活跃状态的路由映射组件,在每个组件中都可以通过this.$route访问路由对象中单个活跃组件对象
  3. 注:在组件的模板中不需要加this

6.3 动态路由传递参数的方式

  1. 传递参数有两种方式:paramsquery
  2. params 的方式:需要传递的数据较少的时候使用
    // 1. 配置路由格式:
    	/tputer/:id
    // 2. 传递方式:在path后面跟上对应的值
    	<router-link :to="'/home/'+userId" tag='button' replace>首页</router-link> // userId 就是拼接上的值
    // 3. 传递后形成的路径:
    	/router/123 
    //===============================================
    // 代码跳转,比如,点击标签触发事件函数跳转
    // 在事件函数中:
    $router.push('/home/'+this.userId)
    
  3. query 的方式:需要传递数据较多的时候使用
    // 1. 配置路由格式:/profile,也就是普通配置
    // 2. 传递方式:对象中使用query的key作为传递方式
    	<router-link :to="{path:'/profile',query:{name:'张三',age:18}}" >file</router-link>
    // 3. 传递后形成的路径:/router?id=123
    // 4. 通过$route.query可以获取传递的对象 
    //================================================
    // 代码跳转,比如,点击标签触发事件函数跳转
    // 在事件函数中:
    $router.push({
    	path: '/profile',
    	query: {
    		name: '张三',
    		age: 18
    	}
    })    
    

7. 路由懒加载

  1. 通常路由中会定义很多不同的页面,这些页面最终打包的时候,会放在一个js文件中
  2. 页面越多,js文件就会越大,如果一次性从服务器请求下来,可能需要花费一定时间,甚至用户的电脑上还会出现短暂的
    空白情况
  3. 使用懒加载就可以避免这种情况
  4. 路由懒加载的主要作用是将路由对应的组件打包成一个个的js代码块
  5. 只有在这个路由被访问到的时候,才加载对应组件
  6. 懒加载的方式:在路由页面中用这种方式导入组件模块
    // AMD写法:
    	const About = resolve => require(['../components/About.vue'],resolve)
    // ES6写法:
    	const Home = () => import('../components/Home.vue')
    	// 开发中推荐使用这种方法导入组件
    

8. 嵌套路由

  1. 嵌套路由是一个很常见的功能,比如在home页面中,我们希望通过/home/news/home/message访问一些内容
  2. 一个路径映射一个组件,访问这个路径也会分别渲染两个组件
  3. 实现路由嵌套的步骤:
     // 1. 创建对应的子组件,并且在路由映射中配置对应的子路由
                   {
                      path:'/home',
                      component:Home,
                      children:[
                           {
                             path:'homenews',     // homenews 前面不需要加 / ,访问的时候会自动 /Home/homenews拼接
                             component:HomeNews
                           },
                           {
                             path:'homemessage',
                             component:HomeMessage
                           }
                      ]
                   }
     //           注:要先导入子组件,用懒加载的方式映射关系中子路径前面不需要加父路径
    // 2. 在Home组件内部使用<router-view>标签
                <div id="about">
                    <h2>我是首页</h2>
                    <p>昨夜雨疏风骤</p>
                    <router-link to='/home/homenews'>新闻</router-link>
                    <router-link to='/home/homemessage'>消息</router-link>
                    <router-view></router-view>
                </div>
    

9. 导航守卫

  1. 导航守卫是一个函数:beforeEach

9.1 路由导航实现改变页面 title 标题

  1. 比如用导航守卫每跳转一个路由页面就改变页面标题

  2. 在每个路由中创建属性

     {
          path:'/about',
          component:About,
          meta:{
             title:'关于'
          }
     }
    
  3. 实现方法:在路由页面使用路由对象调用方法beforeEach

    // beforeEach是全局导航
     router.beforeEach((to, from, next) => {
            document.title = to.matched[0].meta.title  // document.title = 可以改变页面标题
            next()									   // 	
     })
    // 注:这是路由的方法,路由的页面跳转是因为内部调用了 beforeEach 方法,而方法内部
    //     又调用了next()实现的。在这里我们要重写 beforeEach 方法。
    //     重写beforeEach方法,是想要在页面跳转的时候改变跳转页面的 title (标题)值
    //     方法的的参数是一个函数
    //     函数有三个参数:to--->要跳转的目标页面对象
    //                    from--->从这里跳转的当前页面对象
    //                    next()--->实现页面跳转的方法 
    
  4. document.title = '首页',用DOM对象改变页面的title值。

9.2 路由导航控制访问权限

  1. 如果用户没有登录就直接通过 URL 访问特定页面,需要重新导航到登录页面
    // 1. 为路由对象添加 beforeEach 导航守卫
    	router.beforeEach((to, from, next) => {
    		// 2. 如果用户访问的是登录页面,直接放行
    		 	if (to.path === '/login') return next()
    		// 3. 从 sessionStorage 中获取到保存的 token 值
    		 	const tokenStr = window.sessionStorage.getItem('token')
    		// 4. 如果没有 token 就强制跳转到登录页,有的话就直接 next() 跳转
    			if (!tokenStr) return next('/login')
    			next()
    	})
    // to: 跳转的目标页面
    // from: 从这跳转的当前页面
    // next(): 实现跳转的方法,里面也可以传入参数(要跳转的路由)
    

10. 路由页面不销毁

  1. 访问了a页面的的子页面,当跳转到别的页面之后,当前页面就会销毁,想要不销毁有一个办法:

     // 在路由App.vue模板页面: 
     	<keep-alive>
             <router-view></router-view>
        </keep-alive>
     //  注:keep-alive可以保持组件不被销毁,而是被缓存起来。
     //        如果某些页面不希望被缓存,那么就可以使用keep-alive的一个属性:exclude='组件的name值'
     //        如果多个页面name值用逗号隔开(不要加空格)
    
  2. 如果想回到a页面还希望保持离开时的样子,就可以这样做:

    // 在a页面的组件中: 在data中创建 path:'初始页面'    
          activated(){
              	// 把页面压栈到路由中显示,进入页面的时候改变页面路径
                this.$router.push(this.path)
           },
           beforeRouteLeave(to, from, next){
                // 记录离开时的路径,赋值给path属性 
                this.path = this.$route.path
                next()
           } 
           // activated、beforeRouteLeave是组件内导航
    

11. 路由中的方法

  1. router.push() 导航到不同的 url,向 history 栈添加一个新的记录。(=== window.history.pushState)
    // 字符串
    router.push('home')
    
    // 对象
    router.push({ path: 'home' })
    
    // 命名的路由
    router.push({ name: 'user', params: { userId: '123' }})
    
    // 带查询参数,变成 /register?plan=private
    router.push({ path: 'register', query: { plan: 'private' }})
    
声明式编程式
< router-link :to="" replace>router.push()
  1. router.replace() 导航到不同 url,替换 history 栈中当前记录。(=== window.history.replaceState)

  2. router.go(n)指定前进/回退的步数。n 为正数的时候是前进;负数的时候是后退;0的时候是刷新当前页面。(===window.history.go)

    // 在浏览器记录中前进一步,等同于 history.forward()
    router.go(1)
    
    // 后退一步记录,等同于 history.back()
    router.go(-1)
    
    // 前进 3 步记录
    router.go(3)
    
    // 如果 history 记录不够用,那就默默地失败呗
    router.go(-100)
    router.go(100)
    
  3. router. forward():前进一步。

  4. router.back():回退一步。

注意:当你点击 时,这个方法会在内部调用,所以说,点击 等同于调用 router.push()。
参考:编程式导航https://router.vuejs.org/zh/guide/essentials/navigation.html

12. vue 组件的 scrollBehavior-滚动行为

  1. 使用前端路由,当切换到新路由时,想要页面滚到顶部,或者是保持原先的滚动位置,就像重新加载页面那样。 vue-router 能做到,而且更好,它让你可以自定义路由切换时页面如何滚动。
  2. 注意: 这个功能只在支持 history.pushState 的浏览器中可用。
  3. 在文档页面拉动滚动条,然后刷新浏览器会发现滚动条依然在原来的位置,这是浏览器的默认行为,会记录浏览器滚动条默认位置。
  4. 但是点击浏览器“前进/后退”按钮,会发现当初那个页面的滚动条从0开始了,没有记录上一次滚动条的位置。现在要求点击浏览器“前进/后退”按钮,页面滚动条要记录上一次的位置,这时需要设置它的的滚动行为。
  5. 这时候需要在路由配置中设置 scrollBehavior(to,from,savePosition)函数,函数有三个参数。scrollBehavior() 函数在点击浏览器的“前进/后退”,或者切换导航的时候触发。
    // 使用方法
    const router = new VueRouter({
      routes: [...],
      scrollBehavior (to, from, savedPosition) {
      // return 期望滚动到哪个的位置
      }
    })
    // scrollBehavior() 方法在点击浏览器的“前进/后退”,或者切换导航的时候触发。
    // to:要进入的目标路由对象,到哪里去
    // from:离开的路由对象,哪里来
    // savePosition:会记录滚动条的坐标,点击前进/后退的时候记录值{x:?,y:?}
    
  6. 开发中封装
    import Vue from 'vue'
    import Router from 'vue-router'
    import { scrollBehavior } from './utils'
    Vue.use(Router)
    const router = new Router({
     mode: 'history',
     scrollBehavior,
     routes: [
     ...routesPC,
     ...routesMO
     ]
    })
    export default router
    // 将 scrollBehavior 封装在工具类中
    
  7. scrollBehavior 方法接收 to 和 from 路由对象。第三个参数 savedPosition 当且仅当 popstate 导航 (通过浏览器的 前进/后退 按钮触发) 时才可用。
  8. 在该方法内,可以通过判断路由to,from两个对象来做一些必要的判断;
  9. savedPosition 参数是记录的上次滚动的位置;
  10. 通过return {x:number,y:number}来控制页面滚动的位置;
  11. 对于所有路由导航,简单地让页面滚动到顶部。
    scrollBehavior (to, from, savedPosition) {
    	return { x: 0, y: 0 }
    }
    
  12. 想要在后退时,滚动到上次滚动的位置,如果满足条件,savedPosition有值的情况下:
    scrollBehavior (to, from, savedPosition) {
      if (savedPosition) {
        return savedPosition
      } else {
     	return { x: 0, y: 0 }
      }
    }
    
  13. 注意:使用<keep-alive>,scrollBehavior才能生效。

12.2 新增情况:异步滚动

  1. 当页面数据需要请求加载有延迟的情况下,页面如果直接滚动,会出现滚动后,页面数据请求回来,DOM重新渲染,滚动失效的情况;
  2. 所以官方文档给补充了异步滚动的方法:
    scrollBehavior (to, from, savedPosition) {
      return new Promise((resolve, reject) => {
       setTimeout(() => {
    	  resolve({ x: 0, y: 0 })
       }, 500)
      })
    }
    // 这个会在返回后,有一定延迟再滚动,可以根据自己项目的具体情况进行一定修改,兼容;
    
  3. 注:我的项目mobile端数据加载使用的是vue-mugen-scroll滑动加载数据组件,网上没找到能触发它加载的方法,所以,在返回列表页后,数据刷新,只有一页数据,滚动到底,也找不到上次的数据,所以还是没有解决我的问题,但是这个方法是很好的,只是使用情况,会有限制,记录一下,以备后用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值