父子组件通信
- 子组件是不能引用父组件或者Vue实例的数据的。
- 但是,在开发中,往往一些数据确实需要从上层传递到下层:
- 比如在一个页面中,我们从服务器请求到了很多的数据。
- 其中一部分数据,并非是我们整个页面的大组件来展示的,而是需要下面的子组件进行展示。
- 这个时候,并不会让子组件再次发送一个网络请求,而是直接让大组件(父组件)将数据传递给小组件(子组件)。
如何进行父子组件间的通信呢?Vue官方提到- 通过props向子组件传递数据
- 通过事件向父组件发送消息
父组件向子组件传递函数(props)
props的值有两种方式:
- 方式一:字符串数组,数组中的字符串就是传递时的名称。
- 方式二:对象,对象可以设置传递时的类型,也可以设置默认值等
- 具体下面代码展示
<body>
<div id="app">
<cpn :cmessage="message" :cmovies="movies"></cpn>
</div>
<template id="cpn">
<div>
<ul>
<li v-for="item in cmovies">{{item}}</li>
</ul>
<h2>{{cmessage}}</h2>
</div>
</template>
<script src="../vue.js"></script>
<script>
// 父传子:props
const cpn = {
template: "#cpn",
props: {
//1.类型限制
// 2.提供一些默认值,以及必传值
cmovies: {
type: Array,
default() {
return [];
},
},
cmessage: {
type: String,
default: "aaaaaa",
required: true,
},
},
};
const app = new Vue({
el: "#app",
data: {
message: "你好啊",
movies: ["你好", "海贼王", "悲伤逆流成河"],
},
components: {
cpn,
},
});
</script>
</body>
props数据验证
在前面,我们的props选项是使用一个数组。
我们说过,除了数组之外,我们也可以使用对象,当需要对props进行类型等验证时,就需要对象写法了。
验证都支持哪些数据类型呢?
String
Number
Boolean
Array
Object
Date
Function
Symbol
当我们有自定义构造函数时,验证也支持自定义的类型
子组件向父组件传递($emit)
props用于父组件向子组件传递数据,还有一种比较常见的是子组件传递数据或事件到父组件中。
我们应该如何处理呢?这个时候,我们需要使用自定义事件来完成。
什么时候需要自定义事件呢?
- 当子组件需要向父组件传递数据时,就要用到自定义事件了。
- 我们之前学习的v-on不仅仅可以用于监听DOM事件,也可以用于组件间的自定义事件。
自定义事件的流程:- 在子组件中,通过$emit()来触发事件。
- 在父组件中,通过v-on来监听子组件事件。
- 我们来看一个简单的例子:
- 两个按钮+1和-1,点击后修改counter。
- 我们整个操作的过程还是在子组件中完成,但是之后的展示交给父组件。
这样,我们就需要将子组件中的counter,传给父组件的某个属性,比如total。
<body>
<div id="app">
<cpn @item-click="cpnClick"></cpn>
</div>
<template id="cpn">
<div>
<button v-for="item in categories" @click="btnClick(item)">
{{item.name}}
</button>
</div>
</template>
<script src="../vue.js"></script>
<script>
const cpn = {
template: "#cpn",
data() {
return {
categories: [
{ id: "aaa", name: "热门推荐" },
{ id: "bbb", name: "手机数码" },
{ id: "ccc", name: "家用家电" },
{ id: "ddd", name: "电脑办公" },
],
};
},
methods: {
btnClick(item) {
// 发射事件:自定义事件
this.$emit("item-click", item);
},
},
};
// 2.父组件
const app = new Vue({
el: "#app",
data: {
message: "你好啊",
},
components: {
cpn,
},
methods: {
cpnClick(item) {
console.log("cpnClick", item);
},
},
});
</script>
</body>
父子组件的访问方式
有时候我们需要父组件直接访问子组件,子组件直接访问父组件,或者是子组件访问根组件。
-
父组件访问子组件:使用$children或$refs
$children的缺陷:
-
通过$children访问子组件时,是一个数组类型,访问其中的子组件必须通过索引值。
但是当子组件过多,我们需要拿到其中一个时,往往不能确定它的索引值,甚至还可能会发生变化。
有时候,我们想明确获取其中一个特定的组件,这个时候就可以使用$refs$refs的使用:
$refs和ref指令通常是一起使用的。 -
首先,我们通过ref给某一个子组件绑定一个特定的ID。
-
其次,通过this.$refs.ID就可以访问到该组件了。
<body> <div id="app"> <cpn ref="aaa"></cpn> <cpn></cpn> <cpn></cpn> <button @click="btnClick">按钮</button> </div> <template id="cpn"> <div>我是子组件</div> </template> <script src="../vue.js"></script> <script> const app = new Vue({ el: "#app", data: { message: "你好啊", }, methods: { btnClick() { // console.log(this.$children); // for (let c of this.$children) { // console.log(c.name); // c.showMessage(); // } // console.log(this.$children[0].showMessage); console.log(this.$refs); console.log(this.$refs.aaa.name); }, }, components: { cpn: { template: "#cpn", data() { return { name: "我是子组件的name", }; }, methods: { showMessage() { console.log("showMessage"); }, }, }, }, }); </script> </body>
-
-
子组件访问父组件:使用$parent
-
尽管在Vue开发中,我们允许通过$parent来访问父组件,但是在真实开发中尽量不要这样做。
-
子组件应该尽量避免直接访问父组件的数据,因为这样耦合度太高了。
-
如果我们将子组件放在另外一个组件之内,很可能该父组件没有对应的属性,往往会引起问题。
-
另外,更不好做的是通过$parent直接修改父组件的状态,那么父组件中的状态将变得飘忽不定,很不利于我的调试和维护。
-