1、组件数据关系
组件实例的作用域是孤立的。这意味着不能 (也不应该) 在子组件的模板内直接引用父组件的数据。如果在子组件中强行使用父组件的数据 ,就会报错,那么子组件如何才能获取父组件的数据呢?
2、组件之间的通讯
组件之间的通讯又叫做组件的传值,父子组件的通讯和非父子组件的通讯。
A与B、A与C :父子关系
B与D、C与E:父子关系
A与E、A与D:(祖孙)隔代关系
B与C:兄弟关系
D与E:堂兄弟关系(非直系亲属)
我们知道组件实例的作用域是孤立的,因此在子组件中是无法直接使用到父组件中的信息的。
举例:
<div id="app">
<my-son></my-son>
</div>
<template id="son">
<div style="border:1px solid red">
<h1>这是子组件,{{msg}}</h1>
</div>
</template>
<script src="./Vuejs/vue2-6-12.js"></script>
<script>
new Vue({
el:"#app",
data:{
msg:"这是app中的msg"
},
components:{
"mySon":{
template:"#son"
}
}
})
</script>
我们看到这里会报错,原因在于子组件的使用了父组件中的msg,因此会显示msg未定义。
3、父传子组件通讯
如何进行父子组件间的通信呢?Vue官方提到,①通过props向子组件传递数据,②通过事件向父组件发送消息。
在组件中,使用选项props来声明需要从父级接收到的数据。在父组件的子组件标签上绑定一个自定义属性,用于绑定要传递的值,在子组件中使用prop属性进行数据的接受,可以直接使用,绑定的属性名和prop定义的名字必须一致,否则无法接受数据。props中的数据,都是通过父组件传递给子组件的,props就是把父组件传递过来的属性,只有props定义,才能使用这个数据,props中的数据,只能读取,不能重新赋值。
props的值有两种方式:
方式一:字符串数组,数组中的字符串就是传递时的名称。
方式二:对象,对象可以设置传递时的类型,也可以设置默认值等。
举例:方式一:静态传值。
<div id="app">
<!-- 静态使用子组件的属性 -->
<my-son movies="唐人街探案3,你好,李焕英" des="电影"></my-son>
</div>
<template id="son">
<div style="border: 1px solid red;">
<h2>这是子组件</h2>
<h3>类型:{{des}} 电影名称:{{movies}}</h3>
</div>
</template>
<script src="./Vuejs/vue2-6-12.js"></script>
<script>
let mySon = {
template:"#son",
//子组件定义props接收数据并使用
//数组里存放的是自定义属性的名称
props:['movies','des'] //数组写法
}
new Vue({ //父组件
el:"#app",
data:{
msg:"这是app中的msg"
},
components:{ //注册的子组件
mySon
}
})
</script>
这里我们使用的是静态传值的方法,即在子组件中写上属性名为props中的属性,属性值则使我们静态传递的属性值。
举例:方式一:动态传值
<div id="app">
<!-- 静态使用子组件的属性 -->
<my-son movies="唐人街探案3,你好,李焕英" :des="msg"></my-son>
</div>
<template id="son">
<div style="border: 1px solid red;">
<h2>这是子组件</h2>
<h3> 电影名称:{{movies}}</h3>
<h4>{{des}}</h4>
</div>
</template>
<script src="./Vuejs/vue2-6-12.js"></script>
<script>
let mySon = {
template:"#son",
//子组件定义props接收数据并使用
//数组里存放的是自定义属性的名称
props:['movies','des'] //数组写法
}
new Vue({ //父组件
el:"#app",
data:{
msg:"这是父组件中的msg"
},
components:{ //注册的子组件
mySon
}
})
</script>
其实动态传值的方式和静态传值的方式类似,我们可以看到这里是将父组件中的msg以属性值的方式传给子组件中的des。父组件在使用子组件的时候,可以将父组件的数据绑定到使用子组件的标签上,然后子组件再选项中添加一个props属性来接收数据。
举例:方式二:使用对象
<div id="app">
<my-son :clist="list"></my-son>
{{list}}
</div>
<template id="son">
<div style="border: 1px solid red;">
<h2>这是子组件</h2>
<ul>
<li>{{clist}}</li>
</ul>
</div>
</template>
<script src="./Vuejs/vue2-6-12.js"></script>
<script>
let mySon = {
template:"#son",
props:{//对象的写法
clist:Array,//数组类型
}
}
new Vue({
el:"#app",
data:{
msg:"这是父组件中的msg",
list:["苹果","香蕉","梨子","橘子"]
},
components:{
mySon
}
})
</script>
这里我们使用的clist:Array
的主要作用是限定clist的值的类型。
在上面的例子中,当我们将<my-son :clist="list"></my-son>
中的clist的属性值修改为msg时,即:<my-son :clist="msg"></my-son>
我们可以看到这是会报错的,虽然也最终渲染出来了页面。
除了数组之外,我们也可以使用对象,当需要对props进行类型等验证时,就需要对象写法了。
那验证都支持那些类型呢?
String Number Boolean Array Object Date Function Symbol
我们也可以一个属性限制多个类型,如上面的例子中,我们可以将props修改成:
props:{//对象的写法
clist:Array,//数组类型
clist:String
}
可以看到,这样修改后就不会再报错了。
推荐使用下面方法写props,注意不要使用引号。
props:{//对象的写法
clist:[String,Array]
}
3.1、prop默认值设置
在prop中,我们可以使用默认值,以及一些必传值,例如:
<div id="app">
<my-son :clist="msg"></my-son>
{{list}}
</div>
<template id="son">
<div style="border: 1px solid red;">
<h2>这是子组件</h2>
<ul>
<li>{{clist}}</li>
<h3>{{cmsg}}</h3>
</ul>
</div>
</template>
<script src="./Vuejs/vue2-6-12.js"></script>
<script>
let mySon = {
template:"#son",
props:{//对象的写法
clist:[String,Array],
cmsg:{
type:String,
default:"这是cmsg"
}
}
}
new Vue({
el:"#app",
data:{
msg:"这是父组件中的msg",
list:["苹果","香蕉","梨子","橘子"]
},
components:{
mySon
}
})
</script>
当我们将其修改为下面情况:<my-son :clist="list" :cmsg="msg"></my-son>
打印的是父组件中的msg,但是当我们父组件中没有传入msg的时候,它是会使用我们default中的值。
3.2、prop必传值设置
我们可以在prop中设置required来设置该数据是否为必传值,当required的属性值为true时,那么就为必传值,为false是就不是。
举例:prop中required的使用。
<div id="app">
<my-son :mymsg="msg"></my-son>
</div>
<template id="son">
<div style="border: 1px solid red;">
<h2>这是子组件</h2>
<h1>{{mymsg}}</h1>
</div>
</template>
<script src="./Vuejs/vue2-6-12.js"></script>
<script>
let mySon = {
template:"#son",
props:{//对象的写法
mymsg:{
type:String,
},
eg:{
required:true,
}
}
}
new Vue({
el:"#app",
data:{
msg:"我是父组件中的msg"
},
components:{
mySon
}
})
</script>
我们在上面例子中设置了eg的required的值为 true,但是在中,我们并没有使用到eg,因此会报错。
4、子传父组件通讯
子组件使用this.$emit()向父组件传值,首先必须在父组件中引用子组件,然后实现传值。
语法规则:
$emit( eventName, […args] )
参数:
eventName:这是一个事件名,会绑定一个方法。当组件触发事件后,将调用这个方法。
…args:附加参数,会被抛出,由上述绑定的方法接收使用。
举例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div.son{
width: 100px;
height: 100px;
background-color: red;
}
</style>
</head>
<body>
<div id="app">
<!-- 接收子组件通过$emit发射的事件 -->
<h3>这里是子组件传过来的内容:{{des}}</h3>
<son @biuapp="changes"></son>
</div>
<template id="son">
<div>
<div class="son"></div>
<button @click=fn()>发射</button>
</div>
</template>
<script src="./Vuejs/vue2-6-12.js"></script>
<script>
var son = {
template:"#son",
data(){
return {
msg:'我是子组件中的msg',
}
},
methods:{
fn(){//把子组件的数据给父组件
//发送一个事件并携带参数
//$emit()第一个参数是事件名 第二个参数是携带的参数
this.$emit("biuapp",this.msg);
console.log("已经发射");
}
}
}
new Vue({
el:"#app",
data:{
des:'',//定义一个空的des
},
components:{
"son":son,
},
methods:{
changes(value){
console.log(value);//我们这里的value接收的是$emit中的第二个参数
this.des = value;//将我们父组件中的des数据修改成$emit传递的数据,再在#app中调用我们的{{des}}
}
}
})
</script>
</body>
</html>
上面的例子中,我们使用了$emit()
将我们子组件中的内容发送给我们的父组件,其中使用$emit()
时我们是定义了一个事件名(biuapp),子组件传递的内容我们放在$emit()
的第二个参数里,即this.msg,然后在父组件中,我们通过v-on来监听子组件事件(即使用@click=”biuapp”)。这样我们父组件就能接收到子组件传递过来的内容。