vue3项目,实现账号密码错误,登录锁定且倒计时功能
2. 当剩余次数lockRemain为0以及有锁定时间秒数,使用localStorage存储,锁定时间秒数lockSeconds,以及解锁时间lockEndTime。如若锁定则进行倒计时。需要注意的点是,虽然localStorage可以在同一浏览器的不同标签页之间共享数据,但是,当我们在一个标签页中修改localStorage时,其他标签页不会自动收到更新通知。1)当我们打开一个登录标签页,此页面
需求:vue3项目中,在登录页面,账号密码输入错误,后台返回剩余次数lockRemain,锁定时间秒数lockSeconds。前端根据返回数据,锁定登录及倒计时等信息展示。
思路:
1. 当登录错误,后台返回剩余次数不为0时,页面展示账号密码错误,剩余几次机会。
2. 当剩余次数lockRemain为0以及有锁定时间秒数,使用localStorage存储,锁定时间秒数lockSeconds,以及解锁时间lockEndTime。lockEndTime为当前时间加上锁定秒数。 后续根据当前时间是否超过lockEndTime,判断是否需要锁定。如若锁定则进行倒计时。
localStorage知识点:
需要注意的点是,虽然localStorage可以在同一浏览器的不同标签页之间共享数据,但是,当我们在一个标签页中修改localStorage时,其他标签页不会自动收到更新通知。
1)当我们打开一个登录标签页,此页面登录多次错误锁定,我们存储在localStorage的信息,在重新打开一个新的登录页时,这个时候是能共享的。
2)但是当我们同时打开了两个登录标签页。在第一个标签页中,多次输入错误导致账户被锁定。此时,第一个标签页会更新localStorage中的信息并开始倒计时。但是,第二个标签页并不知道这个变化,它仍然显示为未锁定状态,仍然可以尝试登录。此时,我们需要监听`storage`事件,window.addEventListener('storage', )确保多个标签页之间的状态同步。
3)虽然浏览器确实提供了 storage 事件机制,但它仅适用于同源的不同标签页之间。对于当前标签页内的 LocalStorage 变化,却没有直接的方法来实现实时监听。此时通过手动创建并分发 StorageEvent, 使用 window.dispatchEvent(new StorageEvent('storage', { }))方式来实现。
实现代码如下:封装一个useLockTimer.js
import { ref, onMounted, onBeforeUnmount, computed } from 'vue'
export function useLockTimer() {
const isLocked = ref(false) // 是否锁定
const lockSeconds = ref(0) // 锁定秒数
const lockRemain = ref(0) // 剩余次数
let timer = null
// 检查锁定状态
const checkLockStatus = () => {
const lockData = localStorage.getItem('loginLock')
if (lockData) {
const { lockEndTime } = JSON.parse(lockData)
const currentTime = Date.now()
if (lockEndTime > currentTime) {
// 仍在锁定期内
const secondsLeft = Math.ceil((lockEndTime - currentTime) / 1000)
startCountdown(secondsLeft)
} else {
// 锁定已过期
localStorage.removeItem('loginLock')
isLocked.value = false
}
} else {
isLocked.value = false
}
}
// 开始倒计时
const startCountdown = (seconds) => {
isLocked.value = true
lockSeconds.value = seconds
clearInterval(timer)
timer = setInterval(() => {
lockSeconds.value -= 1
if (lockSeconds.value <= 0) {
clearLockTimer()
localStorage.removeItem('loginLock')
}
}, 1000)
}
// 设置锁定计时器
const setLockTimer = (lockSeconds) => {
const lockEndTime = Date.now() + lockSeconds * 1000
const lockData = JSON.stringify({
lockEndTime,
lockSeconds
})
localStorage.setItem('loginLock', lockData)
// 手动触发 StorageEvent,同步分发事件,实现同一页签下的监听
window.dispatchEvent(new StorageEvent('storage', {
key: 'loginLock',
newValue: lockData
}))
startCountdown(lockSeconds)
}
// 清除计时器
const clearLockTimer = () => {
clearInterval(timer)
timer = null
isLocked.value = false
lockSeconds.value = 0
}
// 初始化检查
onMounted(() => {
checkLockStatus()
// 监听存储数据变化
window.addEventListener('storage', handleStorageChange)
})
// 清理
onBeforeUnmount(() => {
clearLockTimer()
window.removeEventListener('storage', handleStorageChange)
})
// 处理跨标签页状态同步
const handleStorageChange = (event) => {
if(event.key === 'loginLock') {
checkLockStatus()
}
}
// 错误显示
const errorMessage = computed(() => {
if(lockRemain.value) {
return `用户名密码错误,剩余${lockRemain.value}次机会`
} else if(lockSeconds.value) {
return `系统已锁定,请等待${lockSeconds.value}秒`
} else {
return ''
}
})
return {
isLocked,
lockSeconds,
lockRemain,
checkLockStatus,
setLockTimer,
clearLockTimer,
errorMessage
}
}
然后在登录页面中引用该方法,如下:
<script setup>
import { useLockTimer } from '@/hooks/useLockTimer'
// 密码登录错误锁定功能
const { isLocked, lockSeconds, lockRemain, setLockTimer, errorMessage } = useLockTimer()
// 点击登录按钮事件
const login = () => {
// 请求后台接口返回中处理锁定功能
lockRemain.value = data.lockRemain
lockSeconds.value = data.lockSeconds
// 如果剩余次数为0,且有锁定时间,则锁定
if (lockRemain.value === 0 && lockSeconds.value) {
setLockTimer(lockSeconds.value)
}
}
</script>
页面展示如下:
<p v-html="errorMessage"></p>
<el-button :disabled="isLocked" type="primary" @click="login">登录</el-button>
更多推荐


所有评论(0)