一、父组件向子组件传值
子组件要得到父组件传递而来的值,需要使用props: 来接受,而props可以接收数组和对象,所以我将从数组方法和对象方法分别阐述。
首先我们在new Vue内,构建一个局部的组件,(1) 先全局定义MyTest组件,(2) 然后在new Vue内注册组件,(3) 之后就可以通过标签形式调用注册的组件。我在这里定义组件使用的是抽离组件模板的方法定义的组件。
<body>
<div id="testPtoC">
<my-test></my-test>
</div>
</body>
<template id="mytest">
<div>这是父组件向子组件传值测试</div>
</template>
<script>
const MyTest = {
template: "#mytest"
}
new Vue({
el: "#testPtoC",
data: {
},
components: {
"my-test": MyTest
}
})
</script>
之后来步入正题父组件如何向子组件传值:
第一步: 我们可以在父组件调用子组件的地方,添加一个 自定义属性,而属性值就是你将要传递给子组件的值。
<div id="testPtoC">
<my-test test="测试"></my-test>
</div>
tips:如果属性值为 Number、Boolean或者是 变量,则需要使用 绑定属性
<div id="testPtoC">
<my-test test="测试" :num="10" :flag="true" :tip="tips"></my-test>
</div>
第二步:在子组件定义的时候,我们给他添加一个 props: 选项, props: 可以是 数组[ ] 也可以是 对象{ }
<script>
const MyTest = {
template: "#mytest",
// props: [] //数组
// props: {} //对象
}
</script>
1.父向子传值的数组方法
第二步中如果是用 数组方法接收,那么数组中的元素,即为父组件调用子组件中 自定义的属性名,在这里就是"test",“num”, “flag”,“tip”。
<script>
new Vue({
el: "#testPtoC",
data: {
tip: "测试数据"
},
components: {
"my-test": MyTest
}
})
const MyTest = {
template: "#mytest",
// props: ["test"],
props: ["test", "num", "flag", "tip"]
}
</script>
通过属性名我们就可以在子组件中获取到值:
<template id="mytest">
<!-- <div>这是父组件向子组件传值测试 --- {{ test }}</div> -->
<div>这是父组件向子组件传值测试 --- {{ test }} --- {{ num }} --- {{ flag }} --- {{ tip }}</div>
</template>
浏览器显示结果:
2.父向子传值的对象方法
第二步中如果用的是 对象的方法接收,那么又可以分为两种写法。
写法一:props: 接收的 对象中的键key,即为父组件调用子组件中 自定义的属性名;
value则为传入值的数据类型。
<script>
const MyTest = {
template: "#mytest",
props: { //数据类型记得大写开头
test: String,
num: Number,
flag: Boolean,
tip: String
}
}
</script>
这种写法可以验证传入的值的数据类型。(显示结果同数组方法)
我举个数据类型错误的例子:将num: Number的数据类型改为String类型,则会有如下警告:译文(属性“num”的类型检查失败。需要值为“10”的字符串,得到值为10的数字)
写法二:props: 接收一个 对象,对象中的键key,为父组件调用子组件中 自定义的属性名;value又是一个 对象,可以在该对象中添加两个键值对,如下所示:(type表示数据类型,default表示属性的默认设置)
<script>
const MyTest = {
template: "#mytest",
props: {
test: {
type: String,
default: "这是默认测试"
},
num: {
type: Number,
default: 1130
},
flag: {
type: Boolean,
default: false
},
tip: {
type: String,
default: "这是默认备注"
},
obj: {
type: Object,
default: function() {
return {user: "cxh"}
}
}
}
}
</script>
以下是在父组件中设置属性值与未设置属性值的对比:
<body>
<div id="testPtoC">
<my-test test="测试" :num="10" :flag="true" :tip="tips" :obj="{key: 'value'}"></my-test>
<my-test></my-test>
</div>
</body>
<template id="mytest">
<div>这是父组件向子组件传值测试--- {{ test }} --- {{ num }} --- {{ flag }} --- {{ tip }} --- {{ obj }}</div>
</template>
浏览器显示结果:
【注意】 如果数据类型为一个对象或者是数组,默认值应该为一个函数。
二、子组件向父组件传值
第一步: 父组件在调用子组件的地方,给它绑定一个自定义的 事件( 不要加() )
<body>
<div id="testCtoP">
<my-test @myevent="getData"></my-test>
</div>
</body>
第二步: 在子组件中,利用组件自己的事件或者是生命周期钩子函数触发 this.$emit(“事件名”, “子向父传递的值”)
这里又有两种写法,我都介绍一下:
1. 写法一: 利用组件自定义的method中实现值的传递
在子组件处绑定一个点击事件sendData来触发传值操作
<template id="mytest">
<div @click="sendData">这是子组件向父组件传值测试 </div>
</template>
在子组件的methods中调用sendData,并调用this.$emit(“事件名”, “子向父传递的值”)来实现
<script>
const MyTest = {
template: "#mytest",
methods: {
sendDate() {
this.$emit("myevent", "这是子向父传递的值")
}
}
}
</script>
2. 写法二: 利用vue的生命周期钩子函数实现值的传递
<template id="mytest">
<div>这是子组件向父组件传值测试 </div>
</template>
直接在mounted()函数中调用this.$emit(“事件名”, “子向父传递的值”)来实现
<script>
const MyTest = {
template: "#mytest",
mounted() {
this.$emit("myevent", "这是子向父传递的值")
}
}
</script>
第三步: 在父组件选项methods中实现此事件,默认参数为从子组件中获取的值
<script>
new Vue({
el: "#testCtoP",
data: {
},
methods: {
getData(value) {
console.log(value)
}
},
components: {
"my-test": MyTest
}
})
</script>
浏览器显示结果:(在浏览器的控制器中打印)
写法一需要在点击后打印该语句,写法二直接打印。
三、非父子组件之间的传值
最后我在来说一下非父子组件之间的传值,笨办法就是:找到需要传值的两个组件之间的关系,然后通过父子之间的传值,多次传值达到我们所需的结果。这里就不谈这个方法。我要说的是通过中央事件总线来传值。
首先,先构建两个组件,我们要实现的效果,是点击组件add,来使组件count中的num+1。
<body>
<div id="testF">
<my-add></my-add>
<my-count></my-count>
</div>
</body>
<template id="add">
<button @click="add">add1</button>
</template>
<template id="count">
<div>
点击次数:{{ num }}
</div>
</template>
<script>
const Add = {
template: "#add"
}
const Count = {
template: "#count",
data() {
return {
num: 0
}
}
}
new Vue({
el: "#testF",
components: {
"my-add": Add,
"my-count": Count
}
})
</script>
【注意】 组件数据初始化为一个data函数,如果data为 对象的话,多次调用之后会相互之间有影响,所以使用 函数确保数据间相互独立,不会影响。本例子中未体现,只是用到了data函数初始化数据,就提点一下。
那么我们如何使用所谓的中央事件总线来实现呢我们的需求呢?
我们可以定义一个 car 用于装载两个组件之间需要传递的数据。
可以在定义组件前先将其定义好:
const car = new Vue;
接下来分为两步:
第一步:我们给要发送数据的组件,通过执行add事件调用car.emit(“发送数据的信号”,data),将它 “装载” 到我们定义的"car" 上.
const Add = {
template: "#add",
methods: {
add() {
car.$emit("addEvent", 1);
}
}
}
第二步:找到我们需要接受数据的组件,通过car.$on(“接受数据的信号”,function() { }),取到"car"上发送来的数据。
tips:一般接受数据都使用生命周期钩子函数。
const Count = {
template: "#count",
data() {
return {
num: 0
}
},
mounted() {
let that = this;//函数内部this指向改变了,所以定义一个that用于获得data中的num
car.$on("addEvent", function(data){
that.num += data;
})
}
}
function函数中参数就是用car.emit(“发送数据的信号”,data)中的data,前提是自定义的*“发送数据的信号"和"接受数据的信号”*一致,这样就保证了两个组件之间可以进行传值操作。
浏览器显示结果:
初始:
点击三次之后:
显而易见,我们需要实现的两个非父子组件之间的传值已经实现了。