Vue祖孙组件如何实现传值

目录
  • 先看基础
    • $props
    • $attrs
    • $listeners
  • 祖传孙
    • 1. $props 链
    • 2. $attrs
  • 孙传祖
    • $listeners
  • 总结

先看基础

祖孙组件,也就是 3 层嵌套的组件。关于 vue 中父子组件之间的数据传递是通过 props$emit 实现,参考 Vue 父子组件传值。

那祖孙组件之间传值怎么实现,先了解下面的几个 vue 属性。

$props

当前组件接收到的 props 对象。Vue 实例代理了对其 props 对象 property 的访问。

$attrs

$attrs 是一个 Object,它包含了父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定 (classstyle 除外)。

如果组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (classstyle 除外),并且可以通过 v-bind="$attrs" 传入内部组件。

怎么理解呢?

就是父组件绑定到子组件上的属性,在子组件中没有声明 props 进行接收的那些属性会被包含在 attrs 中,举个栗子

在父组件中对子组件绑定了两个属性 data1 data2

parent.vue

<Child :data1="data1" :data2="data2" />

<script>
import Child from './child'
...
data(){
  return{
    data1: 'String',
    data2: ['String','Array']
  }
}
...
</script>

但在子组件的 props 只对 data1 做了接收声明,那 data2 就会被包含在 $attrs 中。

在子组件中也是可以取到 $attrs 的值的,既然是对象,那就还可以按照属性名来取值的。

child.vue

<template>
  <div>
    <div>$attrs: {{ $attrs }}</div>
    <div>data2: {{ $attrs['data2'] }}</div>
  </div>
</template>
<script>
...
props: ['data1'], /* <--看这里,只对data1做接收声明 */
data(){
  return{...}
}
...
</script>

其实到这里还没有结束,接着聊聊 inheritAttrs 吧。不过这和传值之间关系不大。

inheritAttrsvue 2.4.0 的新增选项,官方的介绍是酱紫的。

1️⃣ 默认情况下父作用域的不被认作 propsattribute 绑定 (attribute bindings) 将会“回退”且作为普通的 HTML attribute 应用在子组件的根元素上。当撰写包裹一个目标元素或另一个组件的组件时,这可能不会总是符合预期行为。通过设置 inheritAttrsfalse,这些默认行为将会被去掉。

2️⃣ 而通过 (同样是 2.4 新增的) 实例 property $attrs 可以让这些 attribute 生效,且可以通过 v-bind 显性的绑定到非根元素上。

注意:这个选项不影响 classstyle 绑定。

第1️⃣简单理解就是前面说的,在子组件中的 props 没有声明接收的属性(也就是 $attrs 所包含的属性)会被绑定到这个子组件的 HTML 根节点上,我们检查代码也是可以看到的。

就像下面的例子,来自父组件的消息没有被接收时会作为属性被渲染到子组件的根节点上。

然后是使用 inheritAttrs: false 可以避免被渲染。

第2️⃣说的就是可以通过 v-bind="$attrs" 把这些属性绑定到其他的节点上(包括子节点,这是祖孙组件传值的技术基础)

$listeners

vue 2.4.0 新增

$listeners 是个 Object。包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件。

祖传孙

vue 中,祖孙组件之间是不能直接通信的,需要通过父组件作为 中间组件

实际上祖父的关系就是两个 父与子 的关系。

1. $props 链

【不推荐使用】

既然是两个父与子之间的关系,那就可以 祖传父 再由 父传子。而 props 可以用来接收来自父组件的值,那就可以通过 props 实现链式传递了。不举栗子了,举个香蕉吧。

传递次序:GrandFather → Father → GrandSon

GrandFather 中给 Father 传递了两条消息。

GrandFather.vue

<template>
  <div class="parent">
    爷爷
    <Father :msg1="msg1" :msg2="msg2" />
  </div>
</template>

<script>
import Father from './Father'
export default {
  components: {Father},
  data () {
    return {
      msg1: '1️⃣我是GrandFather,把第二条传给GrandSon',
      msg2: '2️⃣GrandSon你好,我是GrandFather'
    }
  }
}
</script>

Father 中使用 props 接收了来自 GrandFather 的所有消息。是的,他把所有的消息都收下了而且还可以随便看。

当然,使用 props 链传递就必须要 Father 接收之后才能继续传递。

看完消息之后,Father 按照 GrandFather 的意思,把 msg2 传递给了 GrandSon

Father.vue

<template>
  <div class="parent">
    父亲
    <p>GrandFather说:{{msg1}}。{{msg2}}</p>
    <GrandSon :msg2="msg2" />
  </div>
</template>

<script>
import GrandSon from './GrandSon'
export default {
  props: ['msg1', 'msg2'],
  components: {GrandSon},
}
</script>

终于到 GrandSon 了,它通过 propsFather 那里接收到了来自 GrandFather 的消息。

GrandSon.vue

<template>
<div class="child">
  孙子
  <p>GrandFather说:{{msg2}}</p>
</div>
</template>

<script>
export default {
  props: ['msg2']
}
</script>

小结

这种方式虽然是比较容易理解,但也是比较繁琐的。中间组件需要接收所有的 props 等。

2. $attrs

上面的 $props 传值方式必须要经过 Father 接收之后继续传递,也是个缺点,毕竟 Father 还是很忙的,要负责自己的功能,不能总为爷孙俩接传消息。

vue2.4.0 版本中新增了 $attrs 属性。根据前面的理解 $attrs 就是没有在 props 中声明要接收的一些属性。此外,还可以通过 v-bind="$attrs" 把来自父组件的一些属性直接传递到子组件中。

这样一来,Father 组件就没必要在 props 中声明接收那些不必要属性了。看看实例吧!

GrandFather 组件不用做修改

这次在 Father 中只在 props 接收了 msg1,与自己无关的直接使用 v-bind="attrs" 绑定到子组件上。

当然,在 Father 中还是可以访问 $attrs 的。在代码中访问要使用 this.$attrs

Father.vue

<template>
  <div class="parent">
    父亲
    <p>$attrs:{{$attrs}}</p>
    <GrandSon v-bind="$attrs" />
  </div>
</template>

<script>
import GrandSon from './GrandSon'
export default {
  props: ['msg1'], //只接收了msg1
  components: {GrandSon},
}
</script>

子组件也不需要做修改

Father 中接收了 msg1,所以在 Father 中继续传递到 GrandSon 的就只有 msg2 了。

孙传祖

$listeners

Father 组件绑定 自定义事件 getReply ,便于后面在 GrandSon 中触发

GrandFather.vue

<template>
  <div class="parent">
    爷爷
    <div>GrandSon的回复:{{reply}}</div>
    <Father :msg1="msg1" :msg2="msg2" @getReply="getReply"/>
  </div>
</template>

<script>
import Father from './Father'
export default {
  components: {Father},
  data () {
    return {
      msg1: '1️⃣我是GrandFather,把第二条传给GrandSon',
      msg2: '2️⃣GrandSon你好,我是GrandFather',
      reply: '' //接收来自GrandSon的消息
    }
  },
  methods: {
    /* 将获得的数据绑定到data中,便于视图层渲染 */
    getReply (param) {
      this.reply = param
    }
  }
}
</script>

Father 中使用 v-on="$listeners"GrandFather 的事件绑定到 GrandSon

Father.vue

<template>
  <div class="parent">
    父亲
    <p>$attrs:{{$attrs}}</p>
    <GrandSon v-bind="$attrs" v-on="$listeners" />
  </div>
</template>

<script>
import GrandSon from './GrandSon'
export default {
  props: ['msg1'],
  components: { GrandSon },
}
</script>

GrandSon 中触发来自 GrandFather 的自定义事件就 了,有两种方式。

this.$listeners.eventName(param)

this.$emit(eventName, param)

GrandSon.vue

<template>
<div class="child">
  孙子
  <p>GrandFather说:{{msg2}}</p>
  <button @click="reply">回复GrandFather</button>
</div>
</template>

<script>
export default {
  props: ['msg2'],
  data () {
    return {
      replyWord: 'GrandFather你好,我是GrandSon,收到消息了'
    }
  },
  methods: {
    reply () {
      this.$emit('getReply', this.replyWord)
      // this.$listeners.getReply(this.replyWord)
    }
  }
}
</script>

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • vue组件间的通信,子组件向父组件传值的方式汇总

    目录 一.子组件通过this.$emit()的方式将值传递给父组件 二.通过vuex来传递组件间的数据 三.通过中央总线来传递组件间的数据 四.通过修改父组件传过来的对象属性 五.父组件使用子组件的引用ref 总结 写vue,如果页面涉及到多个组件,就会涉及组件之间的通信,可能是父子组件间的通信,也可以是同级组件间的通信,那么,vue里面的组件如何通信. 一般来说在vue的数据传递是在父组件传子组件通过属性来传,子组件传父组件通过事件来传值. 子组件通过通过this.$emit()的方式将值传递

  • Vue实现的父组件向子组件传值功能示例

    本文实例讲述了Vue实现的父组件向子组件传值功能.分享给大家供大家参考,具体如下: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Vue 父组件向子组件传值</title> <script src="https://cdn.bootcss.com/vue/2.2.2/vue.min.js"></scrip

  • vue祖孙组件之间的数据传递案例

    **解决的问题:** 使用$attrs和$listeners实现祖孙组件之间的数据传递,也就是多重嵌套组件之间的数据传递. **注意:** 本方法针对vue2.4版本及以上,使用$attrs和$listeners来实现的 **解决方案:** **首先创建父组件:** 父组件用于动态数据的绑定与事件的定义 <template> <div> <!--这里 :one和:two是向后代组件传递数据--> <child1 :one="child1" :t

  • Vue父子组件双向绑定传值的实现方法

    父子组件之间的双向绑定非常简单,但是很多人因为是从Vue 2+开始使用的,可能不知道如何双向绑定,当然最简单的双向绑定(单文件中)就是表单元素的 v-model 了,例如 <input type="text" /> 它会响应表单元素的 value 属性,当输入框文本改变时,会将 value 值传给 v-model 所绑定的变量,如果同时设置 v-model 和 value , value 属性无效. 父子组件的自定义双向 v-model 当若干dom封装成组件时,在父组件中

  • vue父子组件的互相传值和调用

    1.父传值给子组件 父组件: <template> <div> <p class="father">父组件</p> <child :sid="id"></child> </div> </template> <script> import child from './child' export default { components: { child }, d

  • vue中组件之间相互通信传值的几种方法详解

    目录 vue中组件之间相互通讯传值的方式 1.子组件和父组件通讯,通过调用父组件给组件自定义属性值来实现 2.父组件主动获取子组件数据 3.使用provide/inject方法实现 4.使用事件总线 5.vuex\localStorage\sessionStorage 总结 vue中组件之间相互通讯传值的方式 我们在使用vue进行项目开发的时候为了更好地管理项目,我们会把每个功能封装成一个个的组件,在使用的时候直接引入并且调用组件来实现代码的复用. 我们在封装组件的时候经常会留有一些预留的接口,

  • 浅谈Vue父子组件和非父子组件传值问题

    本文介绍了浅谈Vue父子组件和非父子组件传值问题,分享给大家,具体如下: 1.如何创建组件 1.新建一个组件,如:在goods文件夹下新建goodsList.vue <template> <div class='tmpl'> goodsList组件 </div> </template> <style> </style> <script> export default { data() { return{} }, creat

  • Vue.js中兄弟组件之间互相传值实例

    兄弟组件之间互相传值,需要建立一个"中转站"(新的vue实例),并且需要主动触发. 实例上的$on方法来接受监听. <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>组件传值</title> <script src="vue.js"></script

  • 图文介绍Vue父组件向子组件传值

    1:在src/components/child/文件夹下,创建一个名为:child.vue的子组件 2:在父组件中,设置好需要传递的数据 3:在App.vue中引入并注册子组件 4:通过v-bind属性绑定并赋值给子组件 5:子组件通过 props 接收父组件传递过的数据 6:查看 7:总结: 子组件在props中创建一个属性,用以接收父组件传过来的值父组件中注册子组件在子组件标签中添加子组件props中创建的属性把需要传给子组件的值赋给该属性 您可能感兴趣的文章: VUEJS 2.0 子组件访

  • vue 子组件向父组件传值方法

    子组件注册触发事件,父组件注册 触发子组件事件后的方法写在method里面 父组件这么写 <component-a v-on:child-say="listenToMyBoy"></component-a> <p>Do you like me? {{childWords}}</p> methods: { listenToMyBoy: function (somedata){ this.childWords = somedata } } 子

  • vue 进阶之实现父子组件间的传值

    本章我们将深入了解一下组件,并实现父子组件间的传值. <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>vue</title> <script src="https://cdn.jsdelivr.net/npm/vue"></script> </head&g

  • vue实现组件之间传值功能示例

    本文实例讲述了vue实现组件之间传值功能.分享给大家供大家参考,具体如下: slot标签: 想向封装好结构的组件中插入内容,需要借助<slot></slot> 在组件之中进行关联:如 模板中: <slot name='txt'></slot> 组件调用中: <p slot='txt'></p> 注:如果只有slot上面每一定义name属性,则只能有一个slot <div class='box'> <com> &

随机推荐