首先看在vue官方文档中,对$attrs
和$listeners
的定义
感觉有点难理解,那把它放在实例中看下吧
现有一个场景,有以下的目录结构
正常情况下,在爷组件中的参数,传到父组件,父组件用props进行接收并可以使用,父组件可以继续传给孙组件,孙组件用props进行接收并可以使用,那如果父组件不需要用这个参数,只有孙组件中需要使用,那父组件中写props就显得多余了。
$attrs的用法
先看实例
<!-- desc:功能描述 -->
<template>
<div class="page">
<span>爷页面</span>
<Father :name="name" :gender="gender" :age="age" />
</div>
</template>
<script>
import Father from './component/father.vue'
export default {
name: 'Grandpa',
components: {
Father
},
data () {
return {
name: '张三',
gender: '男',
age: 18,
}
}
}
</script>
在爷组件中,会把三个值传给父组件,这时父组件只需要使用其中一个参数,便用props接收
<template>
<div class="father">
<span>父组件</span>
<div>我儿子的名字是{{ name }}</div>
<Sun :name="name"/>
</div>
</template>
<script>
import Sun from './sun.vue'
export default {
components: {
Sun
},
props: {
name: { type: String, default: '' }
},
data () {
return {
}
}
}
</script>
孙组件也是
<!-- desc:功能描述 -->
<template>
<div class="sun">
<span>孙组件</span>
<div>我的名字是{{ name }}</div>
</div>
</template>
<script>
export default {
name: '',
props: {
name: { type: String, default: '' }
},
data () {
return {}
},
}
</script>
现在是正常用props接收,能回显数据
那$attrs有什么用呢?我们让他显示出来 在父组件中加入
<div>$attrs里的内容是:{{ $attrs }}</div>
从页面上可以看到,$attrs里的内容是上个组件传过来的,并且未被props接收的
看到这里就能解决我们刚开始的场景了,爷组件将数据传给父组件,父组件并不使用,就不需要用props接收,那么我们就可以用v-bind='$attrs'
传给孙组件,孙组件再用props接收就可以了
父组件中
<template>
<div class="father">
<span>父组件</span>
<div>我儿子的名字是{{ name }}</div>
<div>$attrs里的内容是:{{ $attrs }}</div>
<Sun :name="name" v-bind="$attrs" />
</div>
</template>
孙组件中
<!-- desc:功能描述 -->
<template>
<div class="sun">
<span>孙组件</span>
<div>我的名字是: {{ name }}</div>
<div>我的性别是: {{ gender }}</div>
</div>
</template>
<script>
export default {
name: '',
props: {
name: { type: String, default: '' },
gender: { type: String, default: '' }
},
data () {
return {}
},
}
</script>
当然孙组件中也可以通过$attrs.gender去获取到 最终实现祖传孙,如图效果
$listeners的用法
$listeners
是实现孙组件的数据,传到爷组件中,类似于$attrs
,
在父组件中加入 v-on="$listeners"
<template>
<div class="father">
<span>父组件</span>
<div>我儿子的名字是{{ name }}</div>
<div>$attrs里的内容是:{{ $attrs }}</div>
<Sun :name="name" v-bind="$attrs" v-on="$listeners" />
</div>
</template>
孙组件发送数据
<template>
<div class="sun">
<span>孙组件</span>
<div>我的名字是: {{ name }}</div>
<div>我的性别是: {{ gender }}</div>
<el-button type="primary" @click="sendInfo">点击向爷组件传递数据</el-button>
</div>
</template>
<script>
export default {
name: '',
inheritAttrs: false, // 默认会继承在html标签上传递过来的数据,类似href属性的继承
props: {
name: { type: String, default: '' },
gender: { type: String, default: '' }
},
data () {
return {}
},
// 组件方法
methods: {
sendInfo () {
this.$emit('getSun', '这是从孙组件中获得的数据')
}
}
}
</script>
爷组件中接收
<template>
<div class="page">
<span>爷页面</span>
<Father :name="name" :gender="gender" :age="age" @getSun="fromSun" />
<div>从孙组件传来的数据: {{ sunInfo }}</div>
</div>
</template>
<script>
import Father from './component/father.vue'
export default {
name: 'Grandpa',
components: {
Father
},
data () {
return {
name: '张三',
gender: '男',
age: 18,
sunInfo: ''
}
},
// 组件方法
methods: {
fromSun (data) {
console.log(data, 111)
this.sunInfo = data
}
}
}
</script>
最终效果,点击孙组件中的按钮,传递数据,在爷组件中能收到
顺带有一个属性interitAttrs
$attrs一般搭配interitAttrs 一块使用
inheritAttrs一般为false
默认会继承在html标签上传递过来的数据,类似href属性的继承
总结一下,$attrs
和$linteners
都相当于一个桥梁,接通了整个数据的传递,
这在组件的二次封装,或是对深层的组件嵌套来说帮助比较大的,使代码看起来更简洁,再回去看官方的解释就比较好理解啦!