Comunicación del componente vue3 y uso de ref&v-model.

1. Comunicación de componentes

1. props => el padre pasa el valor al niño

Los accesorios se utilizan principalmente para comunicarse entre los componentes principales y los componentes secundarios . En el componente principal, use :msg="msg" para vincular el valor de propiedad que debe pasarse al componente secundario y luego use accesorios en el componente secundario para recibir el valor de propiedad.

Método 1: forma normal:

// 父组件 传值
<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étodo 2: utilizar la sintaxis de configuración sugar

// 父组件 传值
<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>

2.método de emisión => el niño pasa el valor defineEmits al padre

$emit consiste en pasar valores a través de eventos personalizados, que se utilizan principalmente para que los componentes secundarios se comuniquen con los componentes principales .
En el evento de clic del componente secundario, al activar el evento personalizado en el componente principal, la información que desea pasar al componente principal se presenta en forma de parámetros, y el componente principal puede obtener los valores de los parámetros pasados. el componente hijo.

// 子组件 派发
<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=》El padre obtiene los atributos o métodos del hijo

exponen y ref son utilizados principalmente por los componentes principales para obtener propiedades o métodos de los componentes secundarios . En un componente secundario, si se exponen propiedades o métodos, el componente principal puede usar ref para obtener las propiedades o métodos expuestos en el componente secundario.

<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.atributos

attrs es utilizado principalmente por componentes secundarios para obtener atributos que no se reciben a través de accesorios en el componente principal .

<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. proporcionar / inyectar

Cuando se encuentra con una transferencia de valor de múltiples capas, el método de usar accesorios y emitir parecerá torpe. En este momento puedes usar proporcionar e inyectar.
Proporcionar e inyectar se comunica principalmente desde componentes principales a componentes secundarios o componentes secundarios anidados de varios niveles .
proporcionar: en el componente principal, puede utilizar proporcionar para proporcionar información que debe transmitirse a los componentes descendientes.
inyectar: ​​desde el componente principal al componente, no importa cuántas capas estén anidadas, puede usar inyectar directamente para obtener la información transmitida por el componente principal.

<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>


Nota: Después de agregar solo lectura, la modificación del subcomponente no afectará al componente principal.

Proporcionar/inyectar con seguridad de tipos
utiliza la herramienta de tipo injectionKey proporcionada por vue para compartir tipos en diferentes contextos

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.solo lectura

Obtiene un objeto (objeto reactivo o puro) o referencia y devuelve un proxy de solo lectura del proxy original. Las propiedades no se pueden reasignar. Los servidores proxy de solo lectura son recursivos: cualquier propiedad anidada a la que se acceda también es de solo lectura.
Fácil de entender: para garantizar que los datos pasados ​​por el componente principal no sean modificados por los componentes descendientes, agregue solo lectura

modelo 7.v

v-model es un azúcar de sintaxis para Vue. Hay más formas de jugar en Vue3

Encuadernación de modelo en V único

<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>


Enlace de múltiples modelos v

<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>

modificador del modelo v

v-model también puede pasar modificaciones en forma de . v-model tiene modificadores integrados : .trim, .number y .lazy. Sin embargo, en algunos casos es posible que también necesites agregar tus propios modificadores personalizados.

<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. ranura ranura

Se puede entender que la ranura pasa un fragmento HTML al componente secundario. Los componentes secundarios utilizan elementos como salidas para alojar contenido distribuido.

Ranura predeterminada

El uso básico de la ranura es muy simple: simplemente use la etiqueta en el componente secundario y se procesará el contenido HTML pasado por el componente principal.

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

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

ranura con nombre

Las ranuras con nombre se clasifican según las ranuras predeterminadas, que pueden entenderse como ranuras coincidentes.

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

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

El componente principal necesita usar una etiqueta y usar v-solt: + nombre en la etiqueta. Los subcomponentes deben recibirse con nombre = nombre en la etiqueta.

ranura de alcance

<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 de eventos (mitt&tiny-emitter)

El bus de eventos se ha eliminado en Vue3, pero se puede lograr con la ayuda de herramientas de terceros. Vue recomienda oficialmente mitt o tiny-emitter ;
en la mayoría de los casos, no se recomienda utilizar el bus de eventos global para implementar la comunicación de componentes. Aunque es relativamente simple y tosco, mantener el bus de eventos es un gran problema a largo plazo.

guante

mitt.js no está diseñado específicamente para servir a Vue, pero Vue puede usar mitt.js para la comunicación entre componentes. (vue3 elimina encendido, encendido,Después de encender y apagar , use la biblioteca de terceros mitt para reemplazar el principio de eventBus. )

¿Cómo es mitt.js mejor que EventBus en instancias de Vue?
  1. En primer lugar, es bastante pequeño, sólo 200 bytes.
  2. En segundo lugar, admite el seguimiento y la eliminación por lotes de todos los eventos.
  3. No depende de instancias de Vue y se puede usar en todos los marcos: React o Vue, e incluso proyectos jQuery pueden usar el mismo conjunto de bibliotecas.

instalación npm --guardar guante

父组件:
<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
        }
    }
};

Insertar descripción de la imagen aquí
Resumen:
emit envía información
activada, recibe información
desactivada, cancela el monitoreo y
borra todos los eventos. El método de escritura
emitter.all.clear()

10. Herramientas de gestión de estado

Vuex y Pinia son herramientas de gestión de estado en Vue3. Con estas dos herramientas, la comunicación de componentes se puede lograr fácilmente.
Pinia es una herramienta relativamente popular recientemente, también se utiliza para manejar la comunicación entre componentes y es muy probable que se convierta en Vuex 5.

2. Detalles

1. ¿Cómo utilizar ref en Vue3? ¿Cómo utilizar ref con v-for?

referencia en Vue2

Obtener nodos: Esta es una de las funciones básicas de ref, el propósito es obtener nodos de elementos, además es muy sencillo de usar en Vue.

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

elementos de acceso de referencia en Vue3

Acceder a los nodos de elementos a través de ref en Vue3 es diferente de Vue2. En Vue3, no tenemos this o this.$refs. Para obtener ref, solo podemos declarar una 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>

Notas:
• El nombre de la variable debe ser coherente con el nombre del atributo nombrado por la ref.
• Obtener el elemento DOM en forma de prueba.valor.
• Test.value debe obtenerse después de completar la representación DOM; de lo contrario, será nulo.

Usar referencia en v-for

Hay muchos escenarios para usar ref: uno es vincularlo solo a un nodo de elemento y el otro es vincularlo a un elemento bucleado por v-for. Este es un requisito muy común, en Vue2 usualmente usamos la forma: ref="...", siempre y cuando podamos identificar que cada referencia es diferente.
Pero es diferente en Vue3, pero aún se puede recibir en forma 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>

Insertar descripción de la imagen aquí
Aquí debemos prestar atención: parece que no tenemos forma de distinguir qué etiqueta li y qué referencia. Excepto por primera vez, nuestra matriz itemRefs no puede garantizar el mismo orden que la matriz original, es decir, correspondencia uno a uno. con los elementos en la matriz original de la lista.

función de enlace de referencia

Cuando definimos ref en el componente anteriormente, siempre usamos una cadena como nombre de ref. De hecho, nuestro atributo ref también puede recibir una función como valor de atributo. En este caso, debemos agregar: delante de 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>

El atributo ref en el código anterior recibe una función setHelloRef, que de forma predeterminada recibe un parámetro el, que es el elemento div que necesitamos obtener. Si adoptamos este método en nuestros requisitos, podemos guardar el en una variable para su uso posterior.

Usando la función de referencia en 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>

Pasar ref en forma de función en v-for es similar a cuando no se usa v-for, pero aquí hicimos un pequeño cambio. Para distinguir qué referencia es qué etiqueta li, decidimos pasar el elemento a se escribe la función, es decir, (el) => setItemRefs(el, item).
La ventaja de esta forma es que no solo mejora nuestra operatividad, sino que también resuelve el problema de que el orden de la matriz ref en el bucle v-for no corresponde al orden de la matriz original.
Insertar descripción de la imagen aquí

Utilice referencia en componentes

Cuando usamos ref antes, estaba vinculado a un elemento dom específico, pero también podemos vincular ref a un componente. Por ejemplo, en Vue2, cuando vinculamos ref a un componente, podemos obtener todos los datos y métodos del componente. En Vue3, cuando se usa ref para obtener un subcomponente, si desea obtener los datos o métodos del subcomponente, el subcomponente puede exponer datos a través del método defineExpose .
Consulte lo anterior "expose/ref=》El padre obtiene atributos o métodos del niño"

Supongo que te gusta

Origin blog.csdn.net/gao_xu_520/article/details/125596347
Recomendado
Clasificación