Code前端首页关于Code前端联系我们

Vue Router里的href该怎么用?和普通a标签有啥区别?

terry 7小时前 阅读数 8 #Vue
文章标签 Vue Router;a标签

在Vue项目里做路由跳转时,好多刚入门的小伙伴都会犯懵:明明HTML里用a标签的href能跳转,咋到Vue里就不行了?Vue Router里到底该咋处理类似href的路由链接?今天咱把这些问题拆开来,从原理到实战一步步说清楚。

为啥Vue项目不能直接用a标签的href?

首先得明白Vue做的是单页应用(SPA),啥是单页?简单说,整个项目运行起来后,浏览器只加载一次HTML文件,后续切换页面靠JS动态替换页面里的组件,不会重新请求服务器

但普通HTML里的a标签,只要写了href(比如<a href="/about">关于我们</a>),点击时浏览器会直接发起新的HTTP请求,让服务器返回新页面,这就把SPA的“单页”优势搞没了——每次跳转都刷新页面,不仅体验差,还浪费性能。

所以Vue Router得搞一套“前端路由”的逻辑,既能让用户感觉是在跳转页面,又不触发全页刷新,这时候就不能直接用a标签的href,得换Vue Router提供的工具。

Vue Router里替代href的两种核心玩法

Vue Router给了两种主流方式处理路由跳转:一种是模板里用<router-link>组件,另一种是在JS里用编程式导航,这俩方式都能替代href,还能保证SPA的特性。

<router-link>组件的to属性

<router-link>是Vue Router专门搞的“路由链接组件”,作用和a标签类似,但内部是用JS处理跳转,不会刷新页面,它的to属性就相当于a标签的href,不过功能更灵活。

举个最简单的例子:想做个跳转到首页的链接,写法是<router-link to="/home">首页</router-link>,渲染到页面后,它会变成<a href="/home">首页</a>(具体href格式受路由模式影响,比如hash模式下是#/home),但点击时是通过Vue Router的逻辑切换组件,不是真的请求服务器。

如果要传参数(比如动态路由),to还能写成对象形式,比如有个用户详情页,路由规则是/user/:id,那可以这样写:

<router-link :to="{ name: 'userDetail', params: { id: 123 } }">用户123</router-link>  

这里用name匹配路由(路由配置里得给这个路由起nameuserDetail),params里的id就是动态参数,最终会生成类似/user/123的链接。

编程式导航:router.push等方法

有时候跳转不是写在模板里,而是要在JS逻辑里触发(比如点击按钮后跳转、接口请求成功后跳转),这时候得用编程式导航,Vue组件里可以通过this.$router调用方法,最常用的是push

比如点击“去关于页”按钮后跳转,可以这么写:

<button @click="goToAbout">去关于页</button>  

然后在methods里:

goToAbout() {  
  this.$router.push('/about')  
}  

要是带查询参数(比如?name=xxx),可以写成对象形式:

this.$router.push({ path: '/search', query: { name: 'Vue' } })  

这样跳转后地址栏会变成/search?name=Vue,页面也会切换到Search组件。

<router-link>和普通a标签href的细节差异

虽然<router-link>最终会被渲染成a标签,但它和普通a标签的href比,藏着不少“小心思”,这些细节能帮咱少踩坑。

页面刷新的本质区别

普通a标签href:点击后浏览器直接发请求,服务器返回新页面,整个页面重新加载(包括HTML、CSS、JS全重新来一遍)。

<router-link>:点击后是Vue Router在前端做路由切换,只更新页面里的组件内容,浏览器不会发新的HTTP请求,也不会刷新整个页面,这也是SPA能实现“秒切页面”的关键。

路由模式的自动适配

Vue Router有两种路由模式:hash模式(地址栏带,比如#/home)和history模式(地址栏像普通URL,比如/home)。

<router-link>会自动根据你配置的模式生成对应的href,比如配了history模式,to="/home"就生成href="/home";要是hash模式,就生成href="#/home",但如果手动写a标签的href,得自己判断模式加,很容易写错。

激活状态的自动处理

做导航栏时,通常需要给当前选中的链接加个高亮样式。<router-link>会自动给当前匹配的路由加两个class:router-link-active(模糊匹配)和router-link-exact-active(精确匹配),咱只要在CSS里写这两个class的样式,就能实现高亮。

但普通a标签得自己写逻辑:监听路由变化,判断当前路径是否匹配,再动态加class,麻烦不说,还容易出错。

实际开发中容易踩的坑和解决办法

就算懂了基本用法,实际写代码时还是会掉坑里,这里列几个高频问题,讲讲咋避坑。

动态路由传参时to的写法错误

很多人想传params参数时,会写成这样:

<router-link :to="{ path: '/user/:id', params: { id: 123 } }">...</router-link>  

结果发现参数没传过去,地址栏还是/user/:id,咋回事?

因为Vue Router的规则是:path的时候,params会被忽略!必须用name来匹配路由,再传params,正确写法是:
先给路由配置加name(比如路由规则里写{ path: '/user/:id', name: 'user', component: User }),

<router-link :to="{ name: 'user', params: { id: 123 } }">...</router-link>  

这样参数才会被正确解析成/user/123

编程式导航时this.$router未定义

遇到这个问题,大概率是在非Vue组件的JS文件里用了this.$router,或者组件没正确引入Vue Router。

解决办法:如果是在Vue组件里,确保组件是通过Vue实例创建的(比如用Vue.extend或者单文件组件),这样this才会指向Vue实例,能拿到$router,如果是在单独的JS工具文件里,得手动导入router实例(比如在router.js里导出了router,工具文件里import router from './router',然后用router.push())。

路由跳转后页面滚动位置不对

SPA切换组件后,页面不会自动滚到顶部,还是停留在之前的位置,体验很差,这时候要配置Vue Router的滚动行为

router.js里加这段代码:

const router = new VueRouter({  
  routes,  
  scrollBehavior(to, from, savedPosition) {  
    // 每次跳转后滚到顶部  
    return { x: 0, y: 0 }  
  }  
})  

这样不管从哪个页面跳过来,新页面都会自动滚到顶部,如果想恢复之前的滚动位置(比如浏览器的回退操作),可以判断savedPosition,返回savedPosition就行。

进阶:路由元信息与权限控制里的href逻辑

实际项目里,不是所有页面都能随便访问(比如个人中心得登录后才能进),这时候就算有人想手动写a标签的href绕开权限,也得被拦截,这就得结合路由元信息(meta)导航守卫来搞。

先给需要权限的路由加meta

{  
  path: '/profile',  
  name: 'profile',  
  component: Profile,  
  meta: { requiresAuth: true } // 标记需要登录  
}  

然后在router.beforeEach导航守卫里判断:

router.beforeEach((to, from, next) => {  
  if (to.meta.requiresAuth && !isLogin()) { // isLogin()是判断是否登录的函数  
    next('/login') // 没登录就跳登录页  
  } else {  
    next() // 正常跳转  
  }  
})  

这样不管是用<router-link>还是编程式导航,只要访问需要权限的页面,都会被守卫拦截,就算有人手动在地址栏输/profile,也会被重定向到登录页,保证权限控制生效。

这里也能看出,Vue Router的跳转逻辑是“全链路可控”的——不管是模板里的链接还是JS里的跳转,都逃不过导航守卫的检查,这也是它比普通a标签href强大的地方。

Vue Router里没有直接对应的href属性,而是用``的to属性和编程式导航来替代,这么做既是为了满足SPA不刷新页面的需求,也是为了让路由跳转更灵活、更可控(比如传参、激活状态、权限控制这些),理解透这俩核心方式,再避开那些常见的小坑,Vue路由这块儿就稳了~要是还有啥细节没搞懂,评论区随时喊我!

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门