Browse Source

fix(frontend): 修复页面生命周期重复跳转导致的 routeDone 报错

微信开发者工具报 "routeDone with a webviewId N is not found",根因是同一
页面在生命周期钩子中重复发起跳转,框架对已销毁的 webview 调用 routeDone。

- splash/index: onShow 每次都新建 2s reLaunch 定时器且 onUnload 未清理;改为
  _hasLaunched 一次性守卫 + onUnload 清理定时器
- profile-extra/{create-child,edit-child,children}: onShow 自动跳转与按钮
  goToFamilyMembers 各发一次 redirectTo,统一收敛到 redirectOnce() 守卫
- rewards/rewards: teacher 分支 redirectTo 增加 _redirected 守卫,
  loadRewards() 仍保持每次 onShow 刷新

其余 5 处 onLoad redirectTo 为每实例仅执行一次的跳转桩,无并发风险,未改动。
全量注册页扫描:HIGH=0,无异步回调内的裸跳转。
liaoxg 3 days ago
parent
commit
926fc7dde2

+ 11 - 3
cfc-frontend/pages/profile-extra/children.vue

@@ -12,12 +12,20 @@
 <script>
 <script>
 export default {
 export default {
   onShow() {
   onShow() {
-    // 自动跳转到家庭成员页面
-    uni.redirectTo({ url: '/pages/profile-extra/family-members' })
+    // 自动跳转到家庭成员页面。
+    // onShow 可能重复触发,且与按钮的 redirectTo 叠加时会并发发起跳转,
+    // 让框架对已销毁的 webview 调用 routeDone,报
+    // "routeDone with a webviewId N is not found"。统一走一次性守卫。
+    this.redirectOnce()
   },
   },
   methods: {
   methods: {
-    goToFamilyMembers() {
+    redirectOnce() {
+      if (this._redirected) return
+      this._redirected = true
       uni.redirectTo({ url: '/pages/profile-extra/family-members' })
       uni.redirectTo({ url: '/pages/profile-extra/family-members' })
+    },
+    goToFamilyMembers() {
+      this.redirectOnce()
     }
     }
   }
   }
 }
 }

+ 10 - 2
cfc-frontend/pages/profile-extra/create-child.vue

@@ -12,11 +12,19 @@
 <script>
 <script>
 export default {
 export default {
   onShow() {
   onShow() {
-    uni.redirectTo({ url: '/pages/profile-extra/family-members' })
+    // onShow 可能重复触发,且与按钮的 redirectTo 叠加时会并发发起跳转,
+    // 让框架对已销毁的 webview 调用 routeDone,报
+    // "routeDone with a webviewId N is not found"。统一走一次性守卫。
+    this.redirectOnce()
   },
   },
   methods: {
   methods: {
-    goToFamilyMembers() {
+    redirectOnce() {
+      if (this._redirected) return
+      this._redirected = true
       uni.redirectTo({ url: '/pages/profile-extra/family-members' })
       uni.redirectTo({ url: '/pages/profile-extra/family-members' })
+    },
+    goToFamilyMembers() {
+      this.redirectOnce()
     }
     }
   }
   }
 }
 }

+ 10 - 2
cfc-frontend/pages/profile-extra/edit-child.vue

@@ -12,11 +12,19 @@
 <script>
 <script>
 export default {
 export default {
   onShow() {
   onShow() {
-    uni.redirectTo({ url: '/pages/profile-extra/family-members' })
+    // onShow 可能重复触发,且与按钮的 redirectTo 叠加时会并发发起跳转,
+    // 让框架对已销毁的 webview 调用 routeDone,报
+    // "routeDone with a webviewId N is not found"。统一走一次性守卫。
+    this.redirectOnce()
   },
   },
   methods: {
   methods: {
-    goToFamilyMembers() {
+    redirectOnce() {
+      if (this._redirected) return
+      this._redirected = true
       uni.redirectTo({ url: '/pages/profile-extra/family-members' })
       uni.redirectTo({ url: '/pages/profile-extra/family-members' })
+    },
+    goToFamilyMembers() {
+      this.redirectOnce()
     }
     }
   }
   }
 }
 }

+ 4 - 0
cfc-frontend/pages/rewards/rewards.vue

@@ -87,6 +87,10 @@ export default {
     // 规划师不适用心愿单,中转至成长规划师中心
     // 规划师不适用心愿单,中转至成长规划师中心
     const role = uni.getStorageSync('currentRole') || uni.getStorageSync('role') || 'parent'
     const role = uni.getStorageSync('currentRole') || uni.getStorageSync('role') || 'parent'
     if (role === 'teacher') {
     if (role === 'teacher') {
+      // 只跳转一次:onShow 重复触发时多次 redirectTo 会让框架对已销毁的
+      // webview 调用 routeDone,报 "routeDone with a webviewId N is not found"
+      if (this._redirected) return
+      this._redirected = true
       uni.redirectTo({ url: '/pages/teacher/index' })
       uni.redirectTo({ url: '/pages/teacher/index' })
       return
       return
     }
     }

+ 14 - 1
cfc-frontend/pages/splash/index.vue

@@ -47,10 +47,23 @@
 <script>
 <script>
 export default {
 export default {
   onShow() {
   onShow() {
+    // 只允许跳转一次。onShow 在 devtools 重渲染、前后台切换时会重复触发,
+    // 多个 reLaunch 并发会让框架对已销毁的 webview 调用 routeDone,
+    // 报 "routeDone with a webviewId N is not found"。
+    if (this._hasLaunched) return
+    this._hasLaunched = true
     // 显示 2 秒后自动跳转到首页
     // 显示 2 秒后自动跳转到首页
-    setTimeout(() => {
+    this._launchTimer = setTimeout(() => {
+      this._launchTimer = null
       uni.reLaunch({ url: '/pages/index-home/index' })
       uni.reLaunch({ url: '/pages/index-home/index' })
     }, 2000)
     }, 2000)
+  },
+  onUnload() {
+    // 离开启动页时清掉尚未触发的定时器,避免对已销毁的页面再发起 reLaunch
+    if (this._launchTimer) {
+      clearTimeout(this._launchTimer)
+      this._launchTimer = null
+    }
   }
   }
 }
 }
 </script>
 </script>