Мини-программа Бесконечная иерархическая схема маршрутизации (без зависимости от платформы)

Апплет WeChat

задний план

  • Мини-стек истории программы поддерживает только до 10 слоев
  • Когда небольшой программный бизнес более сложен, легко превысить 10 слоев.
  • После более чем 10 слоев некоторые модели не реагируют на нажатие, а некоторые модели будут иметь некоторые неизвестные ошибки.

Для решения этих проблем мы вводим бесконечную иерархическую схему маршрутизации.

строить планы

Прежде всего, я хотел бы заявить, что первоначальный план был предложен не мной, а исследователем Цинхуа из нашей компании. Но они обрабатываются на основе фреймворка wepy.Так как мы используем mpvue, то внесли изменения в эту схему, не полагаясь на фреймворк.

Хоть это и модифицированная версия, но принцип тот же.Позвольте представить модифицированную схему.

Несколько ключевых моментов:

  1. В пределах 9 этажей (включая 9 этажей): нормально зайти в собственный стек истории апплета, обновить стек логики при прыжке, тут нечего сказать
  2. Перейти с 9 уровня на 10 уровень: Нужно перенаправить 9-й этаж на страницу переноса, а потом прыгнуть со страницы переноса на 10-й этаж
  3. Прыжок после 10 уровня: Обрабатывается в методе navigationTo, после достижения 10-го слоя, а затем перехода на страницу 10-го слоя выполняется операция redirectTo (перенаправление)
  4. 10 этажей и выше возврат: он вернется на страницу передачи, судя по странице передачи, на какую страницу вернуться, а затем перейдет к (перейти) в прошлое.
  5. Возврат с 10 уровня на 9 уровень: Вернуться на страницу передачи, перенаправить на (перенаправить) страницу передачи на страницу 9-го слоя
  6. Возврат в пределах 9 этажей: Просто вернитесь напрямую, логический стек не будет обновляться при возврате, но это не имеет значения, потому что только страница передачи будет использовать логический стек
  7. Механизм обновления логического стека:
    1. Обновление при переходе и возврате на страницу переноса
    2. Обновлять при навигации
    3. Обновлять при перенаправлении
    4. Обновить при перезапуске
    5. Обновлять при переходе назад

Значок:

  1. Действие пользователя
  2. Мини-стек истории программ
  3. JS логический стек: самоуправляемый стек маршрутизации JS
  4. «Средний» указывает на страницу передачи
  5. «1 2 3 4 5 6 7 8 9 A B C» означает разные пути к страницам
Действие пользователя Мини-стек истории программ js логический стек Следовать за
1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 Перейти на страницу 9
1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 Перейти на страницу А
1 2 3 4 5 6 7 8 9 A 1 2 3 4 5 6 7 8 Средний А 1 2 3 4 5 6 7 8 9 A Перейти на страницу Б
1 2 3 4 5 6 7 8 9 A B 1 2 3 4 5 6 7 8 Средний Б 1 2 3 4 5 6 7 8 9 A B Перейти на страницу С
1 2 3 4 5 6 7 8 9 A B C 1 2 3 4 5 6 7 8 Средний С 1 2 3 4 5 6 7 8 9 A B C вернуть
1 2 3 4 5 6 7 8 9 A B 1 2 3 4 5 6 7 8 Средний Б 1 2 3 4 5 6 7 8 9 A B вернуть
1 2 3 4 5 6 7 8 9 A 1 2 3 4 5 6 7 8 Средний А 1 2 3 4 5 6 7 8 9 A вернуть
1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 return (логический стек не обновляется)
1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 9 return (логический стек не обновляется)
1 2 3 4 5 6 7 1 2 3 4 5 6 7 1 2 3 4 5 6 7 8 9 return (логический стек не обновляется)
1 2 3 4 5 6 1 2 3 4 5 6 1 2 3 4 5 6 7 8 9 return (логический стек не обновляется)
1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 6 7 8 9 Страница перехода 6
1 2 3 4 5 6 1 2 3 4 5 6 1 2 3 4 5 6 Перейти на страницу 7
1 2 3 4 5 6 7 1 2 3 4 5 6 7 1 2 3 4 5 6 7 ...

Внимательные читатели могли найти здесь:

Предыдущая операция перехода и операция возврата выше 10 уровней обновят логический стек, а операция возврата в пределах 10 уровней не обновит логический стек.

причина:

Это также главный пункт преобразования нашего первоначального плана. Потому что в пределах 10 слоев все возвраты и переходы берут на себя системный стек истории WeChat.

Нам просто нужно убедиться, что пользователь обновляется при переходе через API. Более того, поддерживаемый сам по себе стек логической маршрутизации фактически используется только транзитной страницей.

Таким образом, нет необходимости регистрировать хук onUnload на каждой странице для обновления информации о маршрутизации при возврате в режиме реального времени. Логика обновления маршрутной информации размещена на уровне вызовов API. Плевать на все во время развития бизнеса.

код схемы

lib/navigator/Navigator.js (метод перехода инкапсулирован сам по себе, код History.js опущен)

...
import History from '@/lib/navigator/History'
const MAX_LEVEL = 10 // 小程序支持打开的页面层数
export default class Navigator {
  // 中转页面路径
  static curtainPage = '/pages/curtain/curtain/main'
  // 最大页数
  static maxLevel = MAX_LEVEL
  // 逻辑栈
  static _history = new History({
    routes: [{ url: '' }],
    correctLevel: MAX_LEVEL - 2
  })
  
  ...
  
  /**
   * 打开新页面
   * @param {Object} route 页面配置,格式同wx.navigateTo
   */
  @makeMutex({ namespace: globalStore, mutexId: 'navigate' }) // 避免跳转相关函数并发执行
  static async navigateTo (route) {
    console.log('[Navigator] navigateTo:', route)
    // 更新逻辑栈
    Navigator._history.open({ url: route.url })

    let curPages = getCurrentPages()
    // 小于倒数第二层时,直接打开
    if (curPages.length < MAX_LEVEL - 1) {
      await Navigator._secretOpen(route) // 就是调用wx.navigateTo
    // 倒数第二层打开最后一层
    } else if (curPages.length === MAX_LEVEL - 1) {
      const url = URL.setParam(Navigator.curtainPage, { url: route.url })
      await Navigator._secretReplace({ url })  // wx.redirectTo 到中转页,再由中转页跳转到第10层页面
    // 已经达到最大层数,直接最后一层重定向
    } else {
      await Navigator._secretReplace(route)    // wx.redirectTo 第10层页面直接重定向
    }
  }
  
  /**
   * 完整历史记录
   * @return {Array}
   */
  static get history () {
    return Navigator._history.routes
  }
  
  /**
   * 更新路由
   * @param {Object} config 自定义配置,可配置项参见 _config 相关字段及注释
   */
  static updateRoutes (routes = []) {
    this._history._routes = routes
  }
  
  ...
}

Код транзитной страницы /pages/curtain/curtain/index.vue

<template>
  <div class="main"></div>
</template>
<script>
import Navigator from '@/lib/navigate/Navigator'
// query参数
let opts = null
// 是否为返回操作
let isBack = false

export default {
  onLoad (options) {
    // 缓存参数
    opts = options
    // 执行onLoad生命周期,认为是跳转或者重定向操作
    isBack = false
  },
  onShow () {
    // 跳转、重定向操作时,逻辑栈的状态会在跳转函数里更新
    if (!isBack) {
      const url = decodeURIComponent(opts.url)
      // 再返回时认为是返回操作
      isBack = true
      // 跳转操作
      if (opts.type === 'navigateTo') {
        Navigator._secretOpen({ url })      // 相当直接执行wx.navigateTo,不会更新逻辑栈
      // 重定向
      } else if (opts.type === 'redirectTo') {
        Navigator._secretReplace({ url })   // 相当直接执行wx.redirectTo,不会更新逻辑栈
      }
    // 返回操作
    } else {
      // 获取逻辑栈
      let routes = Navigator.history
      // 如果10层之外的返回,用navigateTo操作
      // 如果是10层返回到9层,用redirectTo操作
      const operation = (routes.length === Navigator.maxLevel) ? 'redirectTo' : 'navigateTo'
      // 获取要返回的页面路由
      let preRoute
      if (operation === 'navigateTo') {
        // 移除逻辑层中后两个元素:
        // 移除最后一个是因为要返
        // 移除倒数第二个是因为,跳转到倒数第二个页面时会重新插入逻辑栈
        preRoute = routes.splice(routes.length - 2, 2)[0]
      } else {
        // 重定向时只移除最后一个元素
        preRoute = routes[routes.length - 2]
        routes.splice(routes.length - 1, 1)
      }
      // 更新逻辑栈
      Navigator.updateRoutes(routes)
      // 执行自己包装的跳转、重定向方法,该操作会更新逻辑栈
      Navigator[operation](preRoute)
    }
  }
}
</script>
<style lang="scss">
  .main {
    background-color: $white-color;
  }
</style>

Принцип такой, но есть несколько моментов, на которые стоит обратить внимание:

  • Вам нужно вызвать свой собственный инкапсулированный метод перехода в бизнес-коде.

Помните, что нельзя вызывать API wx напрямую и не использовать компоненты, невозможно обновить логический стек js, правильный способ перехода: Navigator.navigateTo({ url: 'xxx' }).

  • При переходе своевременно обновляйте стек логики js (время обновления указано выше), потому что это напрямую повлияет на логику перехода страницы перехода

Самым большим преимуществом этой схемы является то, что нет необходимости следить за обновлением логического стека при выгрузке страницы, а также нет необходимости добавлять код обновления логического стека на каждую страницу.

Хорошо, на этот раз я расскажу так много. Если у вас есть какие-либо вопросы или у вас есть лучшее решение, вы можете оставить сообщение, чтобы общаться, и все могут учиться друг у друга.