自定义指令v-login优雅实现登录保护

前言:本文介绍封装自定义指令v-login实现,点击某个元素时如果未登录弹出登录框登录,已经登录则执行对应的操作,以及该指令的扩展功能

问题背景与解决方案

自定义指令v-login优雅实现登录保护_第1张图片

在Web应用中,某些操作(如关注、收藏等)需要用户登录后才能执行。传统实现方式是在每个需要登录的操作前都添加登录校验逻辑,这会导致:

  • 代码冗余
  • 维护困难
  • 业务逻辑分散

解决方案:使用Vue自定义指令v-login统一处理登录校验,让代码更简洁、更专注于业务逻辑。

v-login指令核心功能

基本工作原理

  1. 拦截点击事件:自动检查用户登录状态
  2. 已登录情况
    • 执行元素原本绑定的点击事件
    • (可选)进行角色权限校验
  3. 未登录情况
    • 显示友好提示(默认或自定义)
    • 自动弹出登录框引导用户登录

优势对比

传统方式 v-login方式
每个操作单独校验 统一拦截处理
代码重复率高 逻辑集中管理
维护困难 修改一处即可全局生效

️ 技术实现详解

1. 核心指令代码

import { useUserStore } from "@/stores/user";
import { ElMessage } from "element-plus";
import type { Component, Directive } from 'vue';

interface DirectiveBinding {
  value: Function,
  oldValue: Function,
  arg: string,
  modifiers: Record<string, boolean>,
  instance: Component,
  dir: Directive
}

const handler = (binding: DirectiveBinding) => {
  const fn = binding.value
  const userStore = useUserStore()
  
  if (!userStore.isSign) {
    // 扩展的未登录处理方式
    if (binding.modifiers?.msg) {
      ElMessage.error('请先登录')
    }
    // 弹出登录框
    userStore.showLogin = true
    return
  }
  
  // 已登录执行回调
  fn?.()
}

const vLogin: Directive = {
  mounted(el, binding) {
    if (typeof binding.value !== 'function') return
    el.fn = handler.bind(el, binding)
    el.addEventListener('click', el.fn)
  },
  unmounted(el, binding) {
    if (typeof binding.value !== 'function') return
    el.removeEventListener('click', el.fn)
  }
}

export default vLogin

2. Pinia状态管理

import { defineStore } from 'pinia'
import { ref } from 'vue'

export const useUserStore = defineStore('user', () => {
  const showLogin = ref(false)
  const isSign = ref(false)
  return {
    isSign,
    showLogin
  }
})

3. 登录框组件

<template>
  <ElDialog v-model="visible" v-bind="dialogAttributes">
    <div class="login-box">
      <h1>这是一个登录框</h1>
    </div>
  </ElDialog>
</template>

<script setup>
import { useWsLoginStore } from '@/stores/ws.ts'
import { computed } from 'vue'

const loginStore = useWsLoginStore()

const visible = computed({
  get() {
    return loginStore.showLogin
  },
  set(value) {
    loginStore.showLogin = value
  }
})

const dialogAttributes = {
  'close-on-click-modal': false,
  width: '376',
  top: '7vh',
  center: true
}
</script>

使用指南

1. 注册指令

import { createApp } from 'vue'
import vLogin from '@/directives/v-login'

const app = createApp(App)
app.directive("login", vLogin)

2. 基础用法

<template>
  <button v-login="handleSecureAction">需要登录的操作</button>
</template>

<script setup>
const handleSecureAction = () => {
  console.log('用户已登录,执行安全操作')
}
</script>

3. 高级用法

带提示的登录校验

<button v-login.msg="handleSecureAction">带提示的登录操作</button>

自定义未登录处理

const handler = (binding: DirectiveBinding) => {
  // ...原有逻辑
  
  if (!userStore.isSign) {
    // 自定义处理逻辑
    if (binding.arg === 'custom') {
      return customLoginHandler()
    }
    // ...默认处理
  }
}

最佳实践建议

  1. 权限扩展:可在指令中添加角色权限校验
if (binding.modifiers?.admin && !userStore.isAdmin) {
  ElMessage.error('需要管理员权限')
  return
}
  1. 性能优化:对于频繁点击的元素,考虑添加防抖处理

  2. 多框架适配:封装为独立npm包,支持React等框架

  3. 测试覆盖:确保指令在各种边界条件下的稳定性

总结与展望

v-login指令通过Vue的自定义指令机制,优雅地解决了登录校验的代码冗余问题。它的优势在于:

  • 解耦:将登录校验与业务逻辑分离
  • 复用:一次实现,全局使用
  • 可扩展:支持多种自定义处理方式

未来可考虑:

  • 添加更多权限控制选项
  • 支持异步校验
  • 提供更丰富的配置项

你可能感兴趣的:(Vue,vue,vue.js,typescript,前端)