复习Vue13:组件通信
13.1、父组件向子组件传值
当我们将整个页面都拆分为不同的组件之后,这样就会涉及到组件之间的数据传递问题。
常见的组件通信可以分为三类:
第一类:父组件向子组件传递数据
第二类:子组件向父组件传递数据
第三类:兄弟组件的数据传递
下面我们先看一下父组件向子组件传递数据的情况
第一:子组件通过props
接收传递过来的值。
Vue.component('menu-item',{
props:['title'] // props后面跟一个数组,数组中的内容为字符串,这个字符串可以当做属性类使用。
template:'<div>{{title}}</div>'
})
第二:父组件通过属性将值传递给子组件
<menu-item title="向子组件传递数据"> </menu-item>
<menu-item :title="title"></menu-item> <!--可以使用动态绑定的方式来传值-->
下面我们看一下巨日的案例演示:
<!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.js"></script> -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<father></father>
</div>
<script>
// 创建一个父组件
Vue.component('father', {
// 2、在使用子组件的地方,通过v-bind指令来给子组件中的props赋值。
template: '<div><p>我是父组件</p><son :myName="mySonName"></son></div>',
data() {
return {
mySonName: '小强'
}
},
components: {
// 创建一个子组件
// 1.声明props,它的作用是:用来接收父组件传递过来的数据。
// props可以跟一个数组,数组里面的内容可以是字符串,这个字符串可以当属性来使用。
son: {
props: ['myName'],
template: '<p>我是子组件,我的名字叫{{myName}}</p>'
}
}
})
var vm = new Vue({
el: '#app',
data: {
}
})
</script>
</body>
</html>
下面我们再看一个例子,这个例子是前面我们写的关于局部组件的案例,我们在这个案例的基础上实现组件的传值。
<!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.js"></script> -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<father></father>
<component-a></component-a>
<hello-msg title="你好" :pcontent="content"></hello-msg>
</div>
<script>
const son = {
data() {
return {
msg: "Hello 我是子组件",
};
},
template: `<div>{{msg}}</div>`,
};
// 定义HelloMsg组件
const HelloMsg = {
props: ["title", "pcontent"],
data() {
return {
msg: "Hello World",
};
},
template: `<div>{{msg+'----------'+title+'-----------'+pcontent}}</div>`,
};
Vue.component("ComponentA", {
template: "<div><son></son></div>",
components: {
son: son,
},
});
Vue.component("father", {
template: "<div><p>我是父组件</p><son></son></div>",
components: {
// 创建一个子组件
// son: {
// template: "<p>我是子组件</p>",
// },
son: son,
},
});
var vm = new Vue({
el: "#app",
data: {
content: "来自父组件中的内容",
},
components: {
"hello-msg": HelloMsg,
},
});
</script>
</body>
</html>
在上面的代码中,我们首先给hello-msg
这个组件传递了一个属性title
,该属性的值是固定的。在对应的helloMsg
组件内容定义props
,来接收传递过来的title
属性的值。然后在template
模板中展示title
的值。
接下来,又在Vue
实例中指定了一个content的属性
,下面要将该属性的值传递给HelloMsg
组件。
<hello-msg title="你好" :pcontent="content"></hello-msg>
这里需要动态绑定的方式将content
的值传递到HelloMsg
组件,这里动态绑定的属性为pcontent
,所以在helloMsg
组件内部,需要在props
的数组中添加一个pcontent
,最后在template
模板中展示出pcontent
内容。
// 定义HelloMsg组件
const HelloMsg = {
props: ["title", "pcontent"],
data() {
return {
msg: "Hello World",
};
},
template: `<div>{{msg+'----------'+title+'-----------'+pcontent}}</div>`,
};
通过上面的案例,我们可以看到,在子组件中可以使用props
来接收父组件中传递过来的数据。
但是,props
在进行命名的时候,也有一定的规则。
如果在props
中使用驼峰形式,模板中需要短横线的形式,如下代码案例所示:
Vue.component('menu-item',{
//在JavaScript中是驼峰形式
props:['menuTitle'],
template:'<div>{{menuTitle}}</div>'
})
<!--在html中是短横线方式--->
<menu-item menu-title="hello world"></menu-item>
下面看一下具体的代码演示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>组件传值</title>
</head>
<body>
<div id="app">
<menu-item :menu-title="ptitle"></menu-item>
</div>
<!-- <script src="./vue.js"></script> -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
Vue.component("menu-item", {
props: ["menuTitle"],
template: `<div>来自{{menuTitle}}</div>`,
});
const vm = new Vue({
el: "#app",
data: {
ptitle: "父组件中的数据",
},
});
</script>
</body>
</html>
下面我们看一下props
属性值的类型。
props
可以接收各种类型的值。
如下:
字符串(String)
数值(Number)
布尔值(Boolean)
数组(Array)
对象(Object)
下面,将上面的类型都演示一下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>props类型</title>
</head>
<body>
<div id="app">
<menu-item
:str="str"
:num="10"
b="true"
:marr="arr"
:obj="obj"
></menu-item>
</div>
<!-- <script src="./vue.js"></script> -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
Vue.component("menu-item", {
props: ["str", "num", "b", "marr", "obj"],
template: `<div>
<div>{{str}}</div>
<div>{{typeof num}}</div>
<div>{{typeof b}}</div>
<div>
<ul>
<li :key=item.id v-for='item in marr'>{{item.userName}}</li>
</ul>
</div>
<div>
姓名: {{obj.name}}
年龄:{{obj.age}}
</div>
</div>`,
});
const vm = new Vue({
el: "#app",
data: {
str: "hello",
arr: [
{ id: 1, userName: "zhangsan" },
{
id: 2,
userName: "lisi",
},
],
obj: {
name: "wangwu",
age: 18,
},
},
});
</script>
</body>
</html>
在上面的代码中,想menu-item
组件中传递了各种类型的数据。
注意:
<menu-item :str="str" :num="10" b="true" :marr="arr"></menu-item>
在上面的代码中,:num="10"
表示传递的是数字,如果写成num="10"
表示传递的是字符,
同理b="true"
传递的是字符,如果修改成:b="true"
表示传递的是布尔型。
最后还传递了数组类型与对象类型的内容。
13.2、子组件向父组件传值
第一:子组件通过自定义事件向父组件传递信息。
<button v-on:click='$emit("countSum")'> 计算</button>
第二:父组件监听子组件的事件
<menu-item v-on:countSum='sum+=1'></menu-item>
具体的实现步骤如下:
1、构建基本的结构
<div id="app">
</div>
var vm = new Vue({
el: '#app',
data: {
}
})
2、构建相应的父组件。
Vue.component('father', {
template: '<div>我的儿子叫{{mySonName}}</div>',
data() {
return {
mySonName: ''
}
}
}
3、构建对应的子组件,并且单机子组件中的按钮给父组件传值。
Vue.component('father', {
template: '<div>我的儿子叫{{mySonName}}</div>',
data() {
return {
mySonName: ''
}
},
components: {
son: {
data() {
return {
myName: '小强'
}
},
template: '<button @click="emitMyName">我叫{{myName}}</button>',
methods: {
emitMyName() {
// 子组件传值给父组件需要用到$emit()方法,这个方法可以传递两个参数,一个是事件名称,一个是需要传递的数据
this.$emit('tellMyFatherMyName', this.myName)
}
}
}
}
}
4、父组件接收子组件传递过来的数据。
注意在父组件中引用子组件,同时指定在子组件中定义的事件。
Vue.component('father', {
template: '<div>我的儿子叫{{mySonName}}<son @tellMyFatherMyName="getMySonName"></son></div>',
data() {
return {
mySonName: ''
}
},
methods: {
getMySonName(data) {
this.mySonName = data;
}
}
}
5、组件使用
<div id="app">
<father></father>
</div>
6、完整代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<title>props类型</title>
</head>
<body>
<div id="app">
<father></father>
</div>
<script>
Vue.component('father', {
template: '<div>我的儿子叫{{mySonName}}<son @tellMyFatherMyName="getMySonName"></son></div>',
data() {
return {
mySonName: '1'
}
},
methods: {
getMySonName(data) {
this.mySonName = data;
}
},
components: {
son: {
data() {
return {
myName: '小强'
}
},
template: '<button @click="emitMyName">我叫{{myName}}</button>',
methods: {
emitMyName() {
// 子组件传值给父组件需要用到$emit()方法,这个方法可以传递两个参数,一个是事件名称,一个是需要传递的数据
this.$emit('tellMyFatherMyName', this.myName)
}
}
}
}
})
var vm = new Vue({
el: '#app',
data: {
}
})
</script>
</body>
</html>
13.3、兄弟组件之间的数据传递
兄弟组件传值,通过事件总线完成。
1、定义父组件并且在父组件中,完成两个星弟组件的创建。
<script>
Vue.component('father', {
template: '<div><son></son><daughter></daughter></div>',
components: {
son: {
data() {
return {
mySisterName: ''
}
},
template: '<div>我妹妹叫{{mySisterName}}</div>'
},
daughter: {
data() {
return {
myName: '小雪'
}
},
template: '<button @click="emitMyName">告诉哥哥我叫{{myName}}</button>',
methods: {
emitMyName() {
}
}
}
}
})
var vm = new Vue({
el: '#app',
data: {
}
})
</script>
2、创建事件总线
通过事件总线发射一个事件名称和需要传递的数据。
// 创建一个空的vue实例,作为事件总线
var eventbus = new Vue()
daughter: {
data() {
return {
myName: '小雪'
}
},
template: '<button @click="emitMyName">告诉哥哥我叫{{myName}}</button>',
methods: {
emitMyName() {
// 通过事件总线发射一个事件名称和需要传递的数据
eventbus.$emit('tellBroMyName', this.myName)
}
}
}
3、通过eventbus
的$on()
方法去监听兄弟节点发射过来的事件
son: {
data() {
return {
mySisterName: ''
}
},
template: '<div>我妹妹叫{{mySisterName}}</div>',
mounted() {
// 通过eventbus的$on()方法去监听兄弟节点发射过来的事件
// $on有两个参数,一个是事件名称,一个是函数,该函数的默认值就是传递过来的数据
eventbus.$on('tellBroMyName', data => {
this.mySisterName = data
})
}
},
4、组件的使用
<div id="app">
<father></father>
</div>
5、完整的代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<title>props类型</title>
</head>
<body>
<div id="app">
<father></father>
</div>
<script>
// 创建一个空的vue实例,作为事件总线
var eventbus = new Vue()
Vue.component('father', {
template: '<div><son></son><daughter></daughter></div>',
components: {
son: {
data() {
return {
mySisterName: ''
}
},
template: '<div>我妹妹叫{{mySisterName}}</div>',
mounted() {
// 通过eventbus的$on()方法去监听兄弟节点发射过来的事件
// $on有两个参数,一个是事件名称,一个是函数,该函数的默认值就是传递过来的数据
eventbus.$on('tellBroMyName', data => {
this.mySisterName = data
})
}
},
daughter: {
data() {
return {
myName: '小雪'
}
},
template: '<button @click="emitMyName">告诉哥哥我叫{{myName}}</button>',
methods: {
emitMyName() {
// 通过事件总线发射一个事件名称和需要传递的数据
eventbus.$emit('tellBroMyName', this.myName)
}
}
}
}
})
var vm = new Vue({
el: '#app',
data: {
}
})
</script>
</body>
</html>