Skip to content

手机号未验证 弹窗 ​

本节目标:理解“手机号未验证 弹窗”的核心思路,并能把它用于实际开发或面试表达。 👌 那我把 手机号未验证 → 在 (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>

说明 ​

  1. 守卫部分(在 beforeResolve 已经写好):
    • 如果 user.userInfo.phone_verify === false,会在 URL query 上打标 ?phone_verify=0。
    • 这样即使刷新页面,也能保持状态。
  2. 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 分钟免打扰)。

本站总访问 — 次