$attrs
官网上的类型是{ [key: string]: string },但是我试了下,如果传递是的是个对象也是可以接受到的。所以我认为这个value应该为 any 类型
- 类型:{ [key: string]: any } //{ [key: string]: string }
- 只读
- 详细
- 包含了父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind="$attrs" 传入内部组件——在创建高级别的组件时非常有用。
- 简单来说就是 $attrs 可以获取其父组件接收到的所有除了当前组件 props 里面接受了的props字段 和 class/style 之外的字段
例子:
- 目录结构
这个时候如果 grandson 组件需要获取到 从 app.vue 传递过来的参数,可以使用 $attrs
- 首先在需要向需要接受 $attrs 的组件传递 $attrs 参数(因为是在 children 中引入的 grandson组件,所以在 children组件中给grandson传递参数即可)
<template>
<div class="children">
<div>这是子组件</div>
<grandson v-bind="$attrs"></grandson>
</div>
</template>
<script>
import grandson from './grandson.vue'
export default {
name: 'children',
components: { grandson }
}
</script>
- 在 grandson 中直接使用即可,不需要接受,如果在引入 grandson 组件的时候未绑定,则 $attrs 的值默认为 {}
<template>
<div class="grandson">
<pre>{{ $attrs }}</pre>
</div>
</template>
<script>
export default {
name: 'grandson',
// 这里接受传递过来的参数 prop
props: ['prop']
}
</script>
- 在祖先组件(app.vue)中传递参数
<template>
<div id="app">
<children :text="{a: 1}" :params="2" :prop="3"></children>
</div>
</template>
<script>
import children from './components/children'
export default {
name: 'App',
components: {children}
}
</script>
<style lang="less">
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
.children {
width: 200px;
height: 250px;
border: 1px solid #ccc;
.grandson {
width: 150px;
height: 180px;
border: 1px solid #ccc;
}
}
}
</style>
- 运行项目,结果:
得出结论:可以通过 $attrs 在组件中传递参数给 子孙组件,子孙组件可以通过 $attrs 获取传递给父组件下的子组件的所有非props接受的参数
注意:如果是隔代传递,无法接受。比如:给当前组件新增一个层级,parent 组件。将 parent 组件作为 children 组件的父组件。app 作为 parent 的父组件。如果在 app 中给 parent 传递参数。这个时候 grandson 是无法接受到的
可以看到传递给 $attrs的参数是 { [key: string]: any }。。。。。
$listeners
- 类型 { [key: string]: Function | Array< Function > }
- 只读
- 详细
- 包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件——在创建更高层次的组件时非常有用。
- 简单来说就是这玩意可以向祖先组件 emit 没有带 .native 修饰符的 事件
同一个目录,文件不做修改
例子:
- 还是在 children 组件中给 grandson 组件增加 $listeners 绑定
......
<!-- 给 grandson 组件新增 v-on="$listeners" -->
<grandson v-bind="$attrs" v-on="$listeners"></grandson>
......
- 修改 grandson 组件
<template>
<div class="grandson">
<pre>{{$attrs}}</pre>
<div @click="$emit('grandsonEvent', 'grandson组件被点击')">按钮1</div>
<div @click="$emit('grandsonEventNative', '带有.native修饰符事件触发')">按钮2</div>
</div>
</template>
......
- 在app.vue中接收
<template>
<div id="app">
<children :text="{a: 1}" :params="2" :prop="3" @grandsonEvent="grandsonEvent" @grandsonEventNative.native="grandsonEventNative"></children>
</div>
</template>
<script>
import children from './components/children'
export default {
name: 'App',
components: {children},
methods: {
// 接受来自 grandson 组件传递过来的方法。没有加 .navtive修饰符
grandsonEvent (params) {
alert(params)
},
// 接受来自 grandson 组件传递过来的方法。加了 .navtive修饰符
grandsonEventNative (params) {
alert(params)
}
}
}
</script>
......
- 运行结果
- 点击 按钮1,运行结果:
- 点击 按钮2,页面无反应。增加了 .navtive 修饰符的不会接收到来自非子组件的事件
- 点击 按钮1,运行结果:
所以 $listeners 就是用来 孙组件给 组件组件 emit 事件用的?。。。
如果设置了 $attrs 父组件某个参数,祖先组件也传递一样的参数,那么孙组件接受到的是谁的参数?
- 照原来的例子,对 children 做修改,给 grandson 传递 text 参数
......
<grandson v-bind="$attrs" v-on="$listeners" :text="0"></grandson>
......
-
运行项目,看效果
_ 从app.vue组件传递过来的参数被 children 组件覆盖了_
也就是说 $attrs 接收的时候 是先接受到祖先组件的参数,然后接收父组件的参数,这个时候父组件的参数会覆盖祖先组件的值 -
$listeners 一样。。