Лучшее решение для реализации кэширования в проектах vue

Vue.js

необходимость

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

Подводя итог в одном предложении: pageAList->pageADetail->pageAList, кешировать pageAList, и если статус коллекции видео необходимо обновить, другие страницы->pageAList, pageAList не кэшируются

В интернете я нашел много чужих методов, но ни один из них не подходит под наши нужды.

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

После эффекта

Нет картинки, нет правды, используйте гифку, чтобы увидеть эффект после реализации! ! !

Операционные процедуры:

  • Home->pageAList, перейти на вторую страницу -> Home->pageAList, номер страницы показывает первую страницу, указывая на то, что при входе в pageAList с других страниц страница pageAList не кэшируется
  • pageAList, перейти на третью страницу, нажать на видео 22 -> перейти на страницу сведений о видео pageADetail, нажать на Избранное, сбор выполнен успешно, нажать на возврат -> pageAList отображает третью страницу, а статус избранного видео 22 никогда не была добавлена ​​в избранное для коллекции, что указывает на то, что страница pageAList вводится из страницы pageADetail, страница pageAList кэшируется, а статус обновляется.

инструкция:

  • Кэш уровня 2: то есть из A->B->A, кеш A
  • Кэш L3: A->B->C->B->A, кеш A, B Так как большая часть проекта это кеш второго уровня, здесь мы будем делать кеш второго уровня, но это не значит, что мой метод кеширования не подходит для кеша третьего уровня. кеш третьего уровня позже.

Реализовать кеш второго уровня

Проект построен с использованием каркаса vue-cli2, и этот проект используется для иллюстрации того, как достичь Давайте сначала посмотрим на каталог проекта

Удален каталог бесполезных компонентов и каталог ресурсов, добавлен каталог src/pages и каталог src/store, страница pages используется для хранения компонентов страницы, store не так много говорит, хранит вещи, связанные с vuex, добавлен каталог server/app.js для запуска фоновые службы

1. Предпосылки

  • Проект представляет vue, vuex, vue-router, axios и другие ведра семейства vue.
  • Внедрение element-ui просто для красоты проекта.Ведь я ленив в поздней стадии рака и не хочу писать свой стиль.
  • Настройте внешний прокси-сервер в config/index.js.
  • Внедрите экспресс, запустите серверную часть, откройте порт 3003 на серверной части и обеспечьте поддержку API для внешнего интерфейса. Давайте взглянем на серверный код server/app.js, он очень прост, то есть создайте 30 фрагментов данных, напишите 3 интерфейса и напрямую создайте сервер узла с десятками строк файлов, который может решить проблема моделирования данных просто и грубо.
const express = require('express')
// const bodyParser = require('body-parser')
const app = express()
let allList = Array.from({length: 30}, (v, i) => ({
  id: i,
  name: '视频' + i,
  isCollect: false
}))
// 后台设置允许跨域访问
// 前后端都是本地localhost,所以不需要设置cors跨域,如果是部署在服务器上,则需要设置
// app.all('*', function (req, res, next) {
//   res.header('Access-Control-Allow-Origin', '*')
//   res.header('Access-Control-Allow-Headers', 'X-Requested-With')
//   res.header('Access-Control-Allow-Methods', 'PUT,POST,GET,DELETE,OPTIONS')
//   res.header('X-Powered-By', ' 3.2.1')
//   res.header('Content-Type', 'application/json;charset=utf-8')
//   next()
// })
app.use(express.json())
app.use(express.urlencoded({extended: false}))
// 1 获取所有的视频列表
app.get('/api/getVideoList', function (req, res) {
  let query = req.query
  let currentPage = query.currentPage
  let pageSize = query.pageSize
  let list = allList.slice((currentPage - 1) * pageSize, currentPage * pageSize)
  res.json({
    code: 0,
    data: {
      list,
      total: allList.length
    }
  })
})
// 2 获取某一条视频详情
app.get('/api/getVideoDetail/:id', function (req, res) {
  let id = Number(req.params.id)
  let info = allList.find(v => v.id === id)
  res.json({
    code: 0,
    data: info
  })
})
// 3 收藏或者取消收藏视频
app.post('/api/collectVideo', function (req, res) {
  let id = Number(req.body.id)
  let isCollect = req.body.isCollect
  allList = allList.map((v, i) => {
    return v.id === id ? {...v, isCollect} : v
  })
  res.json({code: 0})
})
const PORT = 3003
app.listen(PORT, function () {
  console.log('app is listening port' + PORT)
})

2. Конфигурация маршрутизации

В конфигурации роутинга добавьте атрибут keepAlive в мету роута, который нужно кэшировать, значение true, это должно быть известно всем, это кеширующий компонент роутинга В нашем проекте маршрут, который нужно кэшировать, это pageAList, поэтому для keepAlive мета этого маршрута установлено значение true, остальные маршруты пишутся нормально, а файл маршрутаsrc/router/index.jsследующее:

import Vue from 'vue'
import Router from 'vue-router'
import home from '../pages/home'
import pageAList from '../pages/pageAList'
import pageADetail from '../pages/pageADetail'
import pageB from '../pages/pageB'
import main from '../pages/main'
Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'main',
      component: main,
      redirect: '/home',
      children: [
        {
          path: 'home',
          name: 'home',
          component: home
        },
        {
          path: 'pageAList',
          name: 'pageAList',
          component: pageAList,
          meta: {
            keepAlive: true
          }
        },
        {
          path: 'pageB',
          component: pageB
        }
      ]
    },
    {
      path: '/pageADetail',
      name: 'pageADetail',
      component: pageADetail
    }
  ]
})

3. конфигурация vuex

Store.js Vuex хранит массив с именем excludeComponents, который используется для управления компонентами, которые необходимо кэшировать.

state.js

const state = {
  excludeComponents: [] 
}
export default state

В то же время добавьте два метода в мутации.js, addExcludeComponent для добавления элементов в excludeComponents, removeExcludeComponent для удаления элементов из массива excludeComponents.

Уведомление:Второй параметр этих двух методов — имя массива или компонента.

mutations.js

const mutations = {
  addExcludeComponent (state, excludeComponent) {
    let excludeComponents = state.excludeComponents
    if (Array.isArray(excludeComponent)) {
      state.excludeComponents = [...new Set([...excludeComponents, ...excludeComponent])]
    } else {
      state.excludeComponents = [...new Set([...excludeComponents, excludeComponent])]
    }
  },
  // excludeComponent可能是组件name字符串或者数组
  removeExcludeComponent (state, excludeComponent) {
    let excludeComponents = state.excludeComponents
    if (Array.isArray(excludeComponent)) {
      for (let i = 0; i < excludeComponent.length; i++) {
        let index = excludeComponents.findIndex(v => v === excludeComponent[i])
        if (index > -1) {
          excludeComponents.splice(index, 1)
        }
      }
    } else {
      for (let i = 0, len = excludeComponents.length; i < len; i++) {
        if (excludeComponents[i] === excludeComponent) {
          excludeComponents.splice(i, 1)
          break
        }
      }
    }
    state.excludeComponents = excludeComponents
  }
}
export default mutations

4. Keep-alive обертывает Router-View

Оберните представление маршрутизатора App.vue компонентом поддержания активности, и маршруты main.vue должны быть обернуты таким же образом, что очень важно, поскольку компоненты pageAList сопоставляются с их представлением маршрутизатора.

<keep-alive :exclude="excludeComponents"><som-component></some-component></keep-alive>Вы не должны быть знакомы с этим способом написания.Это также метод кэширования, официально рекомендованный You Dashen.Значением атрибута exclude может быть строка имени компонента (Атрибут имени опции компонента) или массив, что означает, что эти компоненты не кэшируются, поэтомуaddExcludeComponent в vuex означает кэшировать компоненты, addExcludeComponent означает не кэшировать компоненты, здесь небольшой обход, помните об этом правиле, чтобы впредь не сбиться с пути.

App.vue

<template>
  <div id="app">
    <keep-alive :exclude="excludeComponents">
      <router-view v-if="$route.meta.keepAlive"></router-view>
    </keep-alive>
    <router-view v-if="!$route.meta.keepAlive"></router-view>
  </div>
</template>

<script>
export default {
  name: 'App',
  computed: {
    excludeComponents () {
      return this.$store.state.excludeComponents
    }
  }
}
</script

main.vue

<template>
  <div>
    <ul>
      <li v-for="nav in navs" :key="nav.name">
        <router-link :to="nav.name">{{nav.title}}</router-link>
      </li>
    </ul>
    <keep-alive :exclude="excludeComponents">
      <router-view v-if="$route.meta.keepAlive"></router-view>
    </keep-alive>
    <router-view v-if="!$route.meta.keepAlive"></router-view>
  </div>
</template>
<script>
export default {
  name: 'main.vue',
  data () {
    return {
      navs: [{
        name: 'home',
        title: '首页'
      }, {
        name: 'pageAList',
        title: 'pageAList'
      }, {
        name: 'pageB',
        title: 'pageB'
      }]
    }
  },
  methods: {
  },
  computed: {
    excludeComponents () {
      return this.$store.state.excludeComponents
    }
  },
  created () {
  }
}
</script>

Следующие две настройки очень важны

5. Основные компоненты

Для первого уровня маршрутизации pageAList, который необходимо кэшировать, добавьте два хука жизненного цикла маршрутизации.beforeRouteEnterиbeforeRouteLeave

import {getVideoList} from '../api'
export default {
  name: 'pageAList', // 组件名称,和组件对应的路由名称不需要相同
  data () {
    return {
      currentPage: 1,
      pageSize: 10,
      total: 0,
      allList: [],
      list: []
    }
  },
  methods: {
    getVideoList () {
      let params = {currentPage: this.currentPage, pageSize: this.pageSize}
      getVideoList(params).then(r => {
        if (r.code === 0) {
          this.list = r.data.list
          this.total = r.data.total
        }
      })
    },
    goIntoVideo (item) {
      this.$router.push({name: 'pageADetail', query: {id: item.id}})
    },
    handleCurrentPage (val) {
      this.currentPage = val
      this.getVideoList()
    }
  },
  beforeRouteEnter (to, from, next) {
    next(vm => {
      vm.$store.commit('removeExcludeComponent', 'pageAList')
      next()
    })
    },
  beforeRouteLeave (to, from, next) {
    let reg = /pageADetail/
    if (reg.test(to.name)) {
      this.$store.commit('removeExcludeComponent', 'pageAList')
    } else {
      this.$store.commit('addExcludeComponent', 'pageAList')
    }
    next()
  },
  activated () {
    this.getVideoList()
  },
  mounted () {
    this.getVideoList()
  }
}
  • beforeRouteEnter, перед входом в pageAList этого компонента удалить текущий компонент в excludeComponents, то есть кэшировать текущий компонент,Таким образом, любой переход маршрута к этому компоненту, этот компонент фактически кэшируется, вызовет активированный хук
  • beforeRouteLeave: Оставить текущую страницу, если перейти на pageADetail, то нужно убрать текущий компонент pageAList в excludeComponents, то есть кешировать текущий компонент, если переходить на другие страницы, то нужно добавить pageAList в excludeComponents, то есть , не кэшировать текущие компоненты компонентов
  • В смонтированном или созданном хуке вызывается метод получения данных getVideoList.Если роут второго уровня меняет данные и нужно обновить роут первого уровня, то нужно снова получить данные в активированном хуке. может собрать эту деталь и изменить состояние списка, поэтому используются оба хука

6. Второстепенные компоненты

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

В этом хуке beforeRouteLeave вам нужно сначала очистить состояние кеша компонента первого уровня.Если маршрут перехода соответствует компоненту первого уровня, то кэшируйте компонент первого уровня.

beforeRouteLeave (to, from, next) {
    let componentName = ''
    // 离开详情页时,将pageAList添加到exludeComponents里,也就是将需要缓存的页面pageAList置为不缓存状态
    let list = ['pageAList']
    this.$store.commit('addExcludeComponent', list)
    // 缓存组件路由名称到组件name的映射
    let map = new Map([['pageAList', 'pageAList']])
    componentName = map.get(to.name) || ''
    // 如果离开的时候跳转的路由是pageAList,将pageAList从exludeComponents里面移除,也就是要缓存pageAList
    this.$store.commit('removeExcludeComponent', componentName)
    next()
  }

7. Резюме методов реализации

  • После входа в pageAList он кешируется в beforeRouteEnter, и есть две ситуации при выходе из текущего компонента:
    • 1 Перейти к pageADetail, кэшировать pageAList в хуке beforeRouteLeave для pageAList и выйти из pageADetail, есть две ситуации.
      • (1) Вернитесь к pageAList, затем pageAList кэшируется в хуке beforeRouteLeave страницыADetail, так что это когда из pageAList-pageADetail-pageAList, pageAList может быть кэширован или состояние предыдущего номера страницы
      • (2) Введите другие маршруты и очистите кеш pageAList в хуке beforeRouteLeave страницыADetail.
    • 2 Перейти на страницу, отличную от pageADetail, и очистить кеш pageAList в хуке beforeRouteLeave для pageAList

Оценка случая

Я думаю, что использую эту схему для достижения кэширования, и конечный эффект идеален. недостаток:

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

Исходный код проекта

исходный код проектагитхаб-адрес, добро пожаловать на клонирование и загрузку

Старт проекта и демонстрация эффекта

  1. npm installУстановить зависимости проекта
  2. npm run serverЗапустите фоновый сервер для прослушивания локального порта 3003.
  3. npm run devНачать фронтенд-проект

Кэш L3

Вышеописанного метода достаточно для кэша второго уровня. Выше речь идет о двух страницах, проблема кеша второго уровня.Теперь пусть есть три страницы, А1-А2-А3, щелчок в пошаговом режиме, когда требуется вернуться из А3 в А2, кэш А2, и потом вернитесь с А2 на А1 На тот момент кэш А1 можете изучить сами, здесь писать не буду, на самом деле это изложенная выше идея, оставляю всем на изучение, можете обратить внимание на мой Публичный аккаунт WeChat, в котором есть код ответа кэша третьего уровня.

Извините, это все равно неизбежно, как бы вы ни были недовольны, я все равно должен рекламировать свой официальный аккаунт, имя очень вульгарное,Центр передовых исследований, но контент хороший, а высококачественный внешний контент время от времени обновляется: оригинальные или переведенные иностранные отличные учебные пособия, ниже приведен QR-код официальной учетной записи, каждый может отсканировать код, чтобы присоединиться, учиться и прогрессировать вместе.

Последние качественные статьи