Comunicación entre componentes en Vue

Tabla de contenido

introducir

componente padre ==> componente hijo

Componente hijo ==> componente padre

autobús de eventos globales

Suscripción y publicación de mensajes


introducir

¿Sabes cómo comunicarte entre componentes en Vue? Hay múltiples relaciones involucradas, como la transmisión mutua entre padre e hijo, hermanos, hijos y nietos, e incluso componentes arbitrarios...

¿Sientes un poco de hormigueo en el cuero cabelludo? No importa, ¡este artículo los llevará a aprender juntos las soluciones correspondientes! ! !

componente padre ==> componente hijo

Si el componente principal quiere pasar información al componente secundario, la forma más común es usar el elemento de configuración de accesorios. La función de este elemento de configuración es permitir que el componente acepte datos externos.

Pasar datos:<Demo name="xxx"/>

Recibir datos:

1. El primer método (solo recepción):props:['name']

2. La segunda forma (tipo de restricción):props:{name:String}

3. El tercer método (tipo de restricción, necesidad de restricción, especificación del valor predeterminado):

props:{
    name:{
    type:String, //类型
    required:true, //必要性
    default:'老王' //默认值
    }
}

Ahora escriba un caso en el scaffolding para darse cuenta de que el componente principal pasa datos al componente secundario y los muestra en la página. El componente principal predeterminado es Aplicación y el componente secundario es Estudiante. Primero pase tres datos del componente principal al componente secundario y muéstrelos en la página. Los métodos de aceptación se implementan de las formas anteriores respectivamente, y los códigos correspondientes son los siguientes:

aplicación.vue

<template>
    <div>
        <!-- 为子组件传入数据 -->
        <Student name="N-A" sex="男" age="5"/>
    </div>
</template>
​
<script>
    //导入Student组件
    import Student from './components/Student'
    export default {
        name:'App',
    //注册Student组件
        components:{Student}
    }
</script>
​

Student.view

<template>
    <div>
        <h1>{
   
   {msg}}</h1>
        <h2>博主姓名:{
   
   {name}}</h2>
        <h2>博主性别:{
   
   {sex}}</h2>
        <h2>博主年龄:{
   
   {age}}</h2>
    </div>
</template>
<script>
    export default {
        //组件名命名为Student
        name:'Student',
        data() {
            return {
                msg:'我是一名CSDN博主'
            }
        },
        //方式一:简单声明接收
        props:['name','sex',"age"]
​
        //方式二:接收的同时对数据进行类型限制
        props:{
            name:String,
            age:Number,
            sex:String
        } 
​
        //方式三:接收的同时对数据:进行类型限制+默认值的指定+必要性的限制
        props:{
            name:{
                type:String, //name的类型是字符串
                required:true, //name是必要的
            },
            age:{
                type:Number,
                default:99 //默认值
            },
            sex:{
                type:String,
                required:true
            }
        }
    }
</script>

Las representaciones de los tres modos proporcionados al ejecutar los códigos anteriores se muestran arriba.Los tres modos pueden mostrar datos en la página. Pero hay algunos problemas involucrados. En la figura 2 se muestra el error en la consola al usar el segundo método para recibir los datos entrantes, aunque los datos se pueden ver en la página, ya hay un problema, porque estipulamos el atributo de edad de los datos entrantes al recibir los datos. El tipo es tipo de número.

Pero cuando pasamos el valor, escribimos age="5", por lo que el pasado en 5 es una cadena. Entonces, ¿cómo resolverlo? Solo pon dos puntos antes de la edad. Vincúlelo, y después de vincularlo, todo lo que esté entre comillas dobles se analizará como una expresión JS. Por lo tanto, después del análisis, será un número 5 puro, por lo que se puede resolver el problema correspondiente.

Ahora estoy agregando un requisito para agregar un botón en la página para lograr el efecto de agregar uno a la edad en la página después de hacer clic. El código correspondiente es el siguiente:

<template>
    <div>
        <h1>{
   
   {msg}}</h1>
        <h2>博主姓名:{
   
   {name}}</h2>
        <h2>博主性别:{
   
   {sex}}</h2>
        <h2>博主年龄:{
   
   {MyAge}}</h2>
        <button @click="updateAge">年龄加一</button>
    </div>
</template>
​
<script>
    export default {
        name:'Student',
        data() {
            return {
                msg:'我是一名CSDN博主',
                MyAge:this.age
            }
        },
        methods: {
            updateAge(){
                this.MyAge++
            }
        },
        //简单声明接收
        props:['name','age','sex'] 
    }
</script>

El efecto se puede mostrar normalmente. (Me gustaría preguntar a mis amigos en línea cómo hacer la animación en su artículo. Después de leer el código anterior, algunos amigos pueden preguntar por qué los datos de edad recibidos por el subcomponente no se modifican directamente. La modificación directa también puede lograr la correspondiente Efecto. ¿Por qué necesita otra configuración MyAge para recibirlo y luego modificar el valor de MyAge? En este momento, debe prestar atención a las siguientes precauciones.

Nota: los accesorios son de solo lectura. La capa inferior de Vue controlará la modificación de los accesorios. Si modifica los accesorios, se emitirá una advertencia. Si la empresa realmente necesita modificarse, copie el contenido de los accesorios en una copia. de datos, y luego modifíquelo Los datos en datos.

Componente hijo ==> componente padre

Método de implementación 1: pase los accesorios del tipo de función al componente secundario a través del componente principal, para realizar la transmisión de datos del componente secundario al componente principal. Ya tenemos una cierta comprensión de los accesorios antes, ¡así que ahora implementémoslo a través del código!

Caso: El componente Escuela tiene dos datos, el nombre de la escuela y la dirección de la escuela, ahora es necesario darse cuenta de que el componente padre de la aplicación puede recibir el nombre de la escuela pasado del componente Escuela hijo.

App.vue (componente principal)

<template>
    <div class="app">
        <!-- 通过父组件给子组件传递函数类型的props实现:子给父传递数据 -->
        <School :getSchoolName="getSchoolName"/>
    </div>
</template>
​
<script>
    import School from './components/School'
    export default {
        name:'App',
        components:{School},
        methods: {
            getSchoolName(name){
                console.log('App收到了学校名:',name)
            }
        }
    }
</script>
​
<style scoped>
    .app{
        background-color: gray;
        padding: 5px;
    }
</style>

En el componente principal de la aplicación, se define una función getSchoolName y se pasa al componente secundario.

School.vue (subcomponente)

<template>
    <div class="school">
        <h2>学校名称:{
   
   {name}}</h2>
        <h2>学校地址:{
   
   {address}}</h2>
        <button @click="sendSchoolName">把学校名给App</button>
    </div>
</template>
​
<script>
    export default {
        name:'School',
        props:['getSchoolName'],
        data() {
            return {
                name:'史莱克学院',
                address:'天斗帝国',
            }
        },
        methods: {
            sendSchoolName(){
                this.getSchoolName(this.name)
            }
        },
    }
</script>
​
<style scoped>
    .school{
        background-color:rgb(212, 237, 210);
        padding: 5px;
    }
</style>

El subcomponente usa el elemento de configuración props para recibir la función getSchoolName, llama a la función pasada en la función sendSchoolName y pasa el nombre de la escuela. Y vincule el evento de clic getSchoolName al botón. Después de hacer clic, se logra el propósito de pasar el nombre de la escuela al componente padre. El efecto de implementación correspondiente es el siguiente:



Método de implementación 2: si el componente secundario quiere pasar datos al componente principal, también puede usar el evento personalizado del componente. El escenario de uso es: si A es un componente principal, B es un componente secundario y B quiere pasar datos a A, entonces es necesario vincular un evento personalizado a B en A (la devolución de llamada del evento está en A) .

Hay dos formas de enlazar eventos personalizados:

La primera forma, en el componente padre: <Demo @自定义事件名="test"/>o<Demo v-on:自定义事件名="test"/>

El caso sigue arriba, modificando el código correspondiente al evento personalizado de la primera forma de la siguiente manera:

App.vue (componente principal)

<template>
    <div class="app">
        <!-- 通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第一种写法,使用@或v-on) -->
        <School @showName="getSchoolName"/>
    </div>
</template>
​
<script>
    import School from './components/School'
    export default {
        name:'App',
        components:{School},
        methods: {
            getSchoolName(name){
                console.log('App收到了学校名:',name)
            }
        },
    }
</script>
​
<style scoped>
    .app{
        background-color: gray;
        padding: 5px;
    }
</style>
​

School.vue (subcomponente)

<template>
    <div class="school">
        <h2>学校名称:{
   
   {name}}</h2>
        <h2>学校地址:{
   
   {address}}</h2>
        <button @click="sendSchoolName">把学校名给App</button>
    </div>
</template>
​
<script>
    export default {
        name:'School',
        data() {
            return {
                name:'史莱克学院',
                address:'天斗帝国',
            }
        },
        methods: {
            sendSchoolName(){
                //触发School组件实例身上的showName事件
                this.$emit('showName',this.name)
            }
        },
    }
</script>
​
<style scoped>
    .school{
        background-color:rgb(212, 237, 210);
        padding: 5px;
    }
</style>

El efecto es el siguiente: ¡se puede mostrar normalmente!

La segunda forma es simplemente cambiar la forma de vincular eventos en el componente principal, y solo necesita modificar el código en el componente principal:

<template>
	<div class="app">
		<!-- 通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第二种写法,使用ref) -->
		<School ref="school" />
	</div>
</template>

<script>
	import School from './components/School'
	export default {
		name:'App',
		components:{School},
		methods: {
			getSchoolName(name){
				console.log('App收到了学校名:',name)
			}
		},
		mounted() {
			this.$refs.school.$on('showName',this.getSchoolName) //绑定自定义事件
		},
	}
</script>

<style scoped>
	.app{
		background-color: gray;
		padding: 5px;
	}
</style>

El efecto es el mismo que el anterior. No entraré en demasiados detalles sobre otros puntos de conocimiento sobre eventos personalizados aquí, después de todo, se trata principalmente de compartir cómo implementa los componentes secundarios para transmitir datos a los componentes principales.

Nota: Al this.$refs.xxx.$on('atguigu',回调)vincular un evento personalizado, la devolución de llamada debe configurarse en métodos o usar una función de flecha, de lo contrario, esto causará problemas.

autobús de eventos globales

El bus de eventos global es una forma de comunicación entre componentes, que es adecuada para la comunicación entre cualquier componente.

1. Instale el bus de eventos global:

new Vue({
    ......
    beforeCreate() {
        Vue.prototype.$bus = this //安装全局事件总线,$bus就是当前应用的vm
    },
    ......
}) 

2. Utilice el bus de eventos:

  • Recibir datos: si el componente A quiere recibir datos, vincula un evento personalizado a $bus en el componente A, y la devolución de llamada del evento permanece en el componente A mismo.
methods(){
  demo(data){......}
}
......
mounted() {
  this.$bus.$on('xxxx',this.demo)
}
  • Proveer información:this.$bus.$emit('xxxx',数据)

3. Es mejor usar $off en el gancho beforeDestroy para desvincular los eventos usados ​​por el componente actual .

Caso: Hay dos componentes hermanos, a saber, el componente Estudiante y el componente Escuela. Es necesario implementar el componente Estudiante para transmitir datos al componente Escuela. El código de implementación correspondiente es el siguiente:

El archivo de entrada main.js necesita instalar primero el bus de eventos global.

//引入Vue
import Vue from 'vue'
//引入App
import App from './App.vue'
//关闭Vue的生产提示
Vue.config.productionTip = false
​
//创建vm
new Vue({
    el:'#app',
    render: h => h(App),
//安装全局事件总线
    beforeCreate() {
        Vue.prototype.$bus = this 
    }
})

Proporcione el código del componente del cubo de datos de la siguiente manera:

<template>
    <div class="student">
        <h2>学生姓名:{
   
   {name}}</h2>
        <h2>学生性别:{
   
   {sex}}</h2>
        <button @click="sendStudentName">把学生名给School组件</button>
    </div>
</template>
​
<script>
    export default {
        name:'Student',
        data() {
            return {
                name:'N-A',
                sex:'男',
            }
        },
        methods: {
            //提供数据
            sendStudentName(){
                this.$bus.$emit('hello',this.name)
            }
        },
    }
</script>
​
<style  scoped>
    .student{
        background-color:rgb(212, 237, 210);
        padding: 5px;
        margin-top: 30px;
    }
</style>

El código del componente de la parte receptora de datos es el siguiente:

<template>
    <div class="school">
        <h2>学校名称:{
   
   {name}}</h2>
        <h2>学校地址:{
   
   {address}}</h2>
    </div>
</template>
​
<script>
    export default {
        name:'School',
        data() {
            return {
                name:'史莱克学院',
                address:'天斗帝国',
            }
        },
        //绑定一个hello事件,用于接收数据
        mounted() {
            this.$bus.$on('hello',(data)=>{
                console.log('我是School组件,收到了数据',data)
            })
        },
        //用$off去解绑<span style="color:red">当前组件所用到的</span>事件。
        beforeDestroy() {
            this.$bus.$off('hello')
        },
    }
</script>
​
<style scoped>
    .school{
        background-color:rgb(212, 237, 210);
        padding: 5px;
    }
</style>

El efecto de implementación es el siguiente, la transferencia de datos se realiza entre componentes hermanos.

Suscripción y publicación de mensajes

La suscripción y publicación de mensajes es una forma de comunicación entre componentes, que es aplicable a la comunicación entre cualquier componente. El uso es el siguiente:

1. Instala pubsub:npm i pubsub-js

2. Presente:import pubsub from 'pubsub-js'

3. Recibir datos: si un componente desea recibir datos, se suscribe al mensaje en un componente y la devolución de llamada suscrita permanece en el mismo componente.

methods(){
  demo(data){......}
}
......
mounted() {
  this.pid = pubsub.subscribe('xxx',this.demo) //订阅消息
}

4. Proporcionar datos:pubsub.publish('xxx',数据)

5. Lo mejor es PubSub.unsubscribe(pid)darse .

Este método es similar al bus de eventos global mencionado anteriormente, principalmente porque no se necesita $bus, sino que se reemplaza por pubsub.

Después de modificar el código anterior de la siguiente manera:

Proporcione el código del componente del cubo de datos de la siguiente manera:

<template>
    <div class="student">
        <h2>学生姓名:{
   
   {name}}</h2>
        <h2>学生性别:{
   
   {sex}}</h2>
        <button @click="sendStudentName">把学生名给School组件</button>
    </div>
</template>
​
<script>
    import pubsub from 'pubsub-js'
    export default {
        name:'Student',
        data() {
            return {
                name:'N-A',
                sex:'男',
            }
        },
        methods: {
            sendStudentName(){
                pubsub.publish('hello',this.name)
            }
        },
    }
</script>
​
<style  scoped>
    .student{
        background-color:rgb(212, 237, 210);
        padding: 5px;
        margin-top: 30px;
    }
</style>

El código del componente de la parte receptora de datos es el siguiente:

<template>
    <div class="school">
        <h2>学校名称:{
   
   {name}}</h2>
        <h2>学校地址:{
   
   {address}}</h2>
    </div>
</template>
​
<script>
    import pubsub from 'pubsub-js'
    export default {
        name:'School',
        data() {
            return {
                name:'史莱克学院',
                address:'天斗帝国',
            }
        },
        mounted() {
            this.pubId = pubsub.subscribe('hello',(msgName,data)=>{
                console.log(data)
            })
        },
        beforeDestroy() {
            pubsub.unsubscribe(this.pubId)
        },
    }
</script>
​
<style scoped>
    .school{
        background-color:rgb(212, 237, 210);
        padding: 5px;
    }
</style>

El efecto es el siguiente:

 Bueno, este artículo está por aquí, ¿lo has aprendido? Si tiene alguna pregunta o problema, no dude en encontrarme en el área de comentarios o en un mensaje privado para comunicarnos y aprender juntos.

Supongo que te gusta

Origin blog.csdn.net/weixin_51735748/article/details/132255330
Recomendado
Clasificación