$attrs和$listeners
$attrs:从父组件中接收到的,没有注册到props中的值,传递给子组件使用。如果在props中接收了,也需要传递给子组件,可以使用属性合并v-bind="{ type, ...$attrs }"
$listeners:将子组件的自定义事件传递给父组件
如图所示,A、B、C、D四个组件的关系就是一级一级的父子关系
A组件将x传递给B使用,将y传递给C使用,将z传递给D使用并且B不需要使用y和z,C也不需要使用z,如何实现?
B组件中用props接收x,通过 v-bind="$attrs" 将剩下的y和z传递到C中
C组件中用props接收y,就可以使用y了,同时也可以通过 v-bind="$attrs" 将剩下的z传递到D中
D组件中用props接收z,就可以使用z了
在上面的过程中,如果B中通过 :x='x' 将x传给了C,那么C中也可以通过props接收到x值进行使用,同理,C可以将x传递给D。这就是通过props一层一层往下传就行了,但是如果说A中的数据(z)B、C都不需要使用,只有D需要使用,那么在B、C中不要在props中接收,分别加上 v-bind="$attrs",D中通过props就可以拿到A中的z
那如果要从C传递一个值到A中,怎么操作呢?
在A中定义一个自定义事件用于接收子孙组件传来的值 @refresh="handleRefresh",在C中通过 $emit 去触发 refresh 事件,这显然是不行的
但是在B中加上 v-on="$listeners",那么C就可以触发A中的 refresh 事件了
同理,在C中加上 v-on="$listeners",那么D也可以通过 $emit 触发 refresh 事件
A:
<template> <div class="a"> A组件 <p>x:{{ x }}</p> <p>y:{{ y }}</p> <p>z:{{ z }}</p> <B :x="x" :y="y" :z="z" @refresh="handleRefresh"></B> </div> </template> <script> import B from './B' export default { data() { return { x: 'xxx', y: 'yyy', z: 'zzz' } }, methods: { handleRefresh(data) { console.log('刷新', data) } }, components: { B } } </script> <style lang="less" scoped> .a { width: 700px; height: 700px; background-color: red; } </style>
B:
<template> <div class="b"> B组件 <p>A组件x:{{ x }}</p> <C :x="x" v-bind="$attrs" v-on="$listeners"></C> </div> </template> <script> import C from './C' export default { props: ['x'], components: { C } } </script> <style lang="less" scoped> .b { width: 400px; height: 400px; background-color: gold; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } </style>
C:
<template> <div class="c"> C组件 <p>A组件x:{{ x }}</p> <p>A组件y:{{ y }}</p> <button @click="handleBtn">按钮</button> <D v-bind="$attrs" v-on="$listeners"></D> </div> </template> <script> import D from './D' export default { methods: { handleBtn() { this.$emit('refresh', 'CCC') } }, props: ['x', 'y'], components: { D } } </script> <style lang="less" scoped> .c { width: 250px; height: 250px; background-color: greenyellow; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } </style>
D:
<template> <div class="d"> D组件 <p>A组件z:{{ z }}</p> <button @click="handleBtn">按钮</button> </div> </template> <script> export default { methods: { handleBtn() { this.$emit('refresh', 'DDD') } }, props: ['z'] } </script> <style lang="less" scoped> .d { width: 100px; height: 100px; background-color: deeppink; } </style>