Функция ловушки Vue [защита навигации маршрутизации, поддержка активности, ловушка жизненного цикла]

внешний интерфейс Vue.js регулярное выражение Ajax
Функция ловушки Vue [защита навигации маршрутизации, поддержка активности, ловушка жизненного цикла]

предисловие

Когда дело доходит до функций хуков Vue, многие люди могут остановиться только на некоторых очень простых и часто используемых хуках (created,mounted), а насчет разницы, когда какой хук использовать, я внимательно не изучал, а жизненный цикл Vue тоже относительно высокочастотная тестовая площадка в интервью, так что как отвечать на такие вопросы, у людей есть какая яркая чувство...

Передовое расширенное накопление,Нет публики,GitHub


Защита навигации Vue-Router:

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

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

глобальная гвардия

vue-router имеет три охранника по всему миру:

  1. router.beforeEach global front guard перед входом в маршрут
  2. router.beforeResolve глобальная защита разрешения (2.5.0+), вызываемая после вызова beforeRouteEnter
  3. router.afterEach глобальный почтовый хук после ввода маршрута

инструкции:

    // main.js 入口文件
    import router from './router'; // 引入路由
    router.beforeEach((to, from, next) => { 
      next();
    });
    router.beforeResolve((to, from, next) => {
      next();
    });
    router.afterEach((to, from) => {
      console.log('afterEach 全局后置钩子');
    });

to, from, next эти три параметра:

туда и обратноМаршрутизируйте объекты, которые будут входить и выходить, объект маршрутизации ссылается на объект маршрутизации, обычно получаемый через this.$route.

next:FunctionЭтот параметр является функцией, иДолжен быть вызван, иначе он не может войти в маршрут(страница пуста).

  • next() входит в маршрут.

  • следующий (false): отменить входящий маршрут, и URL-адрес сбрасывается на исходный адрес маршрута (то есть адрес маршрута, который нужно оставить).

  • next переходит к новому маршруту, текущая навигация прерывается и начинается новая навигация.

      我们可以这样跳转:next('path地址')或者next({path:''})或者next({name:''})
      且允许设置诸如 replace: true、name: 'home' 之类的选项
      以及你用在router-link或router.push的对象选项。
    

Эксклюзивная защита маршрутизации

Если вы не хотите настраивать защиту глобально, вы можете настроить защиту индивидуально для определенных маршрутов:

    const router = new VueRouter({
      routes: [
        {
          path: '/foo',
          component: Foo,
          beforeEnter: (to, from, next) => { 
            // 参数用法什么的都一样,调用顺序在全局前置守卫后面,所以不会被全局守卫覆盖
            // ...
          }
        }
      ]
    })

Охранники в компонентах маршрутизации:

  1. beforeRouteEnter перед вводом маршрута
  2. beforeRouteUpdate (2.2) Когда маршрутизация повторно использует один и тот же компонент
  3. beforeRouteLeave при выходе с текущего маршрута

Представлено в документации:

  beforeRouteEnter (to, from, next) {
    // 在路由独享守卫后调用 不!能!获取组件实例 `this`,组件实例还没被创建
  },
  beforeRouteUpdate (to, from, next) {
    // 在当前路由改变,但是该组件被复用时调用 可以访问组件实例 `this`
    // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
    // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
  },
  beforeRouteLeave (to, from, next) {
    // 导航离开该组件的对应路由时调用,可以访问组件实例 `this`
  }

beforeRouteEnter получить доступ к этому

Поскольку хук вызывается, когда экземпляр компонента еще не создан, экземпляр компонента не может быть получен.this, вы можете передать обратный вызовnextдля доступа к экземпляру компонента .

ноВремя выполнения обратного вызова после монтирования, так что на мой взгляд, доступ к этому здесь не очень осмысленный и может быть помещен вcreatedилиmountedв.

    beforeRouteEnter (to, from, next) {
    console.log('在路由独享守卫后调用');
      next(vm => {
        // 通过 `vm` 访问组件实例`this` 执行回调的时机在mounted后面,
      })
    }

доRouteLeave:

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

    beforeRouteLeave (to, from , next) {
      if (文章保存) {
        next(); // 允许离开或者可以跳到别的路由 上面讲过了
      } else {
        next(false); // 取消离开
      }
    }

Некоторые знания о хуках:

Перехват ошибок для функций перехвата маршрута

Если у нас есть ошибка в функции ловушки глобальной защиты/маршрутизации эксклюзивной защиты/компонентной защиты маршрутизации, мы можем перехватить ее следующим образом:

    router.onError(callback => { 
    // 2.4.0新增 并不常用,了解一下就可以了 
      console.log(callback, 'callback');
    });

В документации по маршрутизации есть ещеметод экземпляра: Динамически добавлять маршрутизацию и т.п., можете узнать об этом, если интересно.

Перейти в бесконечный цикл, страница всегда пуста

Я понимаю, что многие люди столкнутся с этой проблемой, давайте посмотрим на этот псевдокод:

    router.beforeEach((to, from, next) => {
      if(登录){
         next()
      }else{
          next({ name: 'login' }); 
      }
    });

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

    if(登录 || to.name === 'login'){ next() } // 登录,或者将要前往login页面的时候,就允许进入路由

После установки глобального джамп-хука:

Обратитесь к документации, поскольку Router.Aftereach не принимаетсяnextФункция не изменяет саму навигацию, а это значит, что ее можно использовать только как хук, но когда я попробовал ее сам, то обнаружил, что мы можем использовать эту форму для прыжка:

    // main.js 入口文件
    import router from './router'; // 引入路由
    router.afterEach((to, from) => {
      if (未登录 && to.name !== 'login') {
        router.push({ name: 'login' }); // 跳转login
      }
    });

Ну, router.beforeEach тоже вполне достижимо и лучше, так что покажу.

Полный процесс маршрутизации и навигации (за исключением других жизненных циклов):

  1. Триггер для ввода других маршрутов.
  2. Вызвать охрану компонента, чтобы уйти с маршрутаbeforeRouteLeave
  3. Вызовите охрану бюро:beforeEach
  4. Вызывается в повторно используемом компонентеbeforeRouteUpdate
  5. Вызвать эксклюзивную защиту маршрутаbeforeEnter.
  6. Разобрать компоненты асинхронной маршрутизации.
  7. Вызывается в компоненте маршрутизации, который будет введенbeforeRouteEnter
  8. Вызвать глобальную защиту синтаксического анализаbeforeResolve
  9. Навигация подтверждена.
  10. вызвать глобальный почтовый хукafterEachкрюк.
  11. запустить обновление DOM (mounted).
  12. воплощать в жизньbeforeRouteEnterФункция обратного вызова передается следующему в страже

Keep-alive вы не знаете [я думаю, вы не знаете]

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

Документация: и<transition>сходство,<keep-alive>является абстрактным компонентом: он не отображает элемент DOM сам по себе и не появляется в цепочке родительских компонентов.

Применение:

Кэшировать динамические компоненты:

<keep-alive>При обертывании динамических компонентов неактивные экземпляры компонентов кэшируются, а не уничтожаются, что не имеет большого практического смысла.

    <!-- 基本 -->
    <keep-alive>
      <component :is="view"></component>
    </keep-alive>
    
    <!-- 多个条件判断的子组件 -->
    <keep-alive>
      <comp-a v-if="a > 1"></comp-a>
      <comp-b v-else></comp-b>
    </keep-alive>

Компоненты маршрутизации кэша:

использоватьkeep-aliveВсе компоненты маршрутизации, соответствующие путям, могут кэшироваться, включая компоненты в компонентах маршрутизации,keep-aliveЭто относится к большинству вариантов использования.

    <keep-alive>
        <router-view></router-view>
    </keep-alive>

Крючки жизненного цикла:

Поскольку это специальный сеанс функций ловушек Vue, его необходимо вычесть~

существованиеkeep-aliveВо включенных компонентах/маршрутах будет еще два хука жизненного цикла:activatedа такжеdeactivated.

Документация: В 2.2.0 и более поздних версиях активированные и деактивированные будут в деревевсе вложенные компонентытриггер в.

активированный вызывается при первом рендеринге компонента, а затем каждый раз, когда кешированный компонент активируется.

активированное время вызова:

При первом вводе кэшированного маршрута/компонента вmountedПозади,beforeRouteEnterВызывается до того, как функция обратного вызова передается следующей охранником:

    beforeMount=> 如果你是从别的路由/组件进来(组件销毁destroyed/或离开缓存deactivated)=>
    mounted=> activated 进入缓存组件 => 执行 beforeRouteEnter回调

Поскольку компонент кэшируется,Эти хуки не срабатывают при повторном входе в кешированный маршрут/компонент.:

    // beforeCreate created beforeMount mounted 都不会触发。

Итак, время следующего звонка:

    组件销毁destroyed/或离开缓存deactivated => activated 进入当前缓存组件 
    => 执行 beforeRouteEnter回调
    // 组件缓存或销毁,嵌套组件的销毁和缓存也在这里触发

deactivated: вызывается при деактивации компонента (уходе с маршрута)

использовалkeep-aliveне позвонитbeforeDestroy(хук уничтожения перед компонентом) иdestroyed(Уничтожение компонента), поскольку компонент не уничтожается, он кэшируется.

Этот крючок можно рассматривать какbeforeDestroyВместо этого, если вы кешируете компонент и хотите что-то сделать, когда компонент уничтожен, вы можете поместить его в этот хук.

Если вы покинете маршрут, он будет запущен в следующей последовательности:

    组件内的离开当前路由钩子beforeRouteLeave =>  路由前置守卫 beforeEach =>
    全局后置钩子afterEach => deactivated 离开缓存组件 => activated 进入缓存组件(如果你进入的也是缓存路由)
    // 如果离开的组件没有缓存的话 beforeDestroy会替换deactivated 
    // 如果进入的路由也没有缓存的话  全局后置钩子afterEach=>销毁 destroyed=> beforeCreate等

Так что, если я просто хочу кэшировать несколько из этих маршрутов/компонентов?

Кэшируйте маршруты, которые вы хотите кэшировать:

До Vue2.1.0:

Чтобы добиться чего-то подобного, вы можете:

  1. Настройка метаданных маршрутизации

  2. создать дваkeep-aliveЭтикетка

  3. использоватьv-ifОпределите, какие маршруты кэшируются, с помощью метаинформации маршрутизации.

     <keep-alive>
         <router-view v-if="$route.meta.keepAlive">
             <!--这里是会被缓存的路由-->
         </router-view>
     </keep-alive>
     <router-view v-if="!$route.meta.keepAlive">
         <!--因为用的是v-if 所以下面还要创建一个未缓存的路由视图出口-->
     </router-view>
     //router配置
     new Router({
       routes: [
         {
           path: '/',
           name: 'home',
           component: Home,
           meta: {
             keepAlive: true // 需要被缓存
           }
         },
         {
           path: '/:id',
           name: 'edit',
           component: Edit,
           meta: {
             keepAlive: false // 不需要被缓存
           }
         }
       ]
     });
    

После версии Vue2.1.0:

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

К счастью, после Vue2.1.0 Vue добавил два новых свойства для совместной работы.keep-aliveдля условного кэширования маршрутов/компонентов.

Добавлены свойства:

  • include: соответствующие маршруты/компоненты будут кэшироваться
  • exclude: совпадающие маршруты/компоненты не будут кэшироваться

includeа такжеexcludeПоддерживает три способа условного кэширования маршрутов: строковая форма с разделителями-запятыми, обычная форма и форма массива.

Обычная форма и форма массива, необходимо использоватьv-bindформу для использования.

Как использовать компонент кеша:

    <!-- 逗号分隔字符串 -->
    <keep-alive include="a,b">
      <component :is="view"></component>
    </keep-alive>
    
    <!-- 正则表达式 (使用 `v-bind`) -->
    <keep-alive :include="/a|b/">
      <component :is="view"></component>
    </keep-alive>
    
    <!-- 数组 (使用 `v-bind`) -->
    <keep-alive :include="['a', 'b']">
      <component :is="view"></component>
    </keep-alive>

Но в других сценариях мы будем использоватьkeep-aliveкэшировать маршруты:

<keep-alive include='a'>
    <router-view></router-view>
</keep-alive>

Правила соответствия:

  1. Сначала сопоставьте параметр имени компонента,еслиnameВарианты недоступны.
  2. затем соответствует егоместное зарегистрированное имя. (родительский компонентcomponentsключ опции)
  3. Анонимный компонент, несопоставимый.

Например, компонент маршрутизации неnameвариант, и нет зарегистрированного имени компонента.

  1. может соответствовать только текущему обернутому компоненту,Не удается сопоставить подкомпоненты, вложенные ниже.

Например, при использовании в маршрутизации он может соответствовать только компонентам маршрута.nameПараметр, не может соответствовать вложенному компоненту внутри компонента маршрутизации.nameопции.

  1. Документация:<keep-alive>не будет работать должным образом в функциональных компонентах, так как у них нет кэшированных экземпляров.
  2. excludeприоритет больше, чемinclude

То есть: когдаincludeа такжеexcludeКогда оба существуют,excludeЭффективно,includeне удалось.

  <keep-alive include="a,b" exclude="a">
    <!--只有a不被缓存-->
    <router-view></router-view>
  </keep-alive>

когда компонентexcludematch, компонент не будет закэширован и не будет вызыватьсяactivatedа такжеdeactivated.


Хуки жизненного цикла компонентов:

О жизненном цикле компонентов, пришло время освободить эту картину:

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

  1. Запросы Ajax лучше всего размещать вcreatedв, потому что он уже доступен в этот моментthisТеперь запрошенные данные можно разместить непосредственно наdataв.

    Я тоже несколько раз сталкивался здесь, и интервьюер спрашивал: в какой жизненный цикл следует помещать ajax-запрос.

  2. Операция dom должна быть помещена вmountedв,существуетmountedПредыдущий доступ к дому будетundefined.

  3. Делайте что-то каждый раз, когда вы входите/выходите из компонента, какой хук использовать:

  • Не кэшировать:

    доступно при входеcreatedа такжеmountedкрючок, использовать при уходеbeforeDestoryа такжеdestroyedкрюк,beforeDestoryможет получить доступthis,destroyedне доступныйthis.

  • Кэшированный компонент:

    После кэширования компонента повторный вход в компонент не сработает.beforeCreate,created,beforeMount,mounted,Если вы хотите что-то делать каждый раз при входе в компонент, вы можете поставитьactivatedВ крючок компонента кеша.

    Аналогично: при выходе из кеша компонента,beforeDestroyа такжеdestroyedне срабатывает, вы можете использоватьdeactivatedВместо этого оставьте крючок для компонента кеша.


Полная последовательность срабатывания хуков:

навигация по маршруту,keep-alive, в сочетании с хуком жизненного цикла компонента, триггерной последовательностью, предполагая, что он покидает компонент a и входит в компонент b в первый раз:

  1. beforeRouteLeave: Компонент компонента маршрутизации покидает хук перед маршрутизацией, что может отменить выход из маршрутизации.
  2. beforeEach: глобальная передняя защита маршрутизации, которую можно использовать для проверки входа в систему, загрузки глобальной маршрутизации и т. д.
  3. beforeEnter: Эксклюзивная защита маршрутизации
  4. beforeRouteEnter: компонент компонента маршрутизации входит в крючок предварительной маршрутизации.
  5. beforeResolve:Защита глобального синтаксического анализа маршрута
  6. afterEach: маршрутизировать глобальный почтовый хук
  7. beforeCreate: жизненный цикл компонента, недоступноthis.
  8. created: Жизненный цикл компонента, доступенthis, не могу получить доступ к dom.
  9. beforeMount: жизненный цикл компонента
  10. deactivated: выйти из кеша компонента a или активировать abeforeDestroyа такжеdestroyedХук уничтожения компонента.
  11. mounted: доступ/управление dom.
  12. activated: в компонент кеша, во вложенный дочерний компонент a (если есть).
  13. Затем выполните функцию обратного вызова beforeRouteEnter.

Эпилог

Vue предоставляет много хуков, но мы почти не используем их. Только зная последовательность срабатывания этих функций-хуков и некоторые ограничения, стоящие за ними, мы можем правильно использовать эти хуки.Эти хуки более понятны и более удобны в использовании.

Я надеюсь, что друзья, которые прочитали это, могут нажать «Нравится» / «Подписаться», ваша поддержка — самая большая поддержка для меня.

Передовое расширенное накопление,Нет публики,GitHub, wx:OBkoro1, Электронная почта: obkoro1@foxmail.com

Выше 2018.7.21

Использованная литература:

Vue-документация

Глубокое понимание и использование поддержки активности (с представлением маршрутизатора для кэширования всей страницы маршрутизации)