Vue2.x 中的a t t r s 和 attrs和attrs和listeners
或许很多Vue小白跟我一样, 在之前不太了解a t t r s 和 attrs和attrs和listenners这两个API是干嘛的, 甚至没有听过或者使用过。下面我来浅述一下我对这两个API的理解。
下文将基于下面这张图片来进行解释,现在我们有三个组件, 组件之间的结构关系如下图所示: A:爷爷组件、B:父亲组件、C:儿子组件
场景: 现在组件的结构如上图所示,我们要实现由A组件到C组件之间的数据通信,有几种实现方式?
像我一样的小白或许刚好学了Props,此时一股脑将所有的属性写在B组件的Props中,这个方案固然可行,但是如果C组件下面还有组件呢?C的子孙千千万,B的Props中的属性也将变成千千万。不得不说B作为父亲的压力是真的大,不仅仅要养活C,还要养活C将来可能存在的千万子孙。这种解决方案无疑给后续的代码维护造成了比较大的阻碍。
或许学完了Props的小伙伴们又说了,那我们是不是可以借助其它工具?例如VueX这样的工具来实现,没错!VueX当然也可以实现以上场景,但是如果C中会用到的属性值很少,那么此时使用VueX来介入这样的问题,是否有点 ‘大动干戈’ 了呢?
能够解决(父→子)通信这类问题的手段有很多,正所谓没有最好的解决方案, 只有更适合的解决方案。在本文中主要踢一下$attrs这个API的使用。
怎么使用$attrs?
在vue2.4中,为了更好的解决上面这类场景的问题,引入了$attrs这一API来帮助咱开发者来解决这个问题。话不多说上代码:
?
<!-- 爷爷组件A -->
<template>
<div>
<my-father :foo="foo"
:bar="bar"
:fatherName="'老王'"
:sonName="'小王'">
</my-father>
</div>
</template>
<script>
import MyFather from "./MyFather.vue";
export default {
components: {
MyFather,
},
data () {
return {
foo: "foo",
bar: "bar",
};
},
};
</script>
<!-- 父亲组件B -->
<template>
<div>
<p>----------------------------</p>
<p>father中的foo:{{ foo }}</p>
<p>father中的attrs: {{ $attrs }}</p>
<my-son v-bind="$attrs"></my-son>
</div>
</template>
<script>
import MySon from "./MySon.vue";
export default {
props: ["foo", "fatherName"],
components: {
MySon,
},
created () {
console.log('father组件中的$attrs:', this.$attrs);
}
};
</script>
<!-- 孙子组件C -->
<template>
<div>
<p>----------------------------</p>
<p>son中的bar:{{ bar }}</p>
<p>son中的$attrs:{{ $attrs }}</p>
</div>
</template>
<script>
export default {
props: ["bar"],
created () {
console.log('son组件中的$attrs:', this.$attrs);
}
};
</script>
页面显示如下:
从上面程序运行的结果, 相信能够看到$attrs的威力了, 它能够让咱们在解决父子通信、爷孙通信这类问题场景的时候更加优雅。毕竟优雅永不过时嘛
$listeners
爷爷 → 孙子 讲完了, 接下来看看咱们如何优雅地解决 爷爷 ← 孙子 的问题。
为什么要用$listenners?
场景: 现在组件之间的结构如最上面的图所示,我们要实现由C组件到A组件之间的数据通信,有几种实现方式?
可以在C组件中使用$emit()方法, 抛出一个事件给B组件, B组件再调用$emit()方法抛给A组件, 像这样一层一层往上传递。在组件关系、组件功能都不复杂的情况下,使用这种方法可以快速完成子组件到父组件之间的通信。
通过VueX来实现父子组件通信
父组件通过ref来调用子组件的方法
?
?
能够解决(父←子)通信这类问题的手段有很多,正所谓没有最好的解决方案, 只有更适合的解决方案。接下来主要踢一下$listenners这个API的使用。
话不多说, 上代码:
<!-- 爷爷组件A -->
<template>
<div>
<my-father :foo="foo" @updateFoo="update" />
</div>
</template>
<script>
import MyFather from "./MyFather.vue";
export default {
components: {
MyFather,
},
data () {
return {
foo: "foo",
};
},
methods: {
update (newValue) {
this.foo = newValue
console.log("update success");
}
}
};
</script>
<!-- 父亲组件B -->
<template>
<div>
<p>father中的foo:{{ foo }}</p>
<my-son v-bind="$attrs" v-on="$listeners" />
</div>
</template>
<script>
import MySon from "./MySon.vue";
export default {
props: ["foo"],
inheritAttrs: false,
components: {
MySon,
},
};
</script>
<!-- 孙子组件C -->
<template>
<div>
<button @click="sonFun">更新foo</button>
</div>
</template>
<script>
export default {
props: ["bar"],
methods: {
sonFun () {
this.$emit("updateFoo", "oof");
console.log("sonFun!!!");
}
}
};
</script>
通过观察我们发现, 由C组件到A组件之间的通信仅用到了一次e m i t ( ) , 这一小小的举动让我们的组件通信变得更加优雅了 , 我们只需要在 B 组件使用 C 组件的地方加上一句 ‘ v ? o n = " emit(), 这一小小的举动让我们的组件通信变得更加优雅了, 我们只需要在B组件使用C组件的地方加上一句`v-on="emit(),这一小小的举动让我们的组件通信变得更加优雅了,我们只需要在B组件使用C组件的地方加上一句‘v?on="listeners"`就可以让A组件监听到C组件抛出的事件。看完本文后是否对$attrs 和 $listenners 有了深刻的认识呢?