Appearance
手机号未验证 弹窗
本节目标:理解“手机号未验证 弹窗”的核心思路,并能把它用于实际开发或面试表达。 👌 那我把 手机号未验证 → 在
(public).layout.vue里自动弹窗 的最小实现片段写出来。我们之前在beforeResolve里已经约定了:当用户未验证手机时,会给路由 query 打上phone_verify=0标记。layout 只要监听这个标记,就能拉起弹窗。
** (public).layout.vue **中新增代码
ts
<script setup lang="ts">
import { ref, watch } from 'vue'
import { useRoute } from 'vue-router'
const route = useRoute()
// 手机号验证弹窗的开关
const phoneVerifyVisible = ref(false)
// 复杂逻辑:监听路由 query 中的 phone_verify=0
watch(
() => route.query.phone_verify,
(val) => {
if (val === '0') {
phoneVerifyVisible.value = true
} else {
phoneVerifyVisible.value = false
}
},
{ immediate: true },
)
</script>
<template>
<div>
<router-view />
<!-- 手机号验证弹窗 -->
<PhoneVerifyDialog v-model:visible="phoneVerifyVisible" />
</div>
</template>说明
- 守卫部分(在
beforeResolve已经写好):- 如果
user.userInfo.phone_verify === false,会在 URL query 上打标?phone_verify=0。 - 这样即使刷新页面,也能保持状态。
- 如果
- layout 部分:
- 监听
route.query.phone_verify。 - 值为
"0"就打开弹窗,否则关闭。 - 弹窗组件可以是你已有的
PhoneVerifyDialog,用v-model:visible控制。
- 监听
要不要我帮你把 beforeResolve 守卫和这个 watch 联动起来,做一份完整的 手机号验证拦截 + 弹窗触发 教程版本?
好,给你一份「手机号未验证 → 守卫打标 → 布局弹窗 → 验证成功清标」的落地教程版。 按你的要求:只给需要修改/新增的代码,且复杂逻辑一行注释写在代码上一行。
1) 在** beforeResolve 守卫里:未验证时打 ?phone_verify=0 **标记
> 位置:你项目的守卫注册文件(例如 src/router/guards/index.ts)里 beforeResolve 阶段。
ts
// 复杂逻辑:“哪些路由不触发手机校验弹窗”白名单(登录页/中转页等)
const PHONE_VERIFY_EXCLUDE = new Set(['user', 'user.login', 'redirect'])
/** 在你的 beforeResolve 数组中新增这个 guard(或合并到现有的手机号校验 guard) */
;async (to, _from, next) => {
const user = useUserStore()
const needAuth = to.matched.some((r) => r.meta?.requiresAuth !== false) // 默认收紧:需要登录
// 复杂逻辑:仅在需要登录+已登录 的情况下考虑手机校验
if (!needAuth || !user.isLoggedIn) return next()
// 复杂逻辑:排除不弹窗的页面(避免循环/无效提示)
if (PHONE_VERIFY_EXCLUDE.has(String(to.name || ''))) return next()
// 复杂逻辑:未验证 → 给 URL 打 phone_verify=0 标记,由 layout 监听并弹窗(replace 避免历史污染)
if (user.userInfo?.phone_verify === false) {
if (to.query.phone_verify !== '0') {
return next({
name: String(to.name || ''),
params: to.params,
query: { ...to.query, phone_verify: '0' },
replace: true,
})
}
return next()
}
// 复杂逻辑:已验证但 URL 还残留 phone_verify=0 → 清理标记,保持干净 URL
if (to.query.phone_verify === '0') {
const { phone_verify, ...rest } = to.query
return next({ name: String(to.name || ''), params: to.params, query: rest, replace: true })
}
next()
}2) 在** (public).layout.vue **里:监听标记并弹出验证弹窗
> 位置:src/views/(public)/layout.vue > 你已有大段布局,这里只加少量代码。
ts
<script setup lang="ts">
import { ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useUserStore } from '@/store'
const route = useRoute()
const router = useRouter()
const userStore = useUserStore()
// 复杂逻辑:控制手机号验证弹窗显隐
const phoneVerifyVisible = ref(false)
// 复杂逻辑:监听 ?phone_verify=0 → 打开弹窗;否则关闭
watch(
() => route.query.phone_verify,
(val) => {
phoneVerifyVisible.value = val === '0'
},
{ immediate: true },
)
// 复杂逻辑:验证成功回调——更新本地用户信息,并清除 URL 标记
const onPhoneVerifySuccess = () => {
userStore.setUserInfo({ phone_verify: true })
const { phone_verify, ...rest } = route.query
router.replace({ name: String(route.name || ''), params: route.params, query: rest })
}
// 复杂逻辑:用户手动关闭弹窗(未完成验证)——只关闭 UI,不清标记;下次进入仍会提示
const onPhoneVerifyClose = () => {
phoneVerifyVisible.value = false
}
</script>vue
<template>
<!-- 你现有的布局保持不变 ... -->
<!-- 复杂逻辑:在根布局里挂一个手机号验证弹窗;用 v-model:visible 控制开关 -->
<PhoneVerifyDialog
v-model:visible="phoneVerifyVisible"
@success="onPhoneVerifySuccess"
@close="onPhoneVerifyClose"
/>
</template>> 说明: > > - 成功:设置 phone_verify=true,并 清掉 URL 标记,URL 保持干净。 > - 关闭:只关弹窗,不改 URL;今后再次进入需要登录的页面仍会弹。你也可以在 onClose 时把标记改成 phone_verify=1 来“一次会话内不再提示”,这是产品策略问题。
3) 在验证弹窗组件中:****@success** **时通知父层
> 位置:src/components/PhoneVerifyDialog.vue(或你的弹窗所在处) > 只给你事件声明与触发要点。
ts
<script setup lang="ts">
import { defineEmits, defineProps } from 'vue'
const props = defineProps<{ visible: boolean }>()
const emit = defineEmits<{
(e: 'update:visible', v: boolean): void
(e: 'success'): void
(e: 'close'): void
}>()
// 复杂逻辑:调用后端接口校验手机号成功时,通知父组件
const handleVerifySuccess = () => {
emit('success')
emit('update:visible', false)
}
// 复杂逻辑:用户点击关闭
const handleClose = () => {
emit('close')
emit('update:visible', false)
}
</script>4) 登录完成后“拉起弹窗”的两种策略(2 选 1)
** **✅****(推荐)由守卫统一处理
- 你已经在
beforeResolve实现了“已登录 + 未验证 → 标记?phone_verify=0”。 - 所以登录成功后跳转任何业务页,都会触发标记 → 弹窗拉起。
- 不需要在
login/register逻辑里耦合 UI。
备选:登录成功后显式跳回当前页并打标
> 如果某些场景你想“立刻弹窗”,可以在登录成功回调里加一行:
ts
// 复杂逻辑:登录成功以后,若未验证,给当前目标补标记(通常不需要,因为守卫会做)
if (userStore.userInfo?.phone_verify === false) {
router.replace({ name: 'redirect', query: { to: `${targetPath}?phone_verify=0` } })
}5) 避免循环与边界处理
- 循环保护:我们用了
PHONE_VERIFY_EXCLUDE路由白名单(如user、redirect),并且只有在 未带标记 时才 replace 加标记,所以不会无限跳。 - 刷新可恢复:标记在 URL 上,刷新仍能被 layout 监听到 → 弹窗继续。
- 成功后清理:
onPhoneVerifySuccess里router.replace清标记,干净。 - 手动关闭:不清标记,下一次进入仍拉起(可以根据产品需求调整为会话内不再提示)。
以上就是“守卫打标 → 布局监听 → 弹窗验证 → 成功清标”的完整闭环。 如果后续你想把“会话内不再提示”也加上,我可以再给你最小改动(比如用 sessionStorage.setItem('phone_verify_snooze','1') 做 30 分钟免打扰)。
