vue实例属性-$attrs和$listeners

$attrs属性

$attrs包含了父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind="$attrs" 传入内部组件——在创建高级别的组件时非常有用。

说白了$attrs就是能获取父组件除了props传入的所有的属性(除了class和style属性)

基本使用

父组件

 1 <template>
 2   <div>
 3       <div class="parent">
 4       父组件
 5       <Child style='color:green' :name="name" :sex="sex" :age="age" :height='height'></Child>
 6       </div>
 7   </div>
 8 </template>
 9 
10 <script>
11 import Child from './components/Child.vue'
12 
13   export default {
14     components:{
15       Child
16     },
17     data(){
18       return {
19         name:'父亲',
20         age:50,
21         sex:'男',
22         height:180
23       }
24     }
25   }
26 </script>
27 
28 <style  scoped>
29 .parent{
30   width: 200px;
31   height: 300px;
32   padding: 0 50px;
33   background: blue;
34 }
35 </style>

子组件

 1 <template>
 2     <div>
 3         <div class="child">
 4         子组件接收到的属性{{name}}
 5         </div>
 6     </div>
 7 </template>
 8 
 9 <script>
10     export default {
11         props:['name'],
12         created(){      //页面的初始化生命周期
13             console.log(this.$attrs)
14         }
15     }
16 </script>
17 
18 <style scoped>
19 .child{
20     width: 200px;
21     height: 200px;
22     background: orange;
23 }
24 </style>

我们可以看到浏览器输出为

 

 

 

如果组件的级别更深入?除了有子组件,还有孙子组件,重孙子组件,如何传递属性?

使用$attrs去进行传递

子组件传递给孙子组件

我们再看此时的子组件

 1 <template>
 2     <div>
 3         <div class="child">
 4         子组件接收到的属性{{name}}
 5         <GrandSon v-bind="$attrs"></GrandSon>
 6         </div>
 7     </div>
 8 </template>
 9 
10 <script>
11 import GrandSon from "./GrandSon.vue"
12     export default {
13         components:{
14             GrandSon
15         },
16         props:['name'],
17         created(){
18             console.log(this.$attrs)
19         }
20     }
21 </script>
22 
23 <style scoped>
24 .child{
25     width: 200px;
26     height: 200px;
27     background: orange;
28 }
29 </style>

孙子组件

 1 <template>
 2     <div>
 3         <div class="grandson">
 4         孙子组件
 5         </div>
 6     </div>
 7 </template>
 8 
 9 <script>
10 
11     export default {
12         created(){
13             console.log('孙子组件',this.$attrs)
14         }
15     }
16 </script>
17 
18 <style scoped>
19 .grandson{
20     width: 100px;
21     height: 100px;
22     background: red;
23 }
24 </style>

此时浏览器显示

 

 

$attrs传递的是父组件的非props属性

 

 如果此时子组件也传值,孙子组件也会照样接受并输出

 1 <template>
 2     <div>
 3         <div class="child">
 4         子组件接收到的属性{{name}}
 5         <GrandSon v-bind="$attrs" :cName="cName" :csex="csex" :cage="cage" ></GrandSon>
 6         </div>
 7     </div>
 8 </template>
 9 
10 <script>
11 import GrandSon from "./GrandSon.vue"
12     export default {
13         components:{
14             GrandSon
15         },
16         data(){
17             return{
18                 cName:"儿子",
19                 csex:"男",
20                 cage:18,
21                 
22             }
23         },
24         props:['name'],
25         created(){
26             console.log(this.$attrs)
27         }
28     }
29 </script>
30 
31 <style scoped>
32 .child{
33     width: 200px;
34     height: 200px;
35     background: orange;
36 }
37 </style>

 

 

$attrs属性如果父组件和爷爷组件都传了同一个属性,此时孙子组件得到的$attrs属性是父组件的,优先级就是就近祖先元素的属性

此时父组件也传了一个height

子组件

1  <GrandSon v-bind="$attrs" :cName="cName" :csex="csex" :cage="cage" :height="height"></GrandSon>
1    data(){
2             return{
3                 cName:"儿子",
4                 csex:"男",
5                 cage:18,
6                 height:175
7             }
8         },

父组件

1 data(){
2       return {
3         name:'父亲',
4         age:50,
5         sex:'男',
6         height:180
7       }
8     }

 

$listeners属性

 $listeners包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件——在创建更高层次的组件时非常有用。

就是子组件可以接收到父组件的(非.native修饰符)的事件监听

我们看一下.native修饰符

 1 <template>
 2   <div>
 3       <div class="parent">
 4       父组件
 5       <Child @click="handler"></Child>
 6       </div>
 7   </div>
 8 </template>
 9 
10 <script>
11 import Child from './components/Child.vue'
12 
13   export default {
14     components:{
15       Child
16     },
17     methods:{
18       handler(){
19         console.log(123)
20       }
21     }
22   }
23 </script>
24 
25 <style  scoped>
26 .parent{
27   width: 200px;
28   height: 300px;
29   padding: 0 50px;
30   background: blue;
31 }
32 </style>

我们在组件身上添加了一个普通的click事件监听,此时这个事件监听点击后没有生效,因为原生的事件监听在组件上是默认不生效的,如果希望原生的事件监听在组件上生效,使用.native修饰符

 

 此时我们添加.native修饰符,就可以实现监听

1 <Child @click.native="handler"></Child>

 

 

回到主题

此时我们给父组件设置了两个事件

 1 <template>
 2   <div>
 3       <div class="parent">
 4       父组件{{a}}
 5       <Child @click.native="handler" @add="add"></Child>
 6       </div>
 7   </div>
 8 </template>
 9 
10 <script>
11 import Child from './components/Child.vue'
12 
13   export default {
14     components:{
15       Child
16     },
17     data(){
18       return {
19         a:100
20       }
21     },
22     methods:{
23       handler(){
24         console.log(123)
25       },
26       add(){
27         this.a++
28       }
29     }
30   }
31 </script>
32 
33 <style  scoped>
34 .parent{
35   width: 200px;
36   height: 300px;
37   padding: 0 50px;
38   background: blue;
39   color: white;
40 }
41 </style>

此时我们在浏览器中可以看到得到的是父组件非.native修饰符的事件,当我们把.native修饰符去掉之后就可以看到两个事件都输出了

1   <Child @click="handler" @add="add"></Child>

 

 

 

和$attrs一样,可以继续向下传递事件,比如child组件要向GrandSon组件传递App组件的事件监听

通过v-on将$listeners传递下去

我们子组件

 1 <template>
 2     <div>
 3         <div class="child">
 4         子组件<button @click="add">按我让父组件加一</button>
 5 <GrandSon v-on="$listeners"></GrandSon>
 6         </div>
 7     </div>
 8 </template>
 9 
10 <script>
11 import GrandSon from "./GrandSon.vue"
12     export default {  
13         components:{
14             GrandSon
15         } , 
16         data(){
17             return{
18               
19             }
20         },
21         props:['name'],
22         created(){
23             console.log(this.$listeners)
24         },
25         methods:{
26 add(){
27     this.$emit('click')
28 }
29         }
30     }
31 </script>
32 
33 <style scoped>
34 .child{
35     width: 200px;
36     height: 200px;
37     background: orange;
38 }
39 </style>

孙子组件

 1 <template>
 2     <div>
 3         <div class="grandson">
 4         孙子组件
 5         </div>
 6     </div>
 7 </template>
 8 
 9 <script>
10 
11     export default {
12         created(){
13             console.log('孙子组件',this.$listeners)
14         }
15     }
16 </script>
17 
18 <style scoped>
19 .grandson{
20     width: 100px;
21     height: 100px;
22     background: red;
23 }
24 </style>

 

 

 

我们看下面的案例

孙子组件

 1 <template>
 2     <div>
 3         <div class="grandson">
 4         孙子组件
 5         <button @click="sum">按我向父组件传递数据</button>
 6         </div>
 7     </div>
 8 </template>
 9 
10 <script>
11 
12     export default {
13         created(){
14             console.log('孙子组件',this.$listeners)
15         },
16         methods:{
17 sum(){
18     this.$emit("sum")
19 }
20         }
21     }
22 </script>
23 
24 <style scoped>
25 .grandson{
26     width: 100px;
27     height: 100px;
28     background: red;
29 }
30 </style>

子组件

 1 <template>
 2     <div>
 3         <div class="child">
 4         子组件<button @click="add">按我让父组件加一</button>{{b}}
 5 <GrandSon v-on="$listeners" @sum="sum"></GrandSon>
 6         </div>
 7     </div>
 8 </template>
 9 
10 <script>
11 import GrandSon from "./GrandSon.vue"
12     export default {  
13         components:{
14             GrandSon
15         } , 
16         data(){
17             return{
18               b:100
19             }
20         },
21         props:['name'],
22         created(){
23             console.log(this.$listeners)
24         },
25         methods:{
26 add(){
27     this.$emit('add')
28 },
29 sum(){
30     this.b++
31 }
32         }
33     }
34 </script>
35 
36 <style scoped>
37 .child{
38     width: 200px;
39     height: 200px;
40     background: orange;
41 }
42 </style>

我们看此时的浏览器,

 

 

更高级别的依次通过此方法传递

$listeners获取的是祖先组件的绑定到后代组件的事件监听,比如App组件设置了add事件,child组件设置了sum事件,此时Grandson能够通过$listeners获取add和sum两个事件

 

posted @ 2021-09-16 11:46  keyeking  阅读(610)  评论(0编辑  收藏  举报