VUE组件通信

1、介绍

1.1 组件

  • 组件是可复用的VUE实例,带有一个自己的组件名字,组件可以被用来当做自定义元素开使用。
  • 组件有自己独立的作用域,任何数据不会传递到组件里

1.2 组件之间的关系

  • 首先介绍VUE框架思想:通常一个应用会以一棵嵌套的组件树的形式来组织;
  • 如下图,这是VUE官网介绍组件的图;
  • 图中我用红色字母所标出来的:(以A、B、C、E为例)
  • B、C和A, E和C 为父子关系;
  • B和C是兄弟关系
  • A和E是隔代关系
  • 但是免不了组件之间需要传递数据来实现一些功能;
  • 因为组件有自己的独立的作用域,不能直接访问父组件的数据,因此要实现组件之间的通信,需要使用一些特殊方法。

在这里插入图片描述

2、方法一(prop和$emit):

2.1 父传子——使用 v-bind 来动态传递prop

  • 父组件 Parent.vue
  • 引入了两次子组件:
  • 第一次 直接给 hh 属性赋值,将我来啦传递给子组件,hh 是我自己定义的,可以为任意字符,只要和定义的子组件props中的属性名相同就行
  • 第二次 在使用子组件<Child1>的时候,父组件将自己data里的数据title 使用v-bind指令绑定在子组件上;
  • hh可以当做一个属性名,可以为任意值,由你定义;
<template>
  <div>
  	<Child1 hh="我来啦"></Child1>
    <Child1 v-bind:hh="title"></Child1>
  </div>
</template>

<script>
import Child1 from '../BlogComponentCode/Child/Child1'
export default {
  name: "Parent",
  components:{
    Child1
  },
  data(){
    return{
      title: '嘿嘿嘿,我是父组件!'
    }
  }
}
</script>
  • 子组件 Child1.vue
  • hh 数据就是父组件将自己的数据 title 绑定到 hh 属性中,
  • 子组件这边将父组件那边定义的 hh 放进自己的 props 列表中,就可以在页面上使用 hh 数据了
<template>
<div>
  <h2>我是子组件,我收到的值为:{{hh}}</h2>
</div>
</template>

<script>
export default {
  name: "Child1",
  props:['hh']
}
</script>
  • 运行后如下:
  • 引入两次子组件

在这里插入图片描述

2.2 子传父——使用$emit方法

  • 子组件 Child1.vue
  • 子组件的button按钮使用点击事件click,其中使用 `$emit`` 方法第一个参数传入父组件定义的传过来的事件名称,第二个参数为要传给父组件的值
<template>
<div>
  <button v-on:click="$emit('zichuanfu', content)">1111</button>
</div>
</template>

<script>
export default {
  name: "Child1",
  data(){
    return {
      content: '$$$我想吃饭,我来自子组件---'
    }
  }
}
</script>
  • 父组件 Parent.vue
  • 在子组件上定义事件zichuanfu ,通过$event访问到被传出的值,此处将值赋值给num,之后用插值表达式渲染到页面上
  • zichuanfu可以自定义任意值,与子组件对应就行
<template>
  <div>
    <Child1 v-on:zichuanfu="num = $event"></Child1>
    {{num}}
  </div>
</template>

<script>
import Child1 from '../BlogComponentCode/Child/Child1'
export default {
  name: "Parent",
  components:{
    Child1
  },
  data(){
    return{
      num:''
    }
  }
}
</script>
  • 运行点击 1111 按钮为:

在这里插入图片描述

  • 父组件也可以将事件处理函数写成一个方法:
<template>
  <div>
    <Child1 v-on:zichuanfu="getChild"></Child1>
  </div>
</template>

<script>
import Child1 from '../BlogComponentCode/Child/Child1'
export default {
  name: "Parent",
  components:{
    Child1
  },
  methods:{
    getChild(e){
      alert(e);
    }
  }
}
</script>
  • 点击按钮运行为:
    在这里插入图片描述

3、方法二(使用插槽slot传值)

  • 这里不使用已废弃的slot-scope语法
  • 父级模板里的所有内容都是在父级作用域中编译的
  • 子模板里的所有内容都是在子作用域中编译的

3.1 介绍插槽

  • 需要向一个组件传递内容时使用插槽
  • 在子组件中定义插槽,可以显示子组件原本的默认内容。如下:
  • 子组件 Child1.vue
<template>
<div>
  <slot>{{ user.num }}</slot>
</div>
</template>

<script>
export default {
  name: "Child1",
  data(){
    return {
      user: {
        num: 666,
        name: 'ly'
      }
    }
  }
}
</script>
  • 父组件 Parent.vue
<template>
  <div>
    <Child1></Child1>
  </div>
</template>

<script>
import Child1 from '../BlogComponentCode/Child/Child1'
export default {
  name: "Parent",
  components:{
    Child1
  }
}
</script>
  • 因为父组件使用子组件时在模板内没有写任何内容,因此运行显示为子组件的插槽默认内容

  • 运行如下:
    在这里插入图片描述

  • 父组件使用子组件时在模板内编写内容,运行时父组件编写的内容会替换子组件的默认内容

  • 父组件 Parent.vue若这样写(子组件不变):

<template>
  <div>
    <Child1>红红火火恍恍惚惚</Child1>
  </div>
</template>

<script>
import Child1 from '../BlogComponentCode/Child/Child1'
export default {
  name: "Parent",
  components:{
    Child1
  }
}
</script>
  • 运行结果为:
    在这里插入图片描述

3.2 子传父——使用slot传值

  • 但是如果父组件想要显示子组件data数据里user.name呢,因为user.name在子组件的作用域,父组件无法访问,因此需要使用slot来传值给父组件了。
  • 子组件 Child1.vue
  • 要想使父组件能够使用user数据,如下列代码,将user作为slot的属性绑定上去
<template>
<div>
  <slot v-bind:user="user">
  	{{user.num}}
  </slot>
</div>
</template>

<script>
export default {
  name: "Child1",
  data(){
    return {
      user: {
        num: 666,
        name: 'ly'
      }
    }
  }
}
</script>
  • 父组件 Parent.vue
  • 在父组件这里使用v-slot可以定义插槽过来的值的名字,这里我定义为fromChild,可以为任意值。
  • default可以理解为插槽的名字,因为子组件代码里slot没有定义name属性,因此这里为default;如果插槽定义了name属性,则这里的default更改为name的属性值
  • user使用fromChild值可以点出来,可以拿到name值,这样就可以实现在父组件这边将子组件原本的user.num更换为user.name
  • user.name也可以赋值给父组件的data里的值numName,就可以拿过来直接使用了。
<template>
  <div>
    <Child1>
      <template v-slot:default="fromChild">
        {{ numName = fromChild.user.name}}
      </template>
    </Child1>
    <hr>
    {{numName + '888'}}
  </div>
</template>

<script>
import Child1 from '../BlogComponentCode/Child/Child1'
export default {
  name: "Parent",
  components:{
    Child1
  },
  data(){
    return{
      numName:''
    }
  }
}
</script>
  • 运行如下:
    在这里插入图片描述

4、方法三($parent 和 ref)

4.1 子传父——使用ref和 $refs

  • 直接访问一个子组件使用$ref、$refs
  • 注意!!$refs 只会在组件渲染完成之后生效,并且非响应式!(避免在模板或计算属性中使用 $refs)
  • 父组件 Parent.vue
  • 以下为在父组件中直接访问子组件中的data值
  • 在子组件上使用ref属性为子组件设置一个名称ref="child"child可为任意值,
  • 以下代码表示点击button按钮,出弹框显示子组件datauser.name的值
  • 根据设置的名称child获取子组件引用this.$refs.child,接下来可以直接获取子组件的数据或方法了
<template>
  <div>
    <Child1 ref="child"></Child1>
    <button @click="getChildData">dianwo</button>
  </div>
</template>

<script>
import Child1 from '../BlogComponentCode/Child/Child1'
export default {
  name: "Parent",
  components:{
    Child1
  },
  methods:{
    getChildData(){
      alert(this.$refs.child.user.name);
    }
  }
}
</script>
  • 子组件 Child1.vue
<template>
<div>
  <h4>我是子组件</h4>
</div>
</template>

<script>
export default {
  name: "Child1",
  data(){
    return {
      user: {
        num: 666,
        name: 'ly'
      }
    }
  }
}
</script>
  • 点击按钮dianwo运行如下:
    在这里插入图片描述

4.2 父传子——使用$parent

  • 要直接访问父组件,可使用$parent直接访问父组件的实例
  • 子组件 Child1.vue
<template>
<div>
  <div>{{$parent.$data.title}}</div>
</div>
</template>

<script>
export default {
  name: "Child1"
}
</script>
  • 父组件 Parent.vue
<template>
  <div>
    <child1></child1>
  </div>
</template>

<script>
import Child1 from '../BlogComponentCode/Child/Child1'
export default {
  name: "Parent",
  components:{
    Child1
  },
  data(){
    return{
      title: '嘿嘿嘿,我是父组件!'
    }
  }
}
</script>
  • 运行如下:
    在这里插入图片描述

5、方法四(provide 和 inject)

5.1 父传子——使用provide 和 inject

  • 方法三中的$parent有一个明显的缺点,就是不能访问更深层级的实例上,除非this.$parent.$parent...,但是这无疑是非常麻烦的,因此下面介绍新的方法:
  • 首先这个方法用到了两个新的实例选项:provideinject
  • provide可以在父组件上指定需要提供给后代组件的数据或者方法(注意是后代组件)
  • inject 可以在子组件上用来接收provide提供的所需要的数据或者方法
  • !!!此方法非响应式
  • 上代码啦!
  • 父组件 Parent.vue
  • 以下代码中provide选项将此组件的sendName函数title数据提供给后代,注意:provide选项中的getSendNamegetTitle是提供的数据的名称,可以为任意名称
<template>
  <div>
    <child1></child1>
  </div>
</template>

<script>
import Child1 from '../BlogComponentCode/Child/Child1'
export default {
  name: "Parent",
  components:{
    Child1
  },
  data(){
    return{
      title: '嘿嘿嘿,我是父组件!'
    }
  },
  provide: function(){
    return {
      getSendName: this.sendName,
      getTitle: this.title
    }
  },
  methods:{
    sendName(){
      alert("11111");
    }
  }
}
</script>
  • 子组件 Child1.vue
  • 使用inject引入祖先组件中提供的provide中此组件所需的数据,就可以直接使用了
<template>
<div>
  <button @click="getSendName">{{getTitle}}</button>
</div>
</template>

<script>
export default {
  name: "Child1",
  inject: ['getSendName', 'getTitle']
}
</script>
  • 运行如下
    在这里插入图片描述

欢迎补充和交流!

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值