前言
上一篇介绍了组件的一些基础知识,主要包括组件的注册使用、全局组件与局部组件、组件的语法糖、父子组件、模板分离写法以及其他一些属性。
组件通信使得父子组件之间可以传递数据,扩展了组件的功能。本文将介绍使用props从父组件向子组件传递数据,以及通过自定义事件从子组件向父组件发送数据
一、子组件的props属性
子组件的props属性用于接收父组件传递的数据,主要步骤如下:
- 将vue实例作为父组件,注册其子组件
- 在子组件的props属性中定义接收父组件数据的变量
- 在使用子组件时,v-bind绑定对应的父子组件数据变量
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>props父传子</title>
<script src="../../vue/vue.js" type="text/JavaScript" charset="utf-8"></script>
</head>
<body>
<div id="app">
<cpn v-bind:c_message="message" :c-movies="movies"></cpn>
</div>
<template id="cpn">
<div>
<h2>{{c_message}}</h2>
<p>{{c_movies}}</p>
<ul>
<li v-for="item in c_movies">{{item}}</li>
</ul>
</div>
</template>
<script>
/** 父传子props
* 1、将Vue对象(root组件)作为父组件,其中注册一个子组件cpn
* 2、这里注册子组件结合了语法糖、template模板分离
* 3、在子组件中使用props属性,用于接收父组件的数据
* 4、使用子组件展示父组件的数据时,需要v-bind绑定父组件数据到props变量中
*
*/
const cpn = {
template: "#cpn",
//props: ["c_movies", "c_message"],// 数组
props: {
// 1、可以限制类型
/* c_message: String,
c_movies: Array, */
// 2、限制类型外还可以提供默认值
/**
* default:当使用时未绑定数据,传入默认值
* required:表示此数据必须绑定
*/
c_message: {
type: String,
default: "默认值",
required: true,
},
c_movies: {
type: Array,
// default数据是数组、对象时,需要用工厂函数返回
default() {
return ["默认数组"];
},
},
},
data() {
return {};
},
methods: {},
};
// root组件
const app = new Vue({
el: "#app",
data: {
message: "父传子props",
movies: ["复仇者联盟", "美国往事", "八百"],
},
components: {
//cpn: cpn,
// es6增强写法
cpn,
},
});
</script>
</body>
</html>
二、子组件向父组件发送数据(自定义事件)
1、子组件自定义事件,触发事件调用this.$emit(“custom-event”, argv)
2、在父组件中监听子组件定义的事件,定义函数接收来自子组件的数据(这里的监听函数不需要参数,默认传入子组件emit的参数)
代码如下(示例):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>子组件自定义事件传数据到父组件</title>
<script src="../../vue/vue.js" type="text/JavaScript" charset="utf-8"></script>
</head>
<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>
/**
*自定义事件触发,子组件向父组件传数据
*1、子组件自定义事件,触发事件调用this.$emit("custom-event", argv)
*2、在父组件中监听子组件定义的事件,定义函数接收来自子组件的数据(这里的监听函数不需要参数,默认传入子组件emit的参数)
*/
const cpn = {
template: "#cpn",
data() {
return {
categories: [
{ id: 1, name: "热门推荐" },
{ id: 2, name: "手机数码" },
{ id: 3, name: "家用电器" },
{ id: 4, name: "电脑办公" },
],
};
},
methods: {
btnClick(item) {
this.$emit("item-click", item); // this.$emit()子组件给父组件发送事件
},
},
};
const app = new Vue({
el: "#app",
data: {},
components: {
cpn,
},
methods: {
cpnClick(item) {
console.log(item);
},
},
});
</script>
</body>
</html>
三、父子组件通信小案例
结合props与自定义事件完成以下需求:
1、子组件数据和input数据双向绑定;
2、input数据改变父组件数据同步改变(子组件向父组件传递)
3、num1和num2成百倍关系,一方改变另一方也变
大家可以直接复制代码运行一下,体验一下父子组件通信的案例。
代码示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>父子组件通信案例</title>
<script src="../../vue/vue.js" type="text/JavaScript" charset="utf-8"></script>
</head>
<body>
<!--1、子组件数据和input数据双向绑定;
2、input数据改变父组件数据同步改变(子组件向父组件传递)
3、num1和num2成百倍关系,一方改变另一方也变-->
<div id="app">
<cpn :c_num1="num1" :c_num2="num2"
@num1change="num1change" @num2change="num2change"></cpn>
</div>
<template id="myTemp">
<div>
<h2>父组件数据:{{c_num1}}</h2>
<h2>子组件数据:{{dc_num1}}</h2>
<input type="text" v-model="dc_num1">
<h2>父组件数据:{{c_num2}}</h2>
<h2>子组件数据dc_num2:{{dc_num2}}</h2>
<input type="text" v-model="dc_num2">
</div>
</template>
<script>
const cpn = {
template: '#myTemp',
data() {
return {
dc_num1: this.c_num1,
dc_num2: this.c_num2,
};
},
props: {
c_num1: {
type: Number,
},
c_num2: {
type: Number,
},
},
// watch监听data数据是否改变,并传入新的值
watch: {
dc_num1(newValue) {
// emit发送的argv默认为string类型
this.$emit('num1change', newValue);
this.dc_num2 = newValue * 100;
},
dc_num2(newValue) {
this.$emit('num2change', newValue);
this.dc_num1 = newValue / 100;
}
}
}
const app = new Vue({
el: '#app',
data: {
num1: 1,
num2: 2,
},
components: {
cpn,
},
methods: {
num1change(newValue) {
this.num1 = parseFloat(newValue);
},
num2change(newValue) {
this.num2 = parseFloat(newValue);
}
},
})
</script>
</body>
</html>
总结
本篇介绍了props、自定义事件进行父子组件通信的方法,并分别进行了演示,最后结合了两种方法进行父组件=>子组件,子组件=>父组件的双向通信。