Maison  >  Article  >  interface Web  >  Une introduction détaillée aux fonctions de hook dans Vue

Une introduction détaillée aux fonctions de hook dans Vue

不言
不言original
2018-07-23 10:46:112462parcourir

Le contenu partagé avec vous dans cet article concerne les fonctions de hook de Vue [route navigation guard, keep-alive, life cycle hook]. Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer.

Préface

En ce qui concerne les fonctions de hook de Vue, de nombreuses personnes peuvent s'en tenir uniquement à quelques hooks très simples et couramment utilisés (created, mounted), et quand sont les différences entre eux, je n'ai pas étudié attentivement quel crochet utiliser, et le cycle de vie de Vue est également un point de test relativement élevé dans les entretiens, donc comment répondre à de telles questions rendra les gens brillants...

Vue -Garde de navigation du routeur :

Parfois, nous devons effectuer certaines opérations via le routage, telles que la vérification de l'autorisation de connexion la plus courante. Lorsque l'utilisateur remplit les conditions, l'utilisateur sera autorisé à accéder à la navigation. annulez le saut et accédez à la page de connexion pour vous connecter.

Pour cette raison, nous avons de nombreuses façons d'intégrer le processus de navigation du routage : Global, exclusif à un seul itinéraire, ou au niveau d'un composant , il est recommandé de lire d'abord le document de routage

Garde globale

vue-router compte trois gardes dans le monde :

  1. router.beforeChaque garde avant globale avant d'entrer dans la route

  2. router.beforeResolve global parsing guard (2.5.0+) est appelé après que beforeRouteEnter soit appelé

  3. router.afterEach après que le crochet de publication global entre dans la route

Utilisation  :

    // 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 全局后置钩子');
    });

vers, depuis, suivant Ces trois paramètres :

vers et depuis sont ce que entrera et quittera l'objet Routing , l'objet routage fait référence à l'objet routage habituellement obtenu via this.$route.

suivant :Fonction Ce paramètre est une fonction, et doit être appelé, sinon l'itinéraire ne peut pas être saisi (la page est vierge).

  • next() entre dans l'itinéraire.

  • next(false) : annulez la route d'entrée et réinitialisez l'adresse URL à l'adresse de routage d'origine (c'est-à-dire l'adresse de routage à laisser).

  • suivant passe à un nouvel itinéraire, la navigation en cours est interrompue et une nouvelle navigation recommence.

    Nous pouvons sauter comme ceci : next('path address') ou next({path:''}) ou next({name:''})
    et autoriser des paramètres tels que replace: true , Des options telles que name: 'home'
    et les options d'objet que vous utilisez dans router-link ou router.push.

Gardettes exclusives aux itinéraires

Si vous ne souhaitez pas configurer les gardes globalement, vous pouvez configurer les gardes individuellement pour certains itinéraires :

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

Routes Guards au sein du composant :

  1. beforeRouteEnter avant d'entrer dans la route

  2. beforeRouteUpdate (2.2) Lorsque le routage réutilise le même composant

  3. beforeRouteLeave En quittant l'itinéraire actuel

Introduction dans la documentation :

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

beforeRouteEnter accès this

Étant donné que le hook est appelé avant la création de l'instance du composant, l'instance du composant this ne peut pas être obtenue. Vous pouvez accéder à l'instance du composant next en passant un rappel à
.

Mais le timing d'exécution du rappel est derrière monté, donc à mon avis, l'accès à ceci ici n'est pas très significatif et peut être placé à l'intérieur de created ou mounted.

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

beforeRouteLeave :

Appelé lorsque la navigation quitte l'itinéraire correspondant de ce composant. Nous l'utilisons pour empêcher l'utilisateur de quitter, par exemple avant de sauvegarder le. brouillon, ou lorsque l'utilisateur Avant de partir, détruisez setInterval pour éviter que la minuterie ne soit encore appelée après son départ.

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

Quelques connaissances sur les hooks :

Détection d'erreur de la fonction de hook de routage

Si nous utilisons la fonction hook de global guard/route exclusive guard/component route guard Si s'il y a une erreur, elle peut être capturée comme ceci :

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

Il y a plus de méthodes d'instance dans le document de routage : ajout dynamique de routes, etc. Si vous êtes intéressé, vous pouvez vous renseigner à ce sujet.

Sauter dans une boucle infinie et la page sera toujours vierge

Je comprends que beaucoup de personnes rencontreront ce problème, jetez un oeil à ce pseudo code :

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

La logique semble être correcte, mais lorsque nous passons à login, parce que nous ne sommes toujours pas connectés à ce moment-là, nous continuerons à sauter à login puis bouclerons sans fin, et la page sera toujours vide, donc : il le faut. Les conditions de jugement sont légèrement modifiées.

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

Global post hook jump :

Le document mentionne que parce que router.afterEach n'accepte pas la fonction next, il ne modifiera pas la navigation elle-même, ce qui signifie qu'il ne peut que être utilisé comme Utilisez un crochet, mais quand je l'ai essayé moi-même, j'ai découvert que nous pouvons réaliser le saut sous cette forme :

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

Eh bien, cela peut aussi être réalisé et mieux via router.beforeEach, donc Je viens de me montrer.

Processus complet de résolution de navigation d'itinéraire (à l'exclusion des autres cycles de vie) :

  1. Déclenchez l'entrée sur d'autres itinéraires.

  2. Appelez le garde composant pour quitter l'itinérairebeforeRouteLeave

  3. Appelez le garde préfixe : beforeEach

  4. Appel beforeRouteUpdate

  5. Appeler la garde exclusive de la routebeforeEnter dans le composant réutilisé.

  6. 解析异步路由组件。

  7. 在将要进入的路由组件中调用beforeRouteEnter

  8. 调用全局解析守卫 beforeResolve

  9. 导航被确认。

  10. 调用全局后置钩子的 afterEach 钩子。

  11. 触发DOM更新(mounted)。

  12. 执行beforeRouteEnter 守卫中传给 next 的回调函数

你不知道的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>
    </keeo-alive>

生命周期钩子:

这篇既然是Vue钩子函数的专场,那肯定要扣题呀~

在被keep-alive包含的组件/路由中,会多出两个生命周期的钩子:activateddeactivated

文档:在 2.2.0 及其更高版本中,activated 和 deactivated 将会在 <keep-alive> 树内的所有嵌套组件中触发。

activated在组件第一次渲染时会被调用,之后在每次缓存组件被激活时调用

activated调用时机:

第一次进入缓存路由/组件,在mounted后面,beforeRouteEnter守卫传给 next 的回调函数之前调用:

    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:匹配的 路由/组件 不会被缓存

includeexclude支持三种方式来有条件的缓存路由:采用逗号分隔的字符串形式,正则形式,数组形式。

正则和数组形式,必须采用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="[&#39;a&#39;, &#39;b&#39;]">
      <component :is="view"></component>
    </keep-alive>

但更多场景中,我们会使用keep-alive来缓存路由

<keep-alive include=&#39;a&#39;>
    <router-view></router-view>
</keeo-alive>

匹配规则:

  1. 首先匹配组件的name选项,如果name选项不可用。

  2. 则匹配它的局部注册名称。 (父组件 components 选项的键值)

  3. 匿名组件,不可匹配

比如路由组件没有name选项,并且没有注册的组件名。

  1. 只能匹配当前被包裹的组件,不能匹配更下面嵌套的子组件

比如用在路由上,只能匹配路由组件的name选项,不能匹配路由组件里面的嵌套组件的name选项。

  1. 文档:<keep-alive> 不会在函数式组件中正常工作,因为它们没有缓存实例。

  2. exclude的优先级大于include

也就是说:当includeexclude同时存在时,exclude生效,include不生效。

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

当组件被exclude匹配,该组件将不会被缓存,不会调用activateddeactivated


组件生命周期钩子:

关于组件的生命周期,是时候放出这张图片了:


这张图片已经讲得很清楚了,很多人这部分也很清楚了,大部分生命周期并不会用到,这里提一下几点:

  1. ajax请求最好放在created里面,因为此时已经可以访问this了,请求到数据就可以直接放在data里面。

    这里也碰到过几次,面试官问:ajax请求应该放在哪个生命周期。

  2. 关于dom的操作要放在mounted里面,在mounted前面访问dom会是undefined

  3. 每次进入/离开组件都要做一些事情,用什么钩子:

  • 不缓存:

    进入的时候可以用createdmounted钩子,离开的时候用beforeDestorydestroyed钩子,beforeDestory可以访问thisdestroyed不可以访问this

  • 缓存了组件:

    缓存了组件之后,再次进入组件不会触发beforeCreatecreatedbeforeMountmounted如果你想每次进入组件都做一些事情的话,你可以放在activated进入缓存组件的钩子中

    同理:离开缓存组件的时候,beforeDestroydestroyed并不会触发,可以使用deactivated离开缓存组件的钩子来代替。

触发钩子的完整顺序:

将路由导航、keep-alive、和组件生命周期钩子结合起来的,触发顺序,假设是从a组件离开,第一次进入b组件:

  1. beforeRouteLeave:路由组件的组件离开路由前钩子,可取消路由离开。

  2. beforeEach: 路由全局前置守卫,可用于登录验证、全局路由loading等。

  3. beforeEnter: 路由独享守卫

  4. beforeRouteEnter: 路由组件的组件进入路由前钩子。

  5. beforeResolve:路由全局解析守卫

  6. afterEach:路由全局后置钩子

  7. beforeCreate:组件生命周期,不能访问this

  8. created:组件生命周期,可以访问this,不能访问dom。

  9. beforeMount:组件生命周期

  10. deactivated: 离开缓存组件a,或者触发a的beforeDestroydestroyed组件销毁钩子。

  11. mounted:访问/操作dom。

  12. activated:进入缓存组件,进入a的嵌套子组件(如果有的话)。

  13. 执行beforeRouteEnter回调函数next。

结语

Vue提供了很多钩子,但很多钩子我们几乎不会用到,只有清楚这些钩子函数的触发顺序以及背后的一些限制等,这样我们才能够正确的使用这些钩子,希望看了本文的同学,能对这些钩子有更加清晰的认识,使用起来更加得心应手。

相关推荐:

AngularJs中model、Controller(控制器)和View(视图)之间有什么样的关系?(图文)

Vue自定义指令及指令定义函数的具体分析(代码)

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn