Vue+Pinia+Tailwind实现未登录触发登录模态框方案问询
实现需登录功能的登录引导逻辑(Vue+Pinia+Tailwind)
所需条件
- 项目已集成Pinia并完成全局注册
- NavBar组件已在全局或页面中引入,登录模态框的显示状态可被全局控制
- 已明确哪些功能需要登录权限(比如收藏、下单、个人中心操作等)
实现步骤
1. 创建Pinia全局状态管理Store
新建stores/authStore.js,统一管理用户登录状态和登录模态框的显示:
import { defineStore } from 'pinia' export const useAuthStore = defineStore('auth', { state: () => ({ isLoggedIn: false, // 用户是否已登录 showLoginModal: false // 登录模态框显示状态 }), actions: { // 打开登录模态框 openLoginModal() { this.showLoginModal = true }, // 关闭登录模态框 closeLoginModal() { this.showLoginModal = false // 可选:关闭时重置表单输入 }, // 登录成功后更新状态 loginSuccess() { this.isLoggedIn = true this.closeLoginModal() } } })
2. 改造NavBar.vue中的登录模态框
将模态框的显示状态绑定到Pinia的全局状态,同时更新关闭、登录逻辑:
<template> <!-- NavBar其他内容 --> <!-- 登录模态框 --> <div v-if="authStore.showLoginModal" class="fixed inset-0 flex items-center justify-center bg-gray-800 bg-opacity-75"> <div class="relative bg-white lg:w-[70vw] w-[90vw] h-fit rounded-3xl"> <img src="@/assets/images/Modal/Intersect.png" alt="" class="w-full absolute rounded-t-xl"> <!-- 关闭按钮 --> <div class="relative top-0 flex justify-end"> <button class="absolute pr-4 pt-4" @click="authStore.closeLoginModal"> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="5" stroke="black" class="w-7 h-7"> <path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12" /> </svg> </button> </div> <div class="relative z-10 flex flex-col items-start justify-center h-fit lg:mt-[5rem] mt-[5rem] lg:ml-[6%] m-8"> <div class="mt-5 mb-5"> <h2 class="text-2xl lg:text-3xl font-bold">Welcome!</h2> <p class="text-xs lg:text-sm">Please log in to your account.</p> </div> <form @submit.prevent="handleLogin" class="lg:w-[40%] h-fit md:w-[40%] w-full mr-8"> <!-- 用户名输入 --> <div class="relative mb-4 w-full md:w-365"> <label for="username" class="block text-gray-700">Enter Username</label> <div class="relative"> <img src="@/assets/images/Modal/profile.png" class="absolute inset-y-0 left-0 mx-5 my-3" style="width: 15px;" alt="Username Icon" /> <input type="text" id="username" v-model="username" @input="validateUsername" class="w-full h-8 py-5 pl-10 border border-black rounded-xl" placeholder="Username"> <span v-if="usernameError" class="text-red-500 text-xs">{{ usernameError }}</span> </div> </div> <!-- 密码输入 --> <div class="relative mb-4"> <label for="lpassword" class="w-full text-gray-700">Enter Password</label> <div class="relative w-full"> <img src="@/assets/images/Modal/profile.png" class="absolute inset-y-0 left-0 mx-5 my-3" style="width: 15px;" alt="Username Icon" /> <img v-if="showPassword" src="@/assets/images/Modal/view.png" class="absolute inset-y-0 right-0 mx-3 my-3" style="width: 15px; cursor: pointer;" alt="Eye Icon" @click="togglePasswordVisibility"> <img v-else src="@/assets/images/Modal/hidden.png" class="absolute inset-y-0 right-0 mx-3 my-3" style="width: 15px; cursor: pointer;" alt="Eye Icon" @click="togglePasswordVisibility"> <input id="lpassword" v-model="lpassword" @input="validateLPassword" :type="showPassword ? 'text' : 'password'" class="w-full h-8 py-5 pl-10 border border-black rounded-xl" placeholder="Password"> <span v-if="lpasswordError" class="text-red-500 text-xs">{{ lpasswordError }}</span> </div> </div> <div class="hidden lg:block lg:flex items-center justify-between mb-4"> <p class="text-xs">Don't have an account? <button @click="openPrivacyModal" class="text-xs font-bold text-blue-600">Sign Up</button></p> <button @click="openForgotModal" class="text-xs text-blue-600 font-bold">Forgot Password?</button> </div> <div class="hidden lg:block lg:mt-10 text-center"> <button type="submit" class="lg:w-[8rem] w-full lg:px-4 py-2 text-white disabled:bg-blue-400 bg-blue-600 rounded-md" :disabled="!isLoginFormValid">Login</button> </div> <div class="lg:hidden lg:mt-10 text-center"> <button type="submit" :disabled="!isLoginFormValid" class="lg:w-[8rem] w-full lg:px-4 py-2 lg:mb-10 text-white disabled:bg-blue-400 bg-blue-600 rounded-md">Login</button> <button @click="openForgotModal" class="text-xs text-blue-600 mt-1">Forgot Password?</button> <button @click="openPrivacyModal" class="w-full mt-8 py-2 border border-blue-400 text-blue-600 bg-white rounded-md">Sign Up</button> </div> </form> </div> </div> </div> </template> <script setup> import { useAuthStore } from '@/stores/authStore' import { ref, computed } from 'vue' const authStore = useAuthStore() const username = ref('') const lpassword = ref('') const showPassword = ref(false) const usernameError = ref('') const lpasswordError = ref('') // 用户名验证逻辑(保留原有逻辑) const validateUsername = () => { // 你的验证代码 } // 密码验证逻辑(保留原有逻辑) const validateLPassword = () => { // 你的验证代码 } // 表单有效性判断 const isLoginFormValid = computed(() => { return !usernameError.value && !lpasswordError.value && username.value && lpassword.value }) // 切换密码可见性 const togglePasswordVisibility = () => { showPassword.value = !showPassword.value } // 登录处理 const handleLogin = async () => { try { // 替换为实际登录API请求 // const res = await api.login(username.value, lpassword.value) // 登录成功更新全局状态 authStore.loginSuccess() // 可选:登录成功后执行用户原本要触发的操作 } catch (err) { console.error('登录失败', err) } } // 打开注册模态框(根据实际逻辑实现) const openPrivacyModal = () => { // 你的注册模态框逻辑 } // 打开忘记密码模态框(根据实际逻辑实现) const openForgotModal = () => { // 你的忘记密码模态框逻辑 } </script>
3. 封装登录校验工具函数
新建utils/auth.js,实现通用的登录校验逻辑,避免重复代码:
import { useAuthStore } from '@/stores/authStore' export const requireAuth = (callback) => { const authStore = useAuthStore() if (authStore.isLoggedIn) { // 用户已登录,执行原功能 callback?.() } else { // 用户未登录,唤起登录模态框 authStore.openLoginModal() // 可选:记录用户待执行操作,登录成功后自动触发 // authStore.setPendingAction(callback) } }
4. 在需要登录的功能中调用校验逻辑
比如在收藏按钮、下单按钮等组件中使用:
<template> <button @click="handleFavorite" class="bg-blue-500 text-white px-4 py-2 rounded">收藏</button> </template> <script setup> import { requireAuth } from '@/utils/auth' const handleFavorite = () => { requireAuth(() => { // 这里写收藏功能的实际逻辑 console.log('执行收藏操作') }) } </script>
关键细节说明
- 模态框的显示/隐藏完全由Pinia全局状态控制,确保在任何页面调用都能保持一致性
- 登录成功后必须更新
isLoggedIn状态,避免重复唤起模态框 - 若需要支持登录后自动执行用户原操作,可在Pinia中添加
pendingAction状态,登录成功后调用该函数
内容的提问来源于stack exchange,提问作者Yvette Medrano
相关产品推荐
相关产品推荐

