持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第2天
父子组件通信
通信方式:
- 通过props向子组件传递数据
- 通过事件向父组件发送消息
在子组件中存入props字符串数组,里面的字符串名任意取,之后这些字符和父组件中data中的数据做绑定:在组件标签中,绑定与字符数组中字符相同的属性,令其等于父组件中data域要绑定的数据名。
<script>
window.onload = function(){
const cpn = {
template: `
<div>
{{cmessage}}
</div>
`,
props: ["cmessage"]
}
const app = new Vue({
el:'#app',
data:{
message: 111,
},
methods:{
itemClick(){
}
},
components: {
cpn
}
})
}
</script>
</head>
<body>
<div id="app">
<cpn :cmessage="message"></cpn>
</div>
绑定后,在template中也可通过props中定义的属性名使用
如果不用v-bind,则会将内容当作字符串传递给属性
当需要对props进行类型验证时,就需要对象写法了:
props: {
//用法一:类型限制
cmovies: Array,
//用法二:提供一些默认值
cmessage: {
type: String,
default: 'aaaaa',
required: true //必须在标签中绑定
},
//类型是对象或者数组时,默认值必须是一个函数
cbooks: {
type: Array,
default(){
return []
}
}
}
type其他的可选值:
- null匹配任何类型
- [String, Number]多个可能的类型
自定义验证函数:
props:{
prop:{
validator:function(value){
//这个值必须匹配下列字符串中的一个
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
}
自定义类型:
function Person(firstName, lastName){
this.firstName = firstName
this.lastName = lastName
}
vue.component('blog-post',{
props: {
author: Person
}
})
注意在起名时,若使用驼峰命名法,v-bind绑定时,要转换为 - 连接
在子组件中,必须有一个根元素div包裹其内元素
<!--通过$emit()向父组件发送信息-->
<div id="app">
<!-- 绑定监听子组件发射出去的事件,绑定时省略掉括号,若emit中有传入数据,则默认传入emit的第二个参数 -->
<cpn @itemclick="cpnclick"></cpn>
</div>
<template id="cpn">
<div>
<button @click="btnclick">
{{message}}
</button>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const cpn = {
template: `#cpn`,
data(){
return {
message:'点我向父组件发送消息'
}
},
methods:{
btnclick(){
//发射
this.$emit('itemclick');//第二个参数可选,为要传入的数据
}
}
}
const app = new Vue({
el:'#app',
data: {
message: 0
},
components:{
cpn
},
methods:{
cpnclick(){
console.log("子组件的消息传到了这里")
}
}
})
</script>
在子组件中实现与父组件数据双向绑定
不能直接与props中的参数绑定,虽然可以运行,但会显得数据很乱,并且报错
<div id="app">
<cpn :mynumber1="number1" :mynumber2="number2" @changenum1="change1"></cpn>
{{number1}}
</div>
<template id="cpn">
<div>
<!--与组件的data域数据进行双向绑定-->
<input v-model="cpnnumber1" @input="changenum1"> <br>
props:{{mynumber1}} <br>
cpn:{{cpnnumber1}} <br>
<input v-model="cpnnumber2" > <br>
props:{{mynumber2}} <br>
cpn:{{cpnnumber2}} <br>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const cpn = {
template: `#cpn`,
data(){
return {
//在这里将props得到的数据绑定进自己的data域中
cpnnumber1: this.mynumber1,
cpnnumber2: this.mynumber2
}
},
props: {
mynumber1: Number,
mynumber2: Number
},
methods: {
changenum1(mynumber1){
return this.$emit('changenum1',this.cpnnumber1);
}
}
}
const app = new Vue({
el: `#app`,
data: {
number1:0,
number2:1,
},
components: {
cpn
},
methods: {
change1(num1){
this.number1 = parseInt(num1);
}
}
})
</script>
讲这个案例时老师用v-bind和@input替换v-model,不知道原因,并且后续提到了watch这一options选项,用于监听数据的改变,大致用法:
watch: {
//这里name是要监听的属性,newValue是更新的值,oldValue是旧的值(可省)
name(newValue, oldValue){
}
}
父子组件的访问
父组件访问子组件:this.refs reference
-
$children得到的为一个数组类型数据,它包含所有父/子组件对象,实际开发中使用不多
-
$refs默认得到的是一个空对象,用法↓
<!--在标签中绑定ref属性,指定一个key--> <cpn ref="aaa"></cpn> //获取子组件对应的属性数组 this.$refs.aaa
子组件访问父组件:
- this.children类似,不过返回的不是数组类型,但一个组件可在多个父组件中使用,每个父组件的数据可能不同,所以用这种方式获取父组件属性与父组件耦合度过高,很少使用
- this.$root,访问根组件