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

vue router link 怎么实现 disabled 效果

terry 2天前 阅读数 24 #Vue
文章标签 vue router;disabled

做 Vue 项目时,不少同学会碰到这样的需求:导航栏里某个路由链接暂时不能点,比如权限不够、步骤没完成,得让 <router-link> 有“禁用”的效果,但 Vue Router 的 <router-link> 组件本身没提供 disabled 属性,这该咋实现呢?下面从样式、逻辑、实际场景这些角度一步步拆解。

先搞懂 为啥没有原生 disabled

<router-link> 本质是个“路由导航组件”,核心作用是生成可跳转的链接(默认渲染成 <a> 标签)并处理路由跳转逻辑,从设计层面来说,它更关注“导航”行为,而非像 <button> 那样主打“交互状态控制”,所以官方没内置 disabled 属性,需开发者自己组合样式逻辑来模拟禁用效果。

样式层面:让路由链接“看起来禁用”

用户首先得从视觉上感知“这个链接点不了”,所以第一步要调整样式,常见思路有这些:

改颜色、光标,模拟禁用态

<router-link> 加动态 class,控制颜色变灰、光标变成“不可点击”,示例:

<template>  
  <router-link  
    to="/target"  
    :class="{ 'disabled-style': isDisabled }"  
  >目标页面</router-link>  
</template>  
<style scoped>  
.disabled-style {  
  color: #ccc; /* 文字变灰 */  
  cursor: not-allowed; /* 光标显示“不可点击” */  
  text-decoration: none; /* 去掉下划线(如果有) */  
}  
</style>  

这里用 :class 动态绑定,当 isDisabledtrue 时,就会应用 .disabled-style 的样式。

慎用 pointer-events: none

有些同学会用 CSS 的 pointer-events: none; 让元素“无视鼠标事件”,示例:

.disabled-style {  
  pointer-events: none;  
}  

这么做确实能阻止点击,但有副作用:不仅点击跳转被禁,hover 提示、右键菜单等鼠标事件也会被屏蔽,如果需求是“禁用时要弹出‘权限不足’提示”,用这个属性就实现不了——因为点击事件根本触发不了,所以这种方式适合“纯视觉禁用 + 完全不能交互”的场景,多数业务场景更推荐结合逻辑判断(而非全靠 CSS 屏蔽)。

逻辑层面:真正阻止路由跳转

只改样式还不够,得从逻辑上拦住跳转(毕竟用户按回车、或 JS 触发点击时,仍可能跳转),这时候要结合“事件拦截”处理。

拦截 的点击事件

<router-link> 是 Vue 组件,它的点击事件是原生 DOM 事件,所以要用 @click.native 监听,然后在事件里判断是否禁用,阻止默认行为,示例:

<router-link  
  to="/target"  
  :class="{ 'disabled-style': isDisabled }"  
  @click.native="handleClick"  
>目标页面</router-link>  
<script>  
export default {  
  data() {  
    return {  
      isDisabled: true // 假设禁用状态由这个变量控制  
    }  
  },  
  methods: {  
    handleClick(event) {  
      if (this.isDisabled) {  
        event.preventDefault(); // 阻止默认跳转行为  
        this.$message.warning('该功能暂不可用'); // 提示(需结合 UI 库,如 Element Plus)  
        return;  
      }  
      // 不禁用的话,正常跳转(router-link 会自动处理 to 的跳转,无需额外操作)  
    }  
  }  
}  
</script>  

这里的关键是 event.preventDefault()——它能阻止 <router-link> 默认的跳转逻辑,配合之前的样式,用户既能看到“禁用”的视觉,点击时也会被拦截并收到提示。

进阶:封装自定义路由链接组件

如果项目里很多地方要做“禁用路由链接”,重复写样式和事件太麻烦,可以封装一个 <MyRouterLink> 组件,把禁用逻辑和样式封装起来,示例:

<template>  
  <router-link  
    v-bind="$attrs"  
    :class="[$attrs.class, { 'disabled-style': disabled }]"  
    @click.native="handleClick"  
  >  
    <slot></slot>  
  </router-link>  
</template>  
<script>  
export default {  
  name: 'MyRouterLink',  
  props: {  
    disabled: Boolean, // 控制是否禁用  
    to: [String, Object] // 继承 router-link 的 to 属性  
  },  
  methods: {  
    handleClick(event) {  
      if (this.disabled) {  
        event.preventDefault();  
        this.$emit('disabled-click'); // 向外触发事件,方便父组件加提示  
        return;  
      }  
      this.$emit('click', event); // 正常点击时触发原事件  
    }  
  }  
}  
</script>  
<style scoped>  
.disabled-style {  
  color: #ccc;  
  cursor: not-allowed;  
}  
</style>  

用的时候就像这样:

<MyRouterLink  
  to="/target"  
  :disabled="isDisabled"  
  @disabled-click="showTip"  
>目标页面</MyRouterLink>  

这样封装后,所有需要“禁用路由链接”的地方,直接用 <MyRouterLink> 即可,代码复用性拉满~

业务场景实战:不同需求下的禁用策略

光讲理论不够,结合实际场景看看咋用。

场景 1:权限控制(不同角色看到不同可点击链接)

后台管理系统里,管理员能点“系统设置”,普通用户不能点,这时可以结合“用户角色”和“路由元信息”控制。

<template>  
  <div class="nav">  
    <router-link  
      v-for="route in routes"  
      :key="route.path"  
      :to="route.path"  
      :class="{ disabled: !hasPermission(route) }"  
      @click.native="handlePermissionClick(route)"  
    >{{ route.name }}</router-link>  
  </div>  
</template>  
<script>  
export default {  
  data() {  
    return {  
      routes: [  
        { path: '/home', name: '首页' },  
        { path: '/setting', name: '系统设置', meta: { requiredRole: 'admin' } }  
      ]  
    }  
  },  
  computed: {  
    userRole() {  
      return this.$store.state.user.role; // 假设从 Vuex 取用户角色  
    }  
  },  
  methods: {  
    hasPermission(route) {  
      // 路由元信息里的 requiredRole,和用户角色匹配  
      return this.userRole === route.meta.requiredRole;  
    },  
    handlePermissionClick(route) {  
      if (!this.hasPermission(route)) {  
        this.$message.warning('您没有该功能权限');  
        return false; // 阻止事件传播  
      }  
    }  
  }  
}  
</script>  
<style scoped>  
.nav .disabled {  
  color: #999;  
  cursor: not-allowed;  
}  
</style>  

这里关键点:用 meta 给路由加“权限标记”,用 computed 实时取用户角色,点击时判断权限、拦截非法操作并提示。

场景 2:表单步骤导航(上一步/下一步禁用)

多步骤表单(比如注册流程),必须填完当前步骤才能点下一步,假设每一步对应不同路由(/step1/step2/step3)。

<template>  
  <div class="step-container">  
    <!-- 步骤 1 表单 -->  
    <input v-model="form.username" placeholder="用户名" />  
    <input v-model="form.password" type="password" placeholder="密码" />  
    <router-link  
      to="/step2"  
      :class="{ disabled: !isStep1Valid }"  
      @click.native="handleNext"  
    >下一步</router-link>  
  </div>  
</template>  
<script>  
export default {  
  data() {  
    return {  
      form: { username: '', password: '' }  
    }  
  },  
  computed: {  
    isStep1Valid() {  
      // 验证用户名和密码是否填写  
      return this.form.username.trim() && this.form.password.trim();  
    }  
  },  
  methods: {  
    handleNext(event) {  
      if (!this.isStep1Valid) {  
        event.preventDefault();  
        this.$toast('请先填写完当前步骤表单'); // 假设用 Vant 的 toast  
        return;  
      }  
      // 验证通过,正常跳转(router-link 会处理 to 的跳转)  
    }  
  }  
}  
</script>  

这种场景下,核心是“表单验证状态”和“路由跳转”的联动——只有验证通过,才允许跳转到下一步路由。

避坑指南:这些细节容易踩雷

实现过程中,有些细节没注意就会出问题,提前避坑!

@click@click.native 搞混

<router-link> 是 Vue 组件,它本身的“点击事件”不是原生 DOM 事件,而是组件内部的自定义事件,所以必须加 .native 修饰符才能监听到真实的点击行为。

<!-- 错误:监听不到原生点击 -->  
<router-link @click="handleClick"></router-link>  
<!-- 正确:监听原生点击 -->  
<router-link @click.native="handleClick"></router-link>  

pointer-events: none 导致提示弹不出

如果给 .disabled-style 加了 pointer-events: none,点击事件根本触发不了,就算写了 @click.native 也没用,所以要提示的场景,别用这个属性,改成“样式改颜色 + 光标,逻辑拦点击”的组合。

动态修改 isDisabled 后不生效

isDisabled 是通过计算属性或 Vuex 获取的,要确保它是响应式数据,如果是普通变量,Vue 监测不到变化,样式和逻辑都不会更新,解决方法:把 isDisabled 放在 data 里,或用 computed 返回状态。

同时用了 to 和手动 $router.push

有些同学为了“控制跳转”,既给 <router-link> 加了 to 属性,又在点击事件里用 this.$router.push,这样会导致跳转两次router-link 默认跳转 + 手动 push),正确做法是:要么靠 <router-link>to 自动跳转(拦截时阻止默认行为),要么不用 to、全靠手动 $router.push 控制。

实现 disabled 的核心思路

<router-link> 做“禁用”效果,本质是“视觉模拟 + 逻辑拦截”的组合拳

  1. 样式层:用 class 动态控制颜色、光标,模拟禁用的视觉状态;
  2. 逻辑层:用 @click.native 监听点击,判断禁用状态后阻止默认跳转、加提示;
  3. 复杂场景:封装自定义组件,减少重复代码;结合路由元信息、Vuex 等做权限/步骤控制。

<router-link> 的核心是“导航”,没有现成的 disabled 属性,但通过灵活组合 Vue 的类绑定、事件处理,完全能实现各种“禁用”需求~ 下次碰到类似场景,就按这个思路拆解,准没错!

版权声明

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

发表评论:

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

热门