首页 > 其他分享 >vue:父子组件的通信

vue:父子组件的通信

时间:2024-08-27 23:22:49浏览次数:6  
标签:count vue default counter 父子 props 组件

上一篇:vue组件化开发

在上一篇文章中,我们申明了一点,那就是组件之间是独立的,除非构建了通信。

组件间为什么要构建通信?

在单一文件中写上整个网站的代码逻辑,这无疑使得维护成本巨大。所以我们选择了组件化开发,把组件间独立起来,这样谁也不干涉谁,是谁的逻辑就在谁的文件中实现,最后串在一起,一个网站内容就大功告成了。那父子组件的通信有什么用呢?

我们不妨设想一个场景:在点外卖时,当我们选中某个餐品,下面的计价开始变化,甚至还会计算一下是否满配送,在淘宝购物车中,当我们清空一些商品时,下面也会有总价的变化,或者如果我们想要两个相同组件却拥有不同的反馈,比如两个按钮,一个按钮为提交,一个按钮为回退,但他们来自同一个组件,该怎么为他们添加事件呢?

以上的所有情况我们都可以通过父级组件为子组件提供数据来完成,通过props我们可以为子组件添加Number,String,Object,Array,甚至Function。并且,增加了组件间的通信也表现出了vue的弹性,我们是可以根据自己意愿来添加组件联系的。

组件的通信实现

想要实现组件间的通信,得有一方得发出信息,另一方接收信息,然后返回信息使对方接收到信息,这就是双向通信,但是不是每个组件都是双向通信,我们也可以父级组件单传数据,也可以使子组件单传数据给父组件。

父组件单传子组件

父组件

<template>
  <show-info name="Mike" :age="18" :height="1.88" />
</template>

<script>

import ShowInfo from './ShowInfo.vue'
export default {
  components:{
    ShowInfo,
  }
}
</script>

<style scoped>

</style>

子组件

<template>
  <div class="infos">
    <h2>姓名:{{name}}</h2>
    <h2>年龄:{{age}}</h2>
    <h2>身高:{{height}}</h2>
  </div>
</template>

<script>
export default {
  props:["name","height","age"],
  data(){
    return{
    }
  },
}
</script>

<style scoped>

</style>

 首先,在传输数据前,我们是不是得对一个暗号?这个暗号就是属性名,父组件动态绑定的属性名要与子组件props中的一致,无关顺序。子组件获得来自父组件的数据后就可以使用了。当然,props不只有数组表达形式,还有对象形式。

<template>
  <div class="infos">
    <h2>姓名:{{name}}</h2>
    <h2>年龄:{{age}}</h2>
    <h2>身高:{{height}}</h2>
  </div>
</template>

<script>
export default {
  props:{
      name:String,
      height:Number,
      age:Number
   },
  
  data(){
    return{
    }
  },
 
}
</script>

<style scoped>

</style>

props对象形式中支持我们为传入的数据类型进行一个限制,但是这种限制比较弱,只会提醒一下你,而不会报错。props还有一种形式,这种形式更加完备,我们可以为传输的数据添加默认值,这样即使父级组件没有传入数据也会正常渲染。

<template>
  <div class="infos">
    <h2>姓名:{{name}}</h2>
    <h2>年龄:{{age}}</h2>
    <h2>身高:{{height}}</h2>
  </div>
</template>

<script>
export default {
  props:{
    name:{
      type:String,
      default:"我是默认值"
    },
    height:{
      type: Number,
      default: 0
    },
    age:{
      type: Number,
      default: 0
    },
     
  },
  data(){
    return{
    }
  },
}
</script>

<style scoped>

</style>

非props

形象来说,就是没对上暗号的那些数据该怎么办?

在vue中,这些数据并不会直接丢掉,而是挂在子组件的根节点上,如果有两个根节点会发生什么?

什么都不会发生,会报个错然后让你选取一个根节点来挂载非props数据。

我们可以使用$attrs来访问所有的非props的属性。 

子组件单传父组件

自定义事件

App.vue

<template>
  <h2>counter:{{ counter }}</h2>
  <add-counter @add="addBtnClick"></add-counter>
  <sub-counter @sub="subBtnClick"></sub-counter>
</template>

<script>
import AddCounter from './AddCounter.vue'
import SubCounter from './SubCounter.vue'
export default {
  components:{
    AddCounter,
    SubCounter
  },
  data(){
    return {
      counter:0
    }
  },
  methods:{
    addBtnClick(count){
      this.counter += count;
    },
    subBtnClick(count){
      this.counter -= count;
    }
  }
}
</script>

<style scoped>

</style>

 addCounter.vue

<template>
  <div class="add">
    <button @click="addCounter(1)">+1</button>
    <button @click="addCounter(5)">+5</button>
    <button @click="addCounter(10)">+10</button>
  </div>
</template>

<script>
export default {
  emits:["add"],
  methods:{
    addCounter(count){
      console.log("btnClick",count);
      //第一个参数为事件名称,第二个参数为传递参数
      this.$emit("add",count);
    }
  }
}
</script>

<style scoped>

</style>

 subCounter.vue

<template>
  <div class="sub">
    <button @click="subCounter(1)">-1</button>
    <button @click="subCounter(5)">-5</button>
    <button @click="subCounter(10)">-10</button>
  </div>
</template>

<script>
export default {
  emits:["sub"],
  methods:{
    subCounter(count){
      console.log("btnClick",count);
      this.$emit("sub",count);
    }
  }
}
</script>

<style scoped>

</style>

先来简述一下上述代码功能:

我们分别有+1,+5,+10的三个按钮以及与之对应的减法按钮,当我们点击这些按钮后,位于父组件的counter发生相应的变化。

首先,我们想到的就是在子组件addCounter中创建一个方法increment,传入参数,可以控制为counter加一定的值,再在subCounter中创建一个方法decrement,传入参数,控制counter减一定的值。而counter我们可以通过父组件传过来,计算后的counter在写个方法让父组件监听,父组件得到值后再赋值给counter渲染。

这个方法是可行的。代码如下:

App.vue

<template>
  <div class="app">
    <h2>{{ counter }}</h2>
    <increment :counter="counter" @back="getBackValue"></increment>
  </div>
</template>

<script>
import Increment from './Increment.vue';
export default{
  components:{
    Increment
  },
  data(){
    return{
      counter:0
    }
  },
  methods:{
    getBackValue(res){
      this.counter = res
    }
  }
}
</script>

<style scoped>

</style>

increment.vue

<template>
  <div class="add">
    <button @click="addCounter(1)">+1</button>
    <button @click="addCounter(5)">+5</button>
    <button @click="addCounter(10)">+10</button>
  </div>
</template>

<script>
export default {
  emits:["back"],
  props:["counter"],
  data(){
    return {
      
    }
  },
  methods:{
    addCounter(count){
     let value = this.$props.counter;
     value += count
     console.log("Backing")
     this.$emit("back",value)
    },
    backValue(){
      
    }
  }
}
</script>

<style scoped>

</style>

这样的确能实现目的,但是却不建议这么做,这相当于是把运算过程放在了子组件中,仅仅是把结果返回给父组件。但在实际开发中,我们不一定只开发这么简单的功能,运算或许没这么简单,况且,按下+1按钮给我返回1才符合逻辑吧?我们并不需要子组件干这么多不属于它的活。

下面是另外的一种思路:

对于子组件,不需要父组件给我任何数据,我只需要知道用户按下了哪一个按钮任何返回那个按钮的数值,这样我只需要在点击按钮中释放事件并且把数值传给释放事件中,父组件只需要监听到我这个事件,那任务就结束了。父组件接到子组件传来的值,这时,它可以对这个值做任何操作,这就使得我们有更多的操作空间。

而这就对应着一开始的代码,对比两种思路的代码,你会发现第二种思路的方式组件之间更加独立,至少我们不需要改逻辑的时候跑到子组件的方法中改。

props接收函数的情况

父级组件

<template>
  <div>
    <h1>我是父组件</h1>
    <ChildComponent :handle-click="methodA" method-name="methodA" />
    <ChildComponent :handle-click="methodB" method-name="methodB" />
  </div>
</template>

<script setup>
import ChildComponent from './components/ChildComponent.vue';

const methodA = (data) => {
  console.log('methodA 被调用:', data);
};

const methodB = (data) => {
  console.log('methodB 被调用:', data);
};

</script>

 子组件

<template>
  <div>
    <button @click="callMethod">点击我,调用父组件的方法</button>
  </div>
</template>

<script setup>
import { defineProps } from 'vue';

const props = defineProps({
  handleClick: {
    type: Function,
    required: true,
  },
  methodName: {
    type: String,
    required: true,
  },
});

function callMethod() {
  props.handleClick("一些子组件的数据")
}

</script>

这结合了后面composition api的内容,但大体是一样的,这里我们做出的效果就是相同的两个组件拥有不同的方法,我们向子组件传入函数,这个用传统方法一直搞不出来,难受。最后只能用composition api来替代了,我有时间再试试。回到正题,我们传入methodA,子组件接收到这个函数,当点击按钮时,就会调用接收的函数。

标签:count,vue,default,counter,父子,props,组件
From: https://blog.csdn.net/ma_no_lo/article/details/141607535

相关文章

  • 【PyQt5 应用程序】PyQt基础组件:按钮
    在任何图形用户界面(GUI)应用程序中,按钮是最基本也是最频繁使用的组件之一。它们是用户与应用程序交互的主要方式之一。在PyQt中,按钮可以通过QPushButton类创建,它提供了丰富的功能,包括显示文本、图像,以及响应点击事件。本节将引导你了解如何在PyQt应用中创建和使用按钮,并通过......
  • 基于ssm+vue党员管理系统设计与实现【开题+程序+论文】
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着信息化技术的飞速发展,传统的手工党员管理模式已难以满足当前复杂多变的党务工作需求。党员作为党组织的基石,其信息的准确性、管理的效率性直接关......
  • 基于ssm+vue法律知识咨询普及系统【开题+程序+论文】
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景在当今社会,随着法治建设的不断推进和公民法律意识的日益增强,法律知识咨询与普及成为了社会发展的重要需求。然而,面对纷繁复杂的法律条文与不断更新的......
  • 基于ssm+vue的校园心理咨询室系统【开题+程序+论文】
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着社会的快速发展与竞争的日益激烈,大学生面临着学业压力、人际关系、职业规划等多重挑战,心理健康问题日益凸显。传统的心理咨询方式受限于时间、地......
  • 基于ssm+vue的宠物领养系统【开题+程序+论文】
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着现代社会生活节奏的加快与人际关系的日益复杂,宠物逐渐成为许多人生活中不可或缺的伙伴,它们不仅能够提供情感慰藉,还能在孤独时给予陪伴。然而,宠物......
  • 基于ssm+vue房屋租赁系统的设计与实现【开题+程序+论文】
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着城市化进程的加速和人口流动性的增强,房屋租赁市场日益繁荣,成为现代都市生活中不可或缺的一部分。然而,传统的房屋租赁方式往往存在信息不对称、流......
  • 基于ssm+vue废品回收管理系统设计与实现【开题+程序+论文】
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着社会的快速发展和人们生活水平的不断提升,垃圾产生量急剧增加,垃圾分类与回收已成为环境保护和可持续发展的关键议题。然而,当前废品回收领域仍面临......
  • 基于ssm+vue宠物店管理系统【开题+程序+论文】
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着宠物经济的蓬勃发展,宠物已成为许多家庭不可或缺的一员,其地位逐渐提升,宠物市场的需求也随之日益增长。宠物店作为宠物产业链中的重要一环,不仅提供......
  • 基于Node.js+vue社区医疗服务系统(程序+论文+开题报告)-计算机毕业设计
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容研究背景随着社会老龄化的加剧和居民健康意识的提升,社区医疗服务作为连接居民与医疗资源的重要桥梁,其重要性与日俱增。然而,当前许多社区医疗服务存在资源分配不均、......
  • 基于Node.js+vue网课视频课设(程序+论文+开题报告)-计算机毕业设计
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容研究背景随着互联网技术的飞速发展,特别是在全球疫情的影响下,线上教育成为了教育领域不可或缺的一部分,网课视频课程以其灵活便捷、资源丰富等优势迅速崛起。然而,当前......