Site de test haute fréquence d'interview Web front-end - communication entre les composants Vue et fonctionnalités avancées (communication entre plusieurs composants, v-model personnalisé, nextTick, slot)

Répertoire des articles de la série

contenu Lien de référence
Utilisation de base de Vue L'utilisation de base de Vue (un article pour maîtriser les points de connaissance les plus élémentaires de Vue)
Communication Vue et fonctionnalités avancées Communication entre composants Vue et fonctionnalités avancées (communication entre différents composants, v-model personnalisé, nextTick, slots)
Fonctionnalités avancées de Vue Fonctionnalités avancées de Vue (composants dynamiques, chargement asynchrone, keep-alive, mixin, Vuex, Vue-Router)
Vue Principe 1 Principe de Vue (compréhension du modèle MVVM, modification approfondie/surveillance des données, surveillance des modifications de la baie, compréhension approfondie du DOM virtuel)
Vue Principe 2 Principe de Vue (algorithme diff, compilation de modèles, rendu et mise à jour de composants, routage d'implémentation JS)
Questions d'entretien chez Vue Site de test à haute fréquence d'entretiens front-end Web - Questions d'entretien Vue


1. Communication entre les composants Vue

1. props et $emit

  • propsfréquemment utilisépère en filstransmettre des données
  • this.$emitfréquemment utiliséfils à pèretransmettre des données
  • event.$emitfréquemment utiliséchambre fratrietransmettre des données

Exemple : deux sous-composants (composant de zone de saisie et composant de liste) sont dynamiquement ajoutés et supprimés

Composant parent (index.vue)

  • Liaisons du composant parent et événement personnalisé @addsur l'étiquette du composant enfant@delete
<template>
  <div>
    <Input @add="addHandler" />
    <List :list="list" @delete="deleteHandler" />
  </div>
</template>

<script>
import Input from "./Input";
import List from "./List";

export default {
    
    
  components: {
    
    
    Input,
    List,
  },
  data() {
    
    
    return {
    
    
      list: [
        {
    
    
          id: "id-1",
          title: "标题1",
        },
        {
    
    
          id: "id-2",
          title: "标题2",
        },
      ],
    };
  },
  methods: {
    
    
    // 添加项目
    addHandler(title) {
    
    
      this.list.push({
    
    
        id: `id-${
      
      Date.now()}`,
        title,
      });
    },
    // 删除项目
    deleteHandler(id) {
    
    
      this.list = this.list.filter((item) => item.id !== id);
    },
  },
  // 创建
  created() {
    
    
    console.log("index created");
  },
  // 挂载
  mounted() {
    
    
    console.log("index mounted");
  },
  // 更新前
  beforeUpdate() {
    
    
    console.log("index before update");
  },
  // 更新
  updated() {
    
    
    console.log("index updated");
  },
};
</script>

composant enfant (input.vue)

  • Liaison de bouton événement addTitle
  • this.$emit('add', this.title)Appelez l'événement du composant parent en utilisant
  • Utiliser event.$emit("onAddTitle", this.title)pour appeler des événements personnalisés (événements définis par des composants frères)
<template>
  <div>
    <input type="text" v-model="title" />
    <button @click="addTitle">add</button>
  </div>
</template>

<script>
import event from "./event";

export default {
    
    
  data() {
    
    
    return {
    
    
      title: "",
    };
  },
  methods: {
    
    
    addTitle() {
    
    
      // 调用父组件的事件
      if (this.title.trim() !== "") {
    
    
        this.$emit("add", this.title);

        // 调用自定义事件
        event.$emit("onAddTitle", this.title);

        this.title = "";
      } else {
    
    
        alert('输入内容不能为空')
      }
    },
  },
};
</script>

Composant enfant (List.vue)

  • Utilisez les props pour recevoir la liste du composant parent et faire des restrictions de type et des valeurs par défaut
  • Le bouton est lié à la fonction deleteItem, qui utilise l'événement d' this.$emit("delete", id)appel du composant parent et le supprime en fonction de l'id
  • event.$on("onAddTitle", this.addTitleHandler)Lier des événements personnalisés lors du montage
  • event.$off("onAddTitle", this.addTitleHandler)Détruire les événements personnalisés avant la destruction (beforeDestroy)
  • Remarque : lors de la liaison et de la destruction d'événements personnalisés, le deuxième paramètre est une fonction ordinaire transmise, n'écrivez pas de fonctions fléchées (ce point changera)
<template>
  <div>
    <ul>
      <li v-for="item in list" :key="item.id">
        {
    
    {
    
     item.title }}
        <button @click="deleteItem(item.id)">删除</button>
      </li>
    </ul>
  </div>
</template>

<script>
import event from "./event";

export default {
    
    
  // props: ['list']
  props: {
    
    
    // prop 类型和默认值
    list: {
    
    
      type: Array,
      default() {
    
    
        return []
      }
    },
  },
  methods: {
    
    
    deleteItem(id) {
    
    
      this.$emit("delete", id);
    },
    addTitleHandler(title) {
    
    
      console.log("on add title", title);
    },
  },
  created() {
    
    
    console.log("list created");
  },
  mounted() {
    
    
    console.log("list mounted");

    // 绑定自定义事件
    event.$on("onAddTitle", this.addTitleHandler);
  },
  beforeUpdate() {
    
    
    console.log("list before update");
  },
  updated() {
    
    
    console.log("list updated");
  },
  beforeDestroy() {
    
    
    // 及时销毁,否则可能造成内存泄露
    event.$off("onAddTitle", this.addTitleHandler);
  },
};
</script>

fichier event.js

  • Créez une instance de vue, vous pouvez utiliser des méthodes telles que $emit, $off, $onetc.
import Vue from 'vue'

export default new Vue()

Ligne de séparation------------------------------------------------ -------------------------------------------------- ---------

insérez la description de l'image ici

Ligne de séparation------------------------------------------------ -------------------------------------------------- ---------

insérez la description de l'image ici

Ligne de séparation------------------------------------------------ -------------------------------------------------- ---------

insérez la description de l'image ici

2. Cycle de vie

Cycle de vie détaillé [lien de référence]

  • beforeCreate : l'instance de vue est créée, el et les données n'ont pas été initialisées, ne peuvent pas accéder aux données et à la méthode, ne fonctionnent généralement pas à ce stade.Ne fonctionnent généralement pas à ce stade
  • created : les données et la méthode dans l'instance de vue ont été initialisées et les propriétés ont été liées. Mais pour le moment, il s'agit toujours d'un DOM virtuel, le vrai DOM n'a pas été généré et $el n'est pas encore disponible.Les données sont généralement initialisées ici
  • beforeMount : le modèle a été compilé, mais il n'a pas été rendu dans la page (c'est-à-dire que le dom virtuel est chargé dans le dom réel)
  • monté : le modèle a été rendu dans un véritable DOM et l'utilisateur peut déjà voir la page rendue. Après avoir exécuté monté, cela signifie que l'instance a été complètement créée
  • beforeUpdate : déclenché avant le nouveau rendu, puis le mécanisme de dom virtuel de vue reconstruira le dom virtuel et restituera après avoir comparé le dernier arbre de dom virtuel avec l'algorithme diff. Seules les modifications de données sur la vue se déclencheront avant la mise à jour et la mise à jour, et seules les modifications de données dans les données ne se déclencheront pas.
  • mis à jour : les données ont été modifiées et le dom est restitué.
  • beforeDestroy : Exécuté avant la destruction (lorsque la méthode $destroy est appelée), généralement ici : efface les timers, efface les événements liés personnalisés, etc...
  • détruit : après la destruction (l'élément Dom existe, mais n'est plus contrôlé par vue), désinstallez l'observateur, l'écouteur d'événement et les composants enfants.

En se référant aux résultats des exemples d'accessoires et de $emit, le cycle de vie du composant parent-enfant est résumé comme suit :

01.父组件 before create
02.父组件 created
03.父组件 before mount
04.子组件 before create
05.子组件 created
06.子组件 before mount
07.子组件 mounted
08.父组件 mounted
09.父组件 before update
10.子组件 before update
11.子组件 updated
12.父组件 updated
13.父组件 before destroy
14.子组件 before destroy
15.子组件 destroyed
16.父组件 destroyed

Deuxièmement, les fonctionnalités avancées de Vue

Modèle en V personnalisé, $nextTick, slot, dynamique, composants asynchrones, keep-alive, mixin

1. Personnalisez le modèle en V

Exemple : modèle en V d'implémentation personnalisée

Composant enfant CustomVModel.vue

  • entrée utilisée : valeur au lieu de v-model
  • l'attribut change1 correspond à
  • l'attribut text1 correspond à
  • Prop est la propriété qui est liée à l'aide de la directive v-model dans le composant parent qui appelle le composant
  • event correspond à une fonction qui modifie la valeur de la propriété spécifiée par prop
<template>
  <input
    type="text"
    :text="text1"
    @input="$emit('change1', $event.target.value)"
  />
</template>

<script>
export default {
    
    
  name: "CustomVModel",
  model: {
    
    
    prop: "text1", // 对应 props text1
    event: "change1",
  },
  props: {
    
    
    type: String,
    default() {
    
    
      return "";
    },
  },
};
</script>

composant parent index.vue

  • Utiliser le nom de liaison de données bidirectionnelle v-model sur l'étiquette du composant enfant
<template>
  <div>
    <p>vue 高级特性</p>
    <hr />

    <p>{
    
    {
    
     name }}</p>
    <CustomVModel v-model='name'/>
  </div>
</template>

<script>
import CustomVModel from "./CustomVModel.vue";
export default {
    
    
  name: "index",
  components: {
    
     CustomVModel },
  data() {
    
    
    return {
    
    
        name: '杂货铺'
    }
  }
};
</script>

insérez la description de l'image ici

2、nextTick

  • Vue est un rendu asynchrone
  • Une fois les données modifiées, le DOM ne sera pas rendu immédiatement
  • $nextTick sera déclenché après le rendu DOM pour obtenir le dernier nœud DOM

Exemple : Ajouter des nœuds enfants et obtenir la longueur totale des nœuds enfants

Composant NextTick.vue

  • ref est utilisé pour le marquage
  • les références sont utilisées pour obtenir des éléments DOM
  • this.$nextTick(() => {...})Pour le rendu asynchrone, rappel après le rendu du DOM
  • S'il n'est pas ajouté $nextTick, le résultat de sortie est 3
<template>
  <div>
    <ul ref="ul1">
      <li v-for="(item, index) in list" :key="index">
        {
    
    {
    
     item }}
      </li>
    </ul>
    <button @click="addItem">添加一项</button>
  </div>
</template>

<script>
export default {
    
    
  name: "NextTick",
  data() {
    
    
    return {
    
    
      list: ["a", "b", "c"],
    };
  },
  methods: {
    
    
    addItem() {
    
    
      this.list.push(`${
      
      Date.now()}`);
      this.list.push(`${
      
      Date.now()}`);
      this.list.push(`${
      
      Date.now()}`);

      // 异步渲染,$nextTick 待 DOM 渲染完再回调
      // 页面渲染时会将 data 的修改做整合,多次 data 修改只会渲染一次
      this.$nextTick(() => {
    
    
        // 获取 DOM 元素
        const ulElem = this.$refs.ul1;
        console.log(ulElem.childNodes.length); // 6
      });
    },
  },
};
</script>

insérez la description de l'image ici

3. Fente d'emplacement

(1) Emplacement par défaut

  • Permet aux composants parents d'insérer htmldes structures
  • <solt>Le corps de l'étiquette est le contenu par défaut, c'est-à-dire que lorsque le composant parent ne définit pas de contenu, il s'affiche ici

Exemple : Utilisation de base des emplacements par défaut

composant parent index.vue

  • À l'intérieur de la balise de composant enfant du composant parent { { website.title }}se trouve le contenu à rendre dans l'emplacement du composant enfant
<template>
  <div>
    <p>vue 高级特性</p>
    <hr />

    <SlotDemo :url="website.url">
      {
    
    {
    
     website.title }}
    </SlotDemo>
  </div>
</template>

<script>
import SlotDemo from "./SlotDemo.vue";
export default {
    
    
  components: {
    
     SlotDemo },
  data() {
    
    
    return {
    
    
      website: {
    
    
        url: "http://baidu.com/",
        title: "Baidu",
        subTitle: "百度",
      },
    };
  },
};
</script>

Sous-composant SlotDemo.vue

  • Lorsqu'il y a du contenu dans la balise de composant enfant du composant parent, le contenu correspondant est rendu
  • Le contenu par défaut de l'emplacement est rendu lorsqu'il n'y a pas de contenu dans la balise du composant enfant du parent
<template>
    <a :href="url">
        <slot>
            默认内容,即父组件没设置内容时,这里显示
        </slot>
    </a>
</template>

<script>
export default {
    
    
    props: ['url'],
};
</script>

insérez la description de l'image ici

Ligne de séparation------------------------------------------------ -------------------------------------------------- ---------

insérez la description de l'image ici

(2) Fente pour lunette

  • Scénario : Le contenu d'un emplacement peut souhaiter utiliser des données provenant à la fois du domaine du parent et du domaine de l'enfant

Exemple : Afficher le titre du composant enfant, utiliser le lien du composant parent

composant parent index.vue

  • Défini à l'intérieur de la balise de composant enfant du composant parent<template>
  • <template>Utilisez v-slot pour lier les propriétés personnalisées slotProps dans l'étiquette
  • Obtenez ensuite la valeur du titre du sous-composant via slotProps.soltData.title
<template>
  <div>
    <p>vue 高级特性</p>
    <hr />

    <ScopedSlot:url="website.url">
      <template v-slot="slotProps">
        {
    
    {
    
     slotProps.slotData.title }}
      </template>
    </ScopedSlot>
  </div>
</template>

<script>
import ScopedSlot from "./ScopedSlot.vue";
export default {
    
    
  components: {
    
     ScopedSlot},
  data() {
    
    
    return {
    
    
      website: {
    
    
        url: "http://baidu.com/",
        title: "Baidu",
        subTitle: "百度",
      },
    };
  },
};
</script>

Sous-composant ScopedSlot.vue

  • <slot>Personnalisez l'attribut dynamique slotData dans la balise, liez le site Web dans les données
  • Afficher le titre du composant enfant en utilisant la syntaxe d'interpolation dans la balise
<template>
  <a :href="url">
    <slot :slotData="website">
      {
    
    {
    
     website.subTitle }}
    </slot>
  </a>
</template>

<script>
export default {
    
    
  props: ["url"],
  data() {
    
    
    return {
    
    
      website: {
    
    
        url: "http://bilibili.com/",
        title: "Bilibili",
        subTitle: "哔哩哔哩",
      },
    };
  },
};
</script>

insérez la description de l'image ici

(3) Emplacement nommé

  • Utiliser dans <slot>les sous- name='xxx'pour nommer l'emplacement
  • <template>Utiliser dans l'emplacement du composant parent v-slot:xxxou du composant enfant #xxxcorrespondant

Exemple : utilisation d'emplacements nommés

composant parent index.vue

  • <template>Utiliser dans l'emplacement du composant parent v-slot:xxxou du composant enfant #xxxcorrespondant
<template>
  <div>
    <p>vue 高级特性</p>
    <hr />

    <NamedSlot>
      <template v-slot:header>
        <h4>将插入到 header slot 中</h4>
      </template>

      <p>将插入到 main slot 中,即未命名的 slot</p>

      <template #footer>
        <p>将插入到 footer slot 中</p>
      </template>
    </NamedSlot>
  </div>
</template>

<script>
import NamedSlot from "./NamedSlot.vue";
export default {
    
    
  components: {
    
     NamedSlot }
};
</script>

Sous-composant NamedSlot.vue

  • Utiliser dans <slot>les sous- name='xxx'pour nommer l'emplacement
<template>
  <div>
    <header>
      <slot name="header">默认头部</slot>
    </header>
    <main>
      <slot></slot>
    </main>
    <footer>
      <slot name="footer">默认尾部</slot>
    </footer>
  </div>
</template>

<script>
export default {
    
    };
</script>

insérez la description de l'image ici

不积跬步无以至千里 不积小流无以成江海

Cliquez pour suivre et ne vous perdez pas, continuez à mettre à jour...

Je suppose que tu aimes

Origine blog.csdn.net/qq_45902692/article/details/126453192
conseillé
Classement