Vue 中 $attrs 与 $listeners

我们知道,向子组件传递数据,是通过 v-bind 子类组件定义的 props 属性完成的,这只适用于单向、两层组件之间。同样地,事件传递也是在父组件中用 v-on 给子组件绑定事件,然后在子组件中通过 this.$emit 触发的、以达到修改父组件数据的目的。

那么,在多层嵌套组件中,顶层组件和最底层组件之间如何进行数据传递和事件触发呢?比如,A 组件引用了 B 组件,而 B 组件又引用了 C 组件,那么怎么在 A 中将数据传给 C ;在 C 中,怎么触发 A 中的方法呢?这就是 $attrs$listeners 的作用了。

1.$attrs

继承所有的父组件属性(没有通过 props 接收的属性还有 class 类名 和 style 样式 )。

javascript 复制代码
// parent.vue
<m-child :data-status="dataStatus" :data-message="dataMessage"></m-child>

export default {
	data(){
		return {
			dataStatus: '123',
			dataMessage: '456'
		}
	}
}
// m-child.vue
<m-grandron v-bind="$attrs" data-message="789"></m-grandron>
export default {
	props:{
		dataStatus: String,
	},
	created(){
		console.log('dataStatus',this.dataStatus)  //  123
		console.log('dataMessage',this.dataStatus)  //  456
	}
}
// m-grandron.vue
export default {
	created(){
		console.log('dataStatus',this.$attrs)  
// 因为child组件中props声名了dataStatus所以这里$attrs就不含有dataStatus
// 因为传的dataMessage和$attrs内同名,所以值被覆盖变为789 
	}
}

如果我们按常规的props传值,就要一层一层传,层级多了就很恶心,使用$attrs就很轻松的做到了。

2.$listeners

它是一个对象,能接收所有的方法绑定,里面包含了作用在这个组件上的所有监听器,配合 v-on="$listeners" 将所有的事件监听器指向这个组件的某个特定的子元素。

有一点不同的是:当出现同名的事件时,不会被覆盖,而是都会执行,执行顺序就是事件冒泡的执行顺序,先触发child 再触发parent\

typescript 复制代码
// parent.vue
<m-child @customEvent="ev_customEvent"></m-child>

export default {
	data(){
		return {
			dataStatus: '123',
			dataMessage: '456'
		}
	},
	methods:{
		ev_customEvent(){
			console.log('my name is parent!')
		}
	}
}
// m-child.vue
<m-grandron v-on="$listeners" @customEvent="ev_customEvent"></m-grandron>
export default {
	props:{
		dataStatus: String,
	},
	data(){
		return {}
	},
	methods:{
		ev_customEvent(){
			console.log('my name is child!')
		}
	}
}
// m-grandron.vue
<button @click="$emit('customEvent')">click me!</button>
export default {
	data(){
		return {}
	},
}


// 控制台
// my name is child!
// my name is parent!

使用$listeners 属性可以很方便的在层级很深的组件内,立马就修改最外层的父组件内的属性值

注意:在vue3.0 中$listeners被移除了,将所有属性都集合到attrs里面了

相关推荐
swipe2 分钟前
纯函数、柯里化与函数组合:从原理到源码,构建更可维护的前端代码体系
前端·javascript·面试
远山枫谷3 分钟前
uniapp + Vue 自定义组件封装:自定义样式从入门到实战
前端·vue.js
Lee川7 分钟前
JavaScript 中的 `this` 与变量查找:一场关于“身份”与“作用域”的深度博弈
前端·javascript·面试
Kakarotto2 小时前
Canvas 直线点击事件处理优化
javascript·vue.js·canvas
顺遂2 小时前
基于Rokid CXR-M SDK的引导式作业辅导系统设计与实现
前端
代码搬运媛2 小时前
Generator 迭代器协议 & co 库底层原理+实战
前端
前端拿破轮3 小时前
从0到1搭建个人网站(三):用 Cloudflare R2 + PicGo 搭建高速图床
前端·后端·面试
功能啥都不会3 小时前
PM2 使用指南 - 踩坑记录
前端
HelloReader3 小时前
React 中 useState、useEffect、useRef 的区别与使用场景详解,终于有人讲明白了
前端
兆子龙3 小时前
CSS 里的「if」:@media、@supports 与即将到来的 @when/@else
前端