探索Vue组件通信的秘密:打破隔阂,实现数据共享

文章详细介绍了Vue组件间的通信方式,包括父组件向子组件传递数据(props),子组件通过`$emit`触发事件通知父组件,以及单向数据流原则的应用。还讨论了props校验以增强组件的健壮性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、Vue组件通信

  • 每个组件都有自己的数据, 提供在data中, 每个组件的数据是独立的, 组件数据无法互相直接访问 (合理的)
  • 但是如果需要跨组件访问数据, 就需要用到组件通信
    在这里插入图片描述
  • 要是有一万个商品????就要写一万个吗?在这里插入图片描述
  • 函数调用:看起来调用时用一个函数,执行结果效果都是不一样? 设置形参?在调用的时候传入实参?

特别函数:
1、设置组组件内所有特别,形参
2、组件调用的时候,传入所谓的实参?

(一)组件通信—父传子

1. 组件通信 - 父传子 props 传值

  • 父传子的基本语法:
  • ①、父组件通过给子组件加属性传值
<!-- 3.所谓调用函数:传实参 -->
<cpt-4 title="超级好吃的口水鸡" price="50" num="8"></cpt-4>
<cpt-4 title="泰国榴莲" price="288" num="6"></cpt-4>
  • ②、子组件中, 通过props属性接收
props:["title","price","num"]//1. 设置形参,语法固定
  • 创建components/04-cpt.vue子组件文件,子组件中, 通过props属性接收。
<template>
  <div class="box">
    <!-- 2. 使用:形参用到时候,当做变量!类似data初始化内数据变量! -->
    <h3>标题:{{ title }}</h3>
    <p>价格:{{price}}元</p>
    <p>开业大酬宾,全场{{num}}折</p>
  </div>
</template>
<script>
export default {
    // 特别封装:如何设置所谓的形参
    props:["title","price","num"]//1. 设置形参,语法固定
}
</script>
<style scoped>
    .box{
        border:1px solid black;
    }
</style>
  • App.vue父组件里面调用cpt4子组件,父组件通过给子组件加属性传值。
<template>
  <div>
    <h1>超市商品列表:</h1>
    <!-- 3.所谓调用函数:传实参 -->
    <cpt-4 title="超级好吃的口水鸡" price="50" num="8"></cpt-4>
    <cpt-4 title="泰国榴莲" price="288" num="6"></cpt-4>
  </div>
</template>
<script>
import cpt4 from "./components/04-cpt.vue"
export default {
  components:{
    cpt4,
  }
}
</script>

在这里插入图片描述

  • 在data里面传递数据,通过实参来传递形参的值。
<template>
  <div>
    <h1>超市商品列表:</h1>
    <!-- 👇👇👇绑定变量,其中实参名:title和形参的变量名title没有必然的联系 -->
    <cpt-4 :title="title" :price="price" :num="num"></cpt-4>
  </div>
</template>
<script>
import cpt4 from "./components/04-cpt.vue"
export default {
  components:{
    cpt4,
  },
  data(){
    return{
      title:"火鸡面",
      price:10,
      num:5
    }
  }
}
</script>

在这里插入图片描述在这里插入图片描述

  • 利用父传子,可以往子组件传递数据。
  • 父传子的基本步骤是什么?
    父组件内, 给子组件添加属性的方式传值
    子组件内, 通过 props 接收

2. v-for 遍历展示组件练习

  • 以后的数据,都是从后端来的,那如何渲染的呢? 我们可以循环的使用组件吗?要是可以使用,那又如何往组件里面传值呢?
  • 需求: 遍历展示商品列表
  • ①、假定, 发送请求回来的商品数据,
list:[
	{id:1,title:"good-1",price:10,num:8},
	{id:2,title:"good-2",price:88,num:8},
	{id:3,title:"good-3",price:99,num:8},
]
  • ②、v-for 遍历展示
<template>
  <div>
    <h1>超市商品列表:</h1>
    <!-- 商品数据:后台给的list数组 -->
    <cpt-4 v-for="item in list" :key="item.id" :title="item.title" :price="item.price" :num="item.num"></cpt-4>
  </div>
</template>
<script>
import cpt4 from "./components/04-cpt.vue"
export default {
  components:{
    cpt4,
  },
  data(){
    return{
      title:"火鸡面",
      price:10,
      num:5,
      list:[
			{id:1,title:"good-1",price:10,num:8},
			{id:2,title:"good-2",price:88,num:8},
			{id:3,title:"good-3",price:99,num:8},
		]
    }
  }
}
</script>

在这里插入图片描述在这里插入图片描述

3. 单向数据流

在这里插入图片描述

  • 在vue中需要遵循单向数据流原则: (从父到子的单向数据流动, 叫单向数据流)
 在vue中需要遵循单向数据流原则
 1. 父组件的数据发生了改变,子组件会自动跟着变
 2. 子组件不能直接修改父组件传递过来的props  props是只读的
  • 如果父组件传给子组件的是一个对象,子组件修改对象的属性,是不会报错的,,,,也应该避免

(二)组件通信—子传父

  • 创建components/04-cpt.vue子组件文件。
<template>
  <div class="box">
    <!-- 2使用:形参用到时候,当做变量!类似data初始化内数据变量! -->
    <h3>标题:{{ title }}</h3>
    <p>价格:{{price}}元</p>
    <p>开业大酬宾,全场{{num}}折</p>
    <h4>库存:{{ kc }}件</h4>
    <button @click="kc--">卖一件</button>
  </div>
</template>
<script>
export default {
    props:["title","price","num","kc"]//1.设置形参,语法固定
}
</script>
<style scoped>
    .box{
        border:1px solid black;
    }
</style>
  • App.vue父组件里面调用cpt4子组件,父组件通过给子组件加属性传值。
<template>
  <div>
    <h1>超市商品列表:</h1>
    <!-- 商品数据:后台给的list数组 -->
    <p v-for="item in list" :key="item.id" >{{ item.title }} 库存:{{ item.kc }}</p>
    <hr>
    <cpt-4 
      v-for="item in list"  :key="item.id"  :title="item.title"  :price="item.price"  :num="item.num" :kc="item.kc"></cpt-4>
  </div>
</template>
<script>
import cpt4 from "./components/04-cpt.vue";
export default {
  components:{
    cpt4,
    cpt5,
  },
  data(){
    return{
      title:"火鸡面",
      price:10,
      num:5,
      list:[
        {id:1,title:"good-1",price:10,num:8,kc:10,},
        {id:2,title:"good-2",price:88,num:8,kc:33,},
        {id:3,title:"good-3",price:99,num:8,kc:66,},
      ]
    }
  }
}
</script>

在这里插入图片描述

  • 卖一件:
    ①、子组件自己kc- -
    ②、报错:数据是父级给的,如果要修改数据,应该是让父级去修改数据
    规定:子组件不能直接去修改父组件传入的数据!不然会造成数据紊乱!

1. 子传父组件通信

  • 子传父基本语法
  • ①、子组件可以通过 this.$emit('事件名', 参数1, 参数2, ...) 触发事件的同时传参的
  • 创建04-cpt.vue子组件,内置封装好方法emit发射this.$emit("通道名称,要发送的数据,...)
<template>
  <div class="box">
    <h3>标题:{{ title }}</h3>
    <p>价格:{{price}}</p>
    <p>开业大酬宾,全场{{num}}</p>
    <h4>库存:{{ kc }}</h4>
    <button @click="fn">卖一件</button>
  </div>
</template>

<script>
export default {
    // 特别封装:如何设置所谓的形参
    props:["title","price","num","kc","id"],//1.👈👈👈👈设置形参id
    //接受父级给的id、唯一标识、身份证
    //发信号给父级:告诉父级自己是挪个!
    methods:{
        fn(){
            // 👇👇👇👇👇2. 发送信号:内置封装好方法emit发射this.$emit("通道名称,要发送的数据,...)
            this.$emit("aaa",this.id);
        }
    }
}
</script>
<style scoped>
    .box{
        border:1px solid black;
    }
</style>
  • ②、父组件给子组件注册一个自定义事件、父组件可以给子组件设置相应的接受通道名称
<template>
  <div>
    <h1>超市商品列表:</h1>
    <!-- 商品数据:后台给的list数组 -->
    <p v-for="item in list" :key="item.id" >{{ item.title }} 库存:{{ item.kc }}</p>
    <hr>
    <cpt-4 
      v-for="item in list" 
      :key="item.id" 
      :title="item.title" 
      :price="item.price" 
      :num="item.num"
      :kc="item.kc"
      :id="item.id"

      @aaa="fnn"
    ></cpt-4>
    <!-- @aaa="fnn" 3. 接受信号👉👉👉👉👉@通道名称="执行函数"  执行函数(形参){拿到发送过来的数据}-->
  </div>
</template>
  • ③、父组件并提供对应的函数接收参数
<script>
export default {
  methods:{
    fnn(id){
      //<!-- @aaa="fnn" 3. 接受信号👉👉👉👉👉@通道名称="执行函数"  执行函数(形参){拿到发送过来的数据}-->
      console.log(id);
    }
  },
}
</script>
  • App.vue父组件里面调用cpt4子组件,父组件通过给子组件加属性传值。
<template>
  <div>
    <h1>超市商品列表:</h1>
    <!-- 商品数据:后台给的list数组 -->
    <p v-for="item in list" :key="item.id" >{{ item.title }} 库存:{{ item.kc }}</p>
    <hr>
    <cpt-4 
      v-for="item in list" 
      :key="item.id" 
      :title="item.title" 
      :price="item.price" 
      :num="item.num"
      :kc="item.kc"
      :id="item.id"

      @aaa="fnn"
    ></cpt-4>
    <!-- @通道名称="执行函数"  执行函数(形参){拿到发送过来的数据}-->
  </div>
</template>

<script>
import cpt4 from "./components/04-cpt.vue";
export default {
  components:{
    cpt4,
  },
  methods:{
    fnn(id){
      console.log(id);
      //业务:find把符合条件成员单独跳出来,新数组
      let i = this.list.findIndex(ele=>ele.id==id);
      this.list[i].kc--;//找到到对应对象库存-1
    }
  },
  data(){
    return{
      title:"火鸡面",
      price:10,
      num:5,
      list:[
        {id:1,title:"good-1",price:10,num:8,kc:10,},
        {id:2,title:"good-2",price:88,num:8,kc:33,},
        {id:3,title:"good-3",price:99,num:8,kc:66,},
      ]
    }
  }
}
</script>

在这里插入图片描述

2. 形参和实参用同一个地址

  • 创建04-cptPlus.vue文件,形参一会要接受一个对象
<template>
  <div class="box">
    <h3>标题:{{ item.title }}</h3>
    <p>价格:{{item.price}}元</p>
    <p>开业大酬宾,全场{{item.num}}折</p>
    <h4>库存:{{ item.kc }}件</h4>
    <button @click="item.kc--">卖一件</button>
  </div>
</template>
<script>
export default {
      //item:语义化知道,形参一会要接受一个对象
      props:["item"],
}
</script>
<style scoped>
    .box{
        border:1px solid black;
    }
</style>
  • App.vue里面直接调用
<template>
  <div>
    <h1>超市商品列表:</h1>
    <!-- 商品数据:后台给的list数组 -->
    <p v-for="item in list" :key="item.id" >{{ item.title }} 库存:{{ item.kc }}</p>
    <hr>
    <cptPlus-4 
      v-for="item in list" 
      :key="item.id" 
      :item="item"
    ></cptPlus-4>
  </div>
</template>
<script>
import cptPlus4from "./components/04-cptPlus.vue";
export default {
  components:{
    cptPlus4,
  },
  methods:{
    fnn(id){
      //业务:find把符合条件成员单独跳出来,新数组
      let i = this.list.findIndex(ele=>ele.id==id);
      this.list[i].kc--;//找到到对应对象库存-1
    }
  },
  data(){
    return{
      title:"火鸡面",
      price:10,
      num:5,
      list:[
        {id:1,title:"good-1",price:10,num:8,kc:10,},
        {id:2,title:"good-2",price:88,num:8,kc:33,},
        {id:3,title:"good-3",price:99,num:8,kc:66,},
      ]
    }
  }
}
</script>
  • 最后的效果也是一样的。!!!!

(三)props 校验

  • props 是父传子, 传递给子组件的数据, 为了提高 子组件被使用时 的稳定性, 可以进行props校验, 验证传递的数据是否符合要求。
  • 默认的数组形式, 不会进行校验, 如果希望校验, 需要提供对象形式的 props
  • 创建05-cpt.vue子组件,设置形参以及对象配置的要求。
<template>
  <div>
    <h1>数量:{{ num }}</h1>
  </div>
</template>
<script>
export default {
  props:{
    //形参名称:对象配置有要求
    num:{
      type:Number,//数字类型
      require:true,//必传项
      default:100,//默认值
    }
  }
}
</script>
  • App.vue父组件里面调用cpt5子组件,父组件通过给子组件加属性传值。
<template>
  <div>
    <h1>超市商品列表:</h1>
    <cpt-5 num="800"></cpt-5>
  </div>
</template>
<script>
import cpt5 from "./components/05-cpt.vue";
export default {
  components:{
    cpt5,
  },
}
</script>

在这里插入图片描述在这里插入图片描述

  • props 提供了多种数据验证方案,例如:
  • 基础的类型检查 Number
  • 多个可能的类型 [String, Number]
  • 必填项校验 required: true
  • 默认值 default: 100
  • 自定义验证函数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值