Кэш VUE: динамическая поддержка активности

Vue.js

Дорога всегда есть, это зависит от того, хотите ли вы, чтобы меч пошел боком или нет.

脑壳疼.png

Сцены

В недавней разработке в дизайне есть три страницы A, B и C. Представьте себе такое требование сценария:

  • Покинуть страницу B и перейти на страницу C, кэшировать данные страницы B (keepAlive: true)
  • Покинуть страницу B и войти на страницу A без кэширования данных страницы B (keepAlive: false)

концепция

  • keep-alive

    • Когда keep-alive оборачивает динамические компоненты, экземпляры неактивных компонентов кэшируются, а не уничтожаются. Подобно переходам, keep-alive является абстрактным компонентом: он не отображает элемент DOM сам по себе и не появляется в цепочке родительских компонентов.
    • Keep-alive: документация vue
  • Охранники внутри компонентов — beforeRouteLeave

Предыстория внешнего интерфейса: реализация компонента поддержки активности

  • Добавьте определенные поля, такие как: keepAlive в метаинформацию о маршрутизации
  const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      children: [
        {
          path: 'bar',
          component: Bar,
          // a meta field
          meta: { 
            keepAlive: true 
          }
        }
      ]
    }
  ]
})
  • Тег keep-alive динамически используется в родительском компоненте в соответствии с полем keepAlive в маршруте.
  class Home extends Vue {

    get keepAlive () {
      // 获取当前路由的元信息中的keepAlive字段
      return this.$route.meta.keepAlive
    }

    private render () {
      return (
        <div>
          {
            !this.keepAlive && <router-view />
          }
          <keep-alive>
            {
              this.keepAlive && <router-view/>
            }
          </keep-alive>
        </div>
      )
    }
  }

  export default Home

идеи

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

План реализации

Вариант первый

  • Используйте beforeRouteLeave для изменения реализации keepAlive from (оригинальная идея, одно из сетевых решений, с ошибками)
beforeRouteLeave (to: any, from: any, next: any) {
  // 导航离开该组件的对应路由时调用
  // 判断是否是去往页面 C 
  if (to.name !== 'C') {
    // 不是去 C 页面,不缓存
    from.meta.keepAlive = false
  } else {
    // 是去 C 页面,缓存
    from.meta.keepAlive = true
  }
  next()
}

Ошибка: перейти на страницу C в первый раз, а затем вернуться на страницу B, B не имеет кеша и войти на страницу C во второй раз, страница B находится в кеше, и вход на страницу A не может очистить кеш страницы B

Вариант 2 (сетевое решение)

  • $уничтожить() уничтожить
beforeRouteLeave (to: any, from: any, next: any) {
  // 导航离开该组件的对应路由时调用
  // 判断是否是去往页面 C 
  if (to.name !== 'C') {
    // 不是去 C 页面,不缓存
    this.$destroy()
  }
  next()
}

ошибка: никогда не кешируется после уничтожения

Вариант 3 (сетевое решение)

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

Вариант 4 (оптимальное решение)

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

Решения для особых сценариев, когда ни одно из вышеперечисленных решений не может быть реализовано

специальная сцена

  • Этот проект является мобильным проектом, и атрибут включения поддержки активности не используется, и если вы хотите добавить его, необходимо изменить многие конфигурации проекта, что является хлопотным.

решение

  • Решение аналогично решению выше
  • разница:
    • Не используйте объект from в beforeRouteLeave, чтобы изменить keepAlive
    • Непосредственно управляйте keepAlive в соответствии с метаинформацией о маршрутизации в this.$router.
// 操作指定name的路由的元信息
private changeKeepAlive (parentName: string, name: string, keepAlive: boolean) {
  // @ts-ignore
  this.$router.options.routes.map((item: any) => {
    if (item.name === parentName) {
      item.children.map((a: any) => {
        if (a.name === name) {
          a.meta.keepAlive = keepAlive
        }
      })
    }
  })
}

beforeRouteLeave (to: any, from: any, next: any) {
    // 导航离开该组件的对应路由时调用
    // 可以访问组件实例 `this`
    if (to.name === 'C') {
      this.changeKeepAlive('Home', 'B', true)
    } else {
      this.changeKeepAlive('Home', 'B', false)
    }
    next()
  }

После тестирования это решение не будет иметь ошибки первого решения.

BY--LucaLJX (Гитхаб LucaLJX)