乐趣区

关于前端:vue多层嵌套组件传值

说到 vue 组件传值,大略分为以下几种状况

1. 父传子

父组件通过属性绑定将值传给子组件,子组件通过 props 进行接管

2. 子传父

父组件通过 v -on 监听办法,子组件通过 $emit 触发父组件的办法,将数据作为回调函数的参数传给父组件

3. 兄弟组件传值

通过定义一个 eventBus 通过 on 和 emit 机制来实现事件的绑定和触发,实现数据的流动。当初常见的是用 vuex 来实现数据的共享和流动。

多层嵌套组件传值

问题形容:

除此外,明天遇到一个状况,组件 A,B,C,D, 四个组件之间的关系为嵌套关系,即组件 A > 组件 B > 组件 C > 组件 D, 然而组件 D 中想要触发组件 A 中的办法。

因为一开始的时候没有把设计到的数据放到 vuex 中且是做的公共组件的封装,放在 vuex 外面也不适合。在 vue 的官网上也看了,看到了 inheritAttrs 属性,第一开始没有看明确文档形容的意思,起初在 segmentfault 中看到一篇讲 vue 多层嵌套传值的文章。借助外面的 demo 和 vue 官网,终于如同有点明确多层嵌套传值的意思。

解决思路

一开始也有思考过子组件一层一层的往上 emit, 直到 A 组件监听到这个事件。然而思考到 B 组件和 C 组件作为两头组件并没有用到这个办法,只单纯定义个办法去吧数据 emit 到上一层组件中。每一层组件都须要去实现工夫监听,按情理这个办法也能够实现,然而总感觉办法有点笨,想着把这种办法作为 planB, 先尝试一下,如果找不到适合的解决方案的话,再驳回这个计划。
我想实现的计划简略来说就是 D 能够触发 A 中的办法,然而两头组件不须要帮忙传递。

解决过程

在解决问题之前,首先须要在 vue 官网上理解几个概念

  • inheritAttrs

    默认状况下父作用域的不被认作 props 的 attribute 绑定 (attribute bindings) 将会“回退”且作为一般的 HTML attribute 利用在子组件的根元素上。当撰写包裹一个指标元素或另一个组件的组件时,这可能不会总是合乎预期行为。通过设置 `inheritAttrs` 到 `false`,这些默认行为将会被去掉。而通过 (同样是 2.4 新增的) 实例 property `$attrs` 能够让这些 attribute 失效,且能够通过 `v-bind` 显性的绑定到非根元素上。

      在一开始的时候我读了两遍都没有读懂 inheritAttrs 的形容(理解能力真的略微有点差)。我集体的了解是这样的。
      如果 A 组件外面援用了 B 组件,A 组件是父组件,B 组件是子组件,A 组件给 B 组件传值通过属性绑定,B 组件通过 prop 接管,当然 B 组件必定只会承受本人须要的属性。如果 B 组件不须要 name 属性,然而 A 组件偏偏要传给 B 组件,然而 B 组件并没有在 props 中接管,那么这个值必定是传过来了呀,然而那里去了呢,而后再来读这段话,“父作用域的不被认作 props 的 attribute 绑定 (attribute bindings) 将会“回退”且作为一般的 HTML attribute 利用在子组件的根元素上。”,意思就是 name 属性没有在 props 里承受,就会主动绑定到 B 组件的根组件下来。然而既然 B 组件既然不在 props 中接管他,必定是没有用,那必定不冀望有这样的事件产生,“通过设置 inheritAttrsfalse,这些默认行为将会被去掉。”原来设置为 false 就能够阻止这样的行为。
      回到咱们的需要,组件 B 和组件 C 作为一个两头组件,并不需要接管,就能够设置 inheritAttrs 为 false 即可实现

  • vm.$attrs
    蕴含了父作用域中不作为 prop 被辨认 (且获取) 的 attribute 绑定 (classstyle 除外)。当一个组件没有申明任何 prop 时,这里会蕴含所有父作用域的绑定 (classstyle 除外),并且能够通过 v-bind="$attrs" 传入外部组件——在创立高级别的组件时十分有用。
      父组件传值给子组件,子组件通过 prop 承受了一部分,然而咱们如何能够获取到没有接管的那局部呢,哈哈,就是通过 $attrs。外面蕴含所有父作用域的绑定,划重点!!!, 能够通过 v-bind="$attrs" 传入外部组件
      这样离咱们的需要是不是越来越近了,属性就能够往外部组件传递那事件监听还远吗!!!
  • $listeners
    蕴含了父作用域中的 (不含 .native 润饰器的) v-on 事件监听器。它能够通过 v-on="$listeners" 传入外部组件——在创立更高层次的组件时十分有用。
      是的,没错他来了, 通过 v-on="$listeners" 传入外部组件!!!
      理解完这三个概念,我的问题就迎刃而解。

总结

1. 如果在 D 中想触发 A 中的 handlePreview 办法,首先 A 组件对该办法进行监听
2. 在 B 组件和 C 组件中设置 inheritAttrs 为 false, 不做接管,而后把数据和事件往外部组件接着传(我本次需要只有办法,没有属性,为了加深学习印象就把 v-bind="$alert" 一起传递了)
3. 到了 D 组件中,通过 $emit 触发 A 组件中的办法,顺利完成我的需要。
以下内容为代码片段(vue 语法),大略表述出大略意思。
参考文章链接:vue 多级嵌套组件传参
A 组件

<template>
     <div> A 组件
     <BComponent @handlePreview="preview"</BComponent>
     </div>
 </template>

B 组件

<template>
    <div> B 组件
    <CComponent v-bind="$alert" v-on="$listeners" ></CComponent>
    </div>
</template>
<script>
export default {
 name: 'b-component', 
 inheritAttrs: false
}
</script>

C 组件

<template>
    <div> C 组件
    <DComponent v-bind="$alert" v-on="$listeners" ></CComponent>
    </div>
</template>
<script>
export default {
 name: 'c-component', 
 inheritAttrs: false
}
</script>

D 组件

<template>
    <div> D 组件
    <button @click="handleClick"></button>
    </div>
</template>
<script>
export default {
 name: 'c-component', 
 methods:{handleClick(){this.$emit('handlePreview')
   }
 }
}
</script>
退出移动版