vue $attrs $listeners
wangqinquan 人气:0首先让我们看一下这张图,表示了一个多级关联的组件嵌套
为什么要用$attrs
和 $listeners
先让我们来想一种情况,就是组件A跟组件C怎么通信,我们可以有多少中解决方案?
- 看到这种情况,大多数人应该会想到用vuex来进行数据通信吧,但是如果项目中多个组件中的共享状态很少,且项目比较小,全局数据通信也很少,那我们用vuex来实现这个功能,就感觉有点杀鸡用牛刀了
- 我们可以使用组件B来做通信的中转站,当组件A需要把数据传到组件C时,组件A通过props将数据传给组件B,然后组件B再用props传给组件C,这是一种解决方案,但是如果嵌套的组件过多,就会导致代码冗余且繁琐,维护就比较困难,而且如果组件C也要将数据传给组件A,也要一层一层往上传递,就更麻烦了
- 自定义一个Vue数据总线,这种适合组件跨级传递数据,但是缺点是碰到多人合作时,会导致代码的维护性较低,代码可读性也较低
- 还有一种解决方案,就是用provide inject,但是这种方式,官方不推荐,因为这个方法真的是太不好管控了,比如说我在根组件provide了this,孙孙重孙组件去使用了this里面的一个变量,这时候很难去跟踪到这个变量的出处了,而且你也并不知道,项目中哪个组件有用到这个变量,有没有在其他组件中进行改变,所以这个api在项目中很少人使用,但是很多人拿来写组件用
在很多开发情况下,我们只是想把组件A的数据传给组件C,如果用props来进行组件通信的话,虽然可以实现,但是代码可读性上不强,且难维护。
所以这时候,我们的主角$attrs
和 $listeners
就出现了
$attrs
和 $listeners
的用法
在vue2.4中,为了解决该需求,引入了$attrs
和$listeners
, 新增了inheritAttrs
选项。 在版本2.4以前,默认情况下父作用域的不被认作props的属性属性百年孤独,将会“回退”且作为普通的HTML特性应用在子组件的根元素上。如下列的例子
父组件的代码:
<template> <div> <child-dom :foo="foo" :bar="bar"></child-dom> </div> </template> <script> import ChildDom from "../components/attrs/ChildDom.vue"; export default { components: { ChildDom, }, data() { return { foo: "foo", bar: "bar", }; }, }; </script>
子组件的代码:
<template> <div> <p>foo:{{ foo }}</p> </div> </template> <script> export default { props: ["foo"], }; </script>
我们先看一下这样写的时候,控制台打印出来的dom结构是这样的:
在2.4中新增选项inheritAttrs
,inheritAttrs
的默认值为true, 将inheritAttrs
的值设为false, 这些默认的行为会禁止掉。但是通过实例属性 $attrs
,可以将这些特性生效,且可以通过v-bind
绑定到子组件的非根元素上。
将子组件的代码修改一下:
<template> <div> <p>foo:{{ foo }}</p> <p>attrs: {{ $attrs }}</p> <dom-child v-bind="$attrs"></dom-child> </div> </template> <script> import DomChild from "./DomChild.vue"; export default { props: ["foo"], inheritAttrs: false, components: { DomChild, }, }; </script>
然后在加一个孙组件
<template> <div> <p>bar:{{ bar }}</p> </div> </template> <script> export default { props: ["bar"], }; </script>
页面显示如下:
从上面的代码,可以看出使用$attrs
,inheritAttrs
属性能够使用简洁的代码,将组件A的数据传递给 组件C,该场景的使用范围还是挺广的。
那我们现在来看看组件C怎么传值给组件A?
vue2.4版本新增了$listeners
属性,我们在组件B上 绑定 v-on=”$listeners”
, 在组件A中,监听组件C触发的事件。就能把组件C发出的数据,传递给组件A。
修改一下父组件的代码:
<template> <div> <child-dom :foo="foo" :bar="bar" @upFoo="update"></child-dom> </div> </template> <script> import ChildDom from "../components/attrs/ChildDom.vue"; export default { components: { ChildDom, }, data() { return { foo: "foo", bar: "bar", }; }, methods: { update(val) { this.foo = val; console.log("update success"); }, }, }; </script>
子组件代码:
<template> <div> <p>foo:{{ foo }}</p> <p>attrs: {{ $attrs }}</p> <dom-child v-bind="$attrs" v-on="$listeners"></dom-child> </div> </template> <script> import DomChild from "./DomChild.vue"; export default { props: ["foo"], inheritAttrs: false, components: { DomChild, }, }; </script>
孙组件代码:
<template> <div> <p>bar:{{ bar }}</p> <button @click="startUpFoo">我要更新foo</button> </div> </template> <script> export default { props: ["bar"], methods: { startUpFoo() { this.$emit("upFoo", "foooooooooooo"); console.log("startUpFoo"); }, }, }; </script>
运行结果:
现在我们应该清楚了$attrs
,$listerners
,inheritAttrs
的作用了吧
加载全部内容