communication des composants vue3 et utilisation du modèle ref&v

1. Communication des composants

1. props => le parent transmet la valeur à l'enfant

Les accessoires sont principalement utilisés pour communiquer entre les composants parents et les composants enfants . Dans le composant parent, utilisez :msg="msg" pour lier la valeur de propriété qui doit être transmise au composant enfant, puis utilisez les accessoires dans le composant enfant pour recevoir la valeur de propriété.

Méthode 1 : Méthode normale :

// 父组件 传值
<child :msg1="msg1" :list="list"></child>
<script>
import child from "./child.vue";
import {
    
     ref, reactive } from "vue";
export default {
    
    
    setup() {
    
    
        //基础类型传值
        const msg1 = ref("父组件传给子组件的msg1");
        // 复杂类型(数组或对象)传值
         const list = reactive(['苹果', '梨', '香蕉'])
        return {
    
    
            msg1,
            list
        }
    }
}
</script>
 
// 子组件 接收
<template>
  <ul >
    <li  v-for="i in list" :key="i">{
    
    {
    
     i }}</li>
  </ul>
</template>
<script>
export default {
    
    
  // props接受父组件传过来的值
  props: ["msg1", "list"],
  setup(props) {
    
    
    console.log(props);
    // {
    
     msg1:"父组件传给子组件的msg1", list:['苹果', '梨', '香蕉'] }
  },
}
</script>

Méthode 2 : utiliser le sucre de syntaxe de configuration

// 父组件 传值
<child :msg="msg" :list="list">
</child>
<script setup>
    import child from "./child.vue";
     const list = reactive(['苹果', '梨', '香蕉'])
    const msg = ref("父组件传给子组件的值");
</script>
 
// 子组件 接收
<template>
  <ul >
    <li  v-for="i in list" :key="i">{
    
    {
    
     i }}</li>
  </ul>
</template>
<script setup>
    // 这里不需要在从vue中引入defineProps,直接用
    const props = defineProps({
    
    
        // 第一种写法
        msg: String,
        // 第二种写法
        list: {
    
    
	    	type: Array,
	   	 	default: () => [],
	  	}
    })
    console.log(props);
</script>

Méthode 2.emit => l'enfant passe la valeur finishEmits au parent

$emit consiste à transmettre des valeurs via des événements personnalisés, principalement utilisés pour que les composants enfants communiquent avec les composants parents .
Dans l'événement click du composant enfant, en déclenchant l'événement personnalisé dans le composant parent, les informations que vous souhaitez transmettre au composant parent sont apportées sous forme de paramètres, et le composant parent peut obtenir les valeurs des paramètres transmises par le composant enfant.

// 子组件 派发
<template>
  <button @click="handleClick">按钮</button>
</template>
<script setup>
  let infos = ref('还好');
  const emit = defineEmits(['myClick']);//emits 为 defineEmits 显示声明后的对象。
// defineEmits:如存在多个监听事件则为 defineEmits(['increase','myClick'])
  const handleClick = () => {
    
    
    // 触发父组件中的方法,并把值以参数的形式传过去
    emit('myClick', infos);
    emit('increase', ref('还好33'));
  };
</script>

 
// 父组件 接收
<template>
    <child @myClick="onMyClick"  @increase="onIncrease"></child>
</template>
<script setup>
    import child from "./child.vue";
    // 父组件接受到子组件传过来的值
    const onMyClick = (msg) => {
    
    
        console.log(msg);
    }
    const onIncrease = (msg) => {
    
    
    console.log(msg.value);
}
</script>

3.expose / ref=》Le parent obtient les attributs ou méthodes de l'enfant

expose et ref sont principalement utilisés par les composants parents pour obtenir les propriétés ou les méthodes des composants enfants . Dans un composant enfant, si des propriétés ou des méthodes sont exposées, le composant parent peut utiliser ref pour obtenir les propriétés ou méthodes exposées sur le composant enfant.

<template>
  <div>父组件:拿到子组件的message数据:{
    
    {
    
     msg }}</div>
  <button @click="callChildFn">调用子组件的方法</button>

  <hr />

  <Child ref="com" />
</template>

<script setup>
  import Child from './child.vue';

  const com = ref(null); // 通过 模板ref 绑定子组件

  const msg = ref('');

  onMounted(() => {
    
    
    // 在加载完成后,将子组件的 message 赋值给 msg
    msg.value = com.value.message;
  });

  function callChildFn() {
    
    
    console.log(com.value, '====');
    // 调用子组件的 changeMessage 方法
    com.value.show();

    //  重新将 子组件的message 赋值给 msg
    msg.value = com.value.message;
  }
</script>

子组件:
<template>
  <div> 子组件:</div>
</template>
<script setup>
  const message = ref('子组件传递得信息');
  const show = () => {
    
    
    console.log('子组件得方法');
  };
  defineExpose({
    
    
    message,
    show,
  });
</script>

4.attrs

attrs est principalement utilisé par les composants enfants pour obtenir des attributs qui ne sont pas reçus via les accessoires du composant parent .

<template>
  <Child :msg1="msg1" :msg2="msg2" title="子组件" />
</template>

<script setup>
  import Child from './child.vue';
  const msg1 = ref('信息1');
  const msg2 = ref('信息2');
</script>

子组件
<template>
  <div> 子组件:{
    
    {
    
     msg1 }}-{
    
    {
    
     attrs.msg2 }}-{
    
    {
    
     attrs.title }}</div>
</template>
<script setup>
  // 子组件接收msg1
  defineProps({
    
    
    msg1: String,
  });

  const attrs = useAttrs();
  // 因为子组件接收了msg1,所以打印的结果中不会包含msg1, {
    
     msg2:"信息1", title: "子组件" }
  // 如果子组件没有接收msg1,打印的结果就是 {
    
     msg1: "信息1", msg2:"信息12", title: "子组件" }
  console.log(attrs);
</script>


5. fournir / injecter

Lorsqu'on est confronté à un transfert de valeur multicouche, la méthode d'utilisation des accessoires et de l'émission semblera maladroite. À ce stade, vous pouvez utiliser provide et inject.
Fournir et injecter communique principalement des composants parents aux composants enfants ou aux composants enfants imbriqués à plusieurs niveaux .
provide : dans le composant parent, vous pouvez utiliser provide pour fournir les informations qui doivent être transmises aux composants descendants.
injecter : Du composant parent au composant, quel que soit le nombre de couches imbriquées, vous pouvez directement utiliser inject pour obtenir les informations transmises par le composant parent.

<template>
  <div>------祖父组件---------</div>
  <button @click="fn">改变location的值</button>
  <br />
  <div>双向数据绑定:</div>
  姓名 {
    
    {
    
     userInfos.username }}<input v-model="userInfos.username" />
  <Child />
</template>

<script setup>
  import Child from './child.vue';
  let location = ref('传递祖父的参数');
  var userInfos = reactive({
    
    
    username: '张三',
    age: 20,
  });
  let fn = () => {
    
    
    location.value = '改变值';
  };
  provide('location', location);
  provide('userInfos', readonly(userInfos));
</script>

子组件:
<template>
	<div>
		  <Sun />
	</div>
</template>

<script>
import Sun from "./sun.vue";
</script>
孙组件:
<template>
  <div>
    <h5>-------------孙组件接受参数-------------</h5>
    <div>1.祖父组件定义provide,孙组件inject接受:{
    
    {
    
     location }}</div>
    <p>用户信息: {
    
    {
    
     userInfos.username }}</p>
    <br />
    <br />
    <div>2.provide inject实现父子组件传值的时候,子组件改变数据也会影响父组件</div>
    <br />姓名:
    <input v-model="userInfos.username" />
  </div>
</template>
<script setup>
  let location = inject('location');
  let userInfos = inject('userInfos');
</script>


Remarque : Après l'ajout en lecture seule, la modification du sous-composant n'affectera pas le composant parent.

Provide/inject de type sécurisé
utilise l'outil de type injectionKey fourni par vue pour partager des types dans différents contextes

context。ts

import {
    
     InjectionKey, Ref } from 'vue'
 
export interface SetUser{
    
    
 name: string
  age: number
}
 
// 函数的的InjectionKey
export const setUserKey: InjectionKey<SetUser> = Symbol()


父组件
<script setup>
import {
    
    setUserKey } from './context'
provide(setUserKey , {
    
     
name: 'Karen', //如果输入1,那么类型就会报错
age: 20
 })
</script>

子组件
<script setup>
import {
    
    setUserKey } from './context'
const user =inject(setUserKey)// 输出SetUser | undefined
if(user){
    
    
console.log(user.name)//Karen
}
</script>

6. lecture seule

Obtient un objet (objet réactif ou pur) ou une référence et renvoie un proxy en lecture seule du proxy d'origine. Les propriétés ne peuvent pas être réaffectées. Les proxys en lecture seule sont récursifs : toutes les propriétés imbriquées accessibles sont également en lecture seule.
Simple à comprendre : pour garantir que les données transmises par le composant parent ne seront pas modifiées par les composants descendants, ajoutez en lecture seule

Modèle 7.v

v-model est un sucre de syntaxe pour Vue. Il existe d'autres façons de jouer dans Vue3

Liaison à modèle V unique

<template>
  <Child v-model="message" />
</template>

<script setup>
  import Child from './child.vue';
  const message = ref('父传给子');
</script>
子组件:
<template>
  <div>
    <button @click="handleClick">修改model</button>
    {
    
    {
    
     modelValue }}
  </div>
</template>
<script setup>
  // 接收
  defineProps([
    'modelValue', // 接收父组件使用 v-model 传进来的值,必须用 modelValue 这个名字来接收
  ]);

  const emit = defineEmits(['update:modelValue']); // 必须用 update:modelValue 这个名字来通知父组件修改值

  function handleClick() {
    
    
    // 参数1:通知父组件修改值的方法名
    // 参数2:要修改的值
    emit('update:modelValue', '子改变值');
  }
</script>


Liaison de modèles V multiples

<template>
  <Child v-model:msg1="message1" v-model:msg2="message2" />
</template>

<script setup>
  import Child from './child.vue';
  const message1 = ref('水果1');
  const message2 = ref('水果2');
</script>
子组件:
<template>
  <div>
    <div><button @click="changeMsg1">修改msg1</button> {
    
    {
    
     msg1 }}</div>
    <div><button @click="changeMsg2">修改msg2</button> {
    
    {
    
     msg2 }}</div>
  </div>
</template>
<script setup>
  // 接收
  defineProps({
    
    
    msg1: String,
    msg2: String,
  });

  const emit = defineEmits(['update:msg1', 'update:msg2']);

  function changeMsg1() {
    
    
    emit('update:msg1', '蔬菜1');
  }

  function changeMsg2() {
    
    
    emit('update:msg2', '蔬菜2');
  }
</script>

modificateur de modèle V

v-model peut également transmettre des modifications sous la forme de . v-model a des modificateurs intégrés - .trim, .number et .lazy. Cependant, dans certains cas, vous devrez peut-être également ajouter vos propres modificateurs personnalisés.

<template>
  <Child v-model.uppercasefn="message" />
</template>

<script setup>
  import Child from './child.vue';
  const message = ref('水果');
</script>
子组件:
<template>
  <div>
    <div>{
    
    {
    
     modelValue }}</div>
  </div>
</template>
<script setup>
  const props = defineProps(['modelValue', 'modelModifiers']);

  const emit = defineEmits(['update:modelValue']);

  onMounted(() => {
    
    
    console.log(props.modelModifiers, '自定义v-model 修饰符');
    // 判断有没有uppercasefn修饰符,有的话就执行 下面得方法 方法
    if (props.modelModifiers.uppercasefn) {
    
    
      emit('update:modelValue', '蔬菜');
    }
  });
</script>


8. emplacement pour fente

Le slot peut être compris comme le passage d'un fragment HTML au composant enfant. Les composants enfants utilisent des éléments comme points de vente pour héberger le contenu distribué.

Emplacement par défaut

L'utilisation de base du slot est très simple : utilisez simplement la balise dans le composant enfant et le contenu HTML transmis par le composant parent sera rendu.

<template>
  <Child>
    <div>渲染</div>
  </Child>
</template>
子组件:
// Child.vue

<template>
  <div>
    <slot></slot>
  </div>
</template>

emplacement nommé

Les emplacements nommés sont classés sur la base des emplacements par défaut, qui peuvent être compris comme des emplacements correspondants.

<template>
  <Child>
    <template v-slot:monkey>
      <div>渲染</div>
    </template>

    <button>按钮</button>
  </Child>
</template>
子组件:
<template>
  <div>
    <!-- 默认插槽 -->
    <slot></slot>
    <!-- 具名插槽 -->
    <slot name="monkey"></slot>
  </div>
</template>

Le composant parent doit utiliser une étiquette et utiliser v-solt: + name sur l'étiquette. Les sous-composants doivent être reçus avec name= name dans la balise.

emplacement pour lunette

<template>
  <!-- v-slot="{scope}" 获取子组件传上来的数据 -->
  <!-- :list="list" 把list传给子组件 -->
  <Child v-slot="{ scope }" :list="list">
    <div>
      <div>{
    
    {
    
     scope.name }}--职业:{
    
    {
    
     scope.occupation }}</div>
      <hr />
    </div>
  </Child>
</template>
<script setup>
  import Child from './child.vue';
  const list = reactive([
    {
    
     name: '鲁班', occupation: '辅助' },
    {
    
     name: '貂蝉', occupation: '刺客和法师' },
    {
    
     name: '虞姬', occupation: '射手' },
  ]);
</script>
子组件:
<template>
  <div>
    <!-- 用 :scope="item" 返回每一项 -->
    <slot v-for="item in list" :scope="item"></slot>
  </div>
</template>
<script setup>
  defineProps({
    
    
    list: {
    
    
      type: Array,
      default: () => [],
    },
  });
</script>

9. Bus événementiel (gant et petit émetteur)

Le bus d'événements a été supprimé dans Vue3, mais cela peut être réalisé à l'aide d'outils tiers. Vue recommande officiellement mitt ou tiny-emitter ;
dans la plupart des cas, il n'est pas recommandé d'utiliser le bus d'événements global pour implémenter la communication des composants. , bien que ce soit relativement simple et rudimentaire, mais la maintenance du bus événementiel est un gros problème à long terme.

gant

mitt.js n'est pas spécifiquement conçu pour servir Vue, mais Vue peut utiliser mitt.js pour la communication entre composants. (vue3 supprime le, le,Après on et off , utilisez la bibliothèque tierce mitt pour remplacer le principe d'eventBus. )

En quoi mitt.js est-il meilleur qu'EventBus sur les instances Vue ?
  1. Tout d’abord, il est assez petit, seulement 200 octets.
  2. Deuxièmement, il prend en charge la surveillance et la suppression par lots de tous les événements.
  3. Il ne repose pas sur les instances Vue et peut être utilisé dans tous les frameworks React ou Vue, et même les projets jQuery peuvent utiliser le même ensemble de bibliothèques.

npm install --save gant

父组件:
<template>
	<div>
		<Home />
        <Mitt/>
    <div>
</template>
<script >
import Home from "@/views/home.vue";
import Mitt from "@/views/mitt.vue";
</script >
emiter.js
// mitt库默认导出的是一个函数,我们需要执行它从而得到事件总线的对象
import mitt from 'mitt'
const emiter = mitt()
export default emiter

子组件Home:
<template>
	<div>
         <p>这里是home组件</p>
	<button @click="sendHomeContent">$mitt发送数据</button>  
	</div>
</template>

<script>
import {
    
     ref}from 'vue'
import emitter from "./../model/emitter.js";
export default {
    
    
    setup(props,ctx) {
    
    
        const money = ref(98);
        var sendHomeContent=()=>{
    
    
            // emit发送信息
            emitter.emit("moneyEvent",money.value += 2);// 触发自定义总线moneyEvent,并传入一个对象 。
        }
        return{
    
    
            sendHomeContent
        }
    }
};
</script>
子组件 Mitt:
<template>
	<div>
		<p>这里是Mitt组件</p>
        <p>接收到的数据:{
    
    {
    
     amount }}</p>
	</div>
</template>

import {
    
     ref,   onUnmounted, onMounted } from 'vue';
import emitter from "../model/event";
export default {
    
    
	setup(props,ctx) {
    
    
        const amount = ref(0);
        const callback = (res) => {
    
    
            if (res) {
    
    
                amount.value = res;
            }
        }
        onMounted(() => {
    
    
           //DOM挂载完毕
            emitter.on('moneyEvent', callback );
        })
        onUnmounted(() => {
    
    
            //销毁完毕
            emitter.off('moneyEvent',callback );
        });
        return {
    
    
            amount
        }
    }
};

Insérer la description de l'image ici
Résumé :
émettre envoie des informations
, reçoit des informations
, annule la surveillance
et efface tous les événements. La méthode d'écriture
émetteur.all.clear()

10. Outils de gestion du statut

Vuex et Pinia sont des outils de gestion d'état dans Vue 3. Grâce à ces deux outils, la communication entre les composants peut être facilement réalisée.
Pinia est un outil relativement populaire ces derniers temps. Il est également utilisé pour gérer la communication entre composants. Il est très probable qu'il devienne Vuex 5.

2. Détails

1.Comment utiliser ref dans Vue3 ? Comment utiliser ref avec v-for ?

référence dans Vue2

Obtenir des nœuds : C'est l'une des fonctions de base de ref. Le but est d'obtenir des nœuds d'éléments. Elle est également très simple à utiliser dans Vue.

<template>
  <div id="app">
    <div ref="test">你好!</div>
  </div>
</template>
<script>
export default {
    
    
  mounted() {
    
    
    console.log(this.$refs.test); // <div>你好!</div>
  },
};
</script>

ref accéder aux éléments dans Vue3

L'accès aux nœuds d'éléments via ref dans Vue3 est différent de Vue2. Dans Vue3, nous n'avons pas this ou this.$refs. Pour obtenir la référence, nous pouvons uniquement déclarer une variable.

<template>
  <div ref="test">你好!</div>
</template>
<script setup >
import {
    
     onMounted, ref } from "vue";
const test = ref(null);
onMounted(() => {
    
    
  console.log(test.value); // <div>你好!</div>
});
</script>

Remarques :
• Le nom de la variable doit être cohérent avec le nom de l'attribut nommé par la réf.
• Récupérez l'élément DOM sous la forme test.value.
• Test.value doit être obtenu une fois le rendu DOM terminé, sinon il sera nul.

Utiliser la référence dans v-for

Il existe de nombreux scénarios d'utilisation de la référence. L'un consiste à le lier à un nœud d'élément seul, et l'autre consiste à le lier à un élément bouclé par v-for. C'est une exigence très courante. Dans Vue2, nous utilisons généralement la forme : ref="...", tant que nous pouvons identifier que chaque référence est différente.
Mais c'est différent dans Vue3, mais cela peut toujours être reçu sous forme de variables.

<template>
	<div>
         <p ref="test">1. v-for 中的 Ref 数组</p>
            <div v-for="item in 5" :key="item"  :ref="setItemRef">
                  {
    
    {
    
     item }} -水果
            </div>
          <button @click="printFN">点击2</button>
	</div>
</template>

<script>
import {
    
     ref,onMounted}from 'vue'
export default {
    
    
    setup(props,ctx) {
    
    
        const test = ref(null);
        let itemRefs = [];
        const setItemRef = el => {
    
    
        if (el) {
    
    
            itemRefs.push(el)
        }
        }
        onMounted(() => {
    
    
            console.log(test.value,'在 vue3 中'); // <div>小猪课堂</div>
        });
        const printFN=()=>{
    
    
            console.log(itemRefs,'在嵌套 vue3 中')
        }
        return {
    
    
            test,
            setItemRef,
            printFN
        }
    }
};
</script>

Insérer la description de l'image ici
Ici, nous devons faire attention : nous semblons n'avoir aucun moyen de distinguer quelle balise li et quelle ref. Sauf pour la première fois, notre tableau itemRefs ne peut pas garantir le même ordre que le tableau d'origine, c'est-à-dire une correspondance biunivoque avec les éléments du tableau original de la liste.

fonction de liaison de référence

Lorsque nous avons défini ref sur le composant plus tôt, nous avons toujours utilisé une chaîne comme nom de ref. En fait, notre attribut ref peut également recevoir une fonction comme valeur d'attribut. Dans ce cas, nous devons ajouter : devant ref.

<template>
	   <div :ref="setHelloRef">水果</div>
</template>

<script>
import {
    
     ref}from 'vue'
export default {
    
    
    setup(props,ctx) {
    
    
        const setHelloRef = (el) => {
    
    
          console.log(el); // <div>水果</div>
        };
        return {
    
    
            setHelloRef
        }
    }
};
</script>

L'attribut ref dans le code ci-dessus reçoit une fonction setHelloRef, qui reçoit par défaut un paramètre el, qui est l'élément div que nous devons obtenir. Si nous adoptons cette méthode dans nos exigences, nous pouvons enregistrer el dans une variable pour une utilisation ultérieure.

Utilisation de la fonction ref dans v-for

<template>
    <div v-for="item in 10" :key="item" :ref="(el) => setItemRefs(el, item)">
            {
    
    {
    
     item }} -水果
    </div>
</template>

<script>
import {
    
     ref,onMounted}from 'vue'
export default {
    
    
    setup(props,ctx) {
    
     
        let itemRefs = [];
        const setItemRefs = (el,item) => {
    
    
            if(el) {
    
    
                itemRefs.push({
    
    
                    id: item,
                    el,
                });
            }
        }
        onMounted(() => {
    
    
            console.log(itemRefs,'在 vue3 中'); // <div>小猪课堂</div>
        });
        return {
    
    
            setItemRefs
        }
    }
};
</script>

Passer ref sous la forme d'une fonction dans v-for est similaire au formulaire lorsque vous n'utilisez pas v-for, mais ici nous avons fait un petit changement. Afin de distinguer quelle ref est quelle balise li, nous avons décidé de passer l'élément dans la fonction, c'est-à-dire (el) => setItemRefs(el, item) est écrite.
L'avantage de cette forme est qu'elle améliore non seulement notre opérabilité, mais résout également le problème selon lequel l'ordre du tableau ref dans la boucle v-for ne correspond pas à l'ordre du tableau d'origine.
Insérer la description de l'image ici

Utiliser la référence sur les composants

Lors de l'utilisation de ref auparavant, il était lié à un élément dom spécifique, mais nous pouvons également lier ref à un composant. Par exemple, dans Vue2, lorsque nous lions ref à un composant, nous pouvons obtenir toutes les données et méthodes du composant. Dans Vue3, lorsque vous utilisez ref pour obtenir un sous-composant, si vous souhaitez obtenir les données ou les méthodes du sous-composant, le sous-composant peut exposer les données via la méthode DefinExpose .
Reportez-vous à ce qui précède "expose/ref=》Le parent obtient les attributs ou les méthodes de l'enfant"

Je suppose que tu aimes

Origine blog.csdn.net/gao_xu_520/article/details/125596347
conseillé
Classement