Дорога всегда есть, это зависит от того, хотите ли вы, чтобы меч пошел боком или нет.
Сцены
В недавней разработке в дизайне есть три страницы A, B и C. Представьте себе такое требование сценария:
- Покинуть страницу B и перейти на страницу C, кэшировать данные страницы B (keepAlive: true)
- Покинуть страницу B и войти на страницу A без кэширования данных страницы B (keepAlive: false)
концепция
-
keep-alive
- Когда keep-alive оборачивает динамические компоненты, экземпляры неактивных компонентов кэшируются, а не уничтожаются. Подобно переходам, keep-alive является абстрактным компонентом: он не отображает элемент DOM сам по себе и не появляется в цепочке родительских компонентов.
- Keep-alive: документация vue
-
Охранники внутри компонентов — beforeRouteLeave
- Вызывается при переходе от соответствующего маршрута компонента
- Может получить доступ к экземпляру компонента
this - Защита внутри компонентов: документация vue-router
Предыстория внешнего интерфейса: реализация компонента поддержки активности
- Добавьте определенные поля, такие как: 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)