第三种:隔代组件之间的传值
当我们由需求,需要在隔代组件之间进行传值的时候,是不是只需要使用props和$emit一层层地进行传递就好了?是的,这样做完全没有问题,但是vue给我们提供了一种更为优雅的解决方案,那就是$attrs和$listeners,首先我们来看官方API是怎么对这两个属性定义的:

这两个属性的定义 读起来就非常的拗口,但先抓取内容中的关键词,$attrs:不作为prop被识别的特性绑定、传入内部组件;$listener:父作用域中事件监听器、传入内部组件。总结起来就是,从父组件接收属性和方法,传递到内部组件中去。我们来看一下代码是怎样实现的:
grandfather组件(最外层的组件)
<template> <div class="grand-father"> <h2>{{name}}</h2> <p>{{desc}}</p> <p>{{price}}</p> <child :desc="desc" :price="price" @setPrice="setPrice"/> </div></template><script>import child from '@/components/child'export default { name: 'grandfather', components: {child}, data () { return { name: '祖父组件中的名字', desc: '我们将desc和price传递到孙代组件中去,并在孙代节点中修改price的值', price: 10 } }, methods: { setPrice (val) { this.price = val } }}</script><style></style>这里我们将后代组件需要的属性和方法传递到father组件(第一级嵌套组件)中,接下来是father组件的代码
<template> <div> <h4>{{name}}</h4> <son v-bind="$attrs" v-on="$listeners"/> </div></template><script>import son from '@/components/grandson'export default { name: 'father', components: { son }, data () { return { name: '这里是父代节点' } }, methods: {}}</script><style></style>在father组件中,除去props接收到的属性使用v-bind="$attrs"直接打包传递到孙代组件中去,使用v-on="$listener"将定义的方法打包传递到孙代节点中去,这里不需要使用,就是不必要在这里接收,再来看grandson的代码
<template> <div class="son"> <h5>{{name}}</h5> <p>{{$attrs.desc}}</p> <input type="text" @input="changePrice"> </div></template><script>export default { name: 'son', data () { return { name: '这里是孙代节点' } }, methods: { changePrice (e) { this.$emit('setPrice', e.target.value) } }, created () { console.log(this.$attrs) console.log(this.$listeners) }}</script><style></style>在grandson组件(内部组件)中,我们可以使用$attrs接收到所有来自最外层组件所传递的属性,可以使用$emit来调用最外层监听的事件,这样我们就完成了隔代组件之间的通信