今天我们看一下组件通信。
经过前面几篇文章,我们已经可以构建出完整的单个组件,并利用路由使其串联起来访问了。
但这明显还是不够的。一个页面不可能就是个单组件,一般是由多个组件合成的。正因为如此,组件之间肯定是有相互关系的,我们就称这种现象叫组件通信。
比如父组件发生了某项改变,子组件会跟着相应发生变化;反过来,子组件有了某种改变,父组件有时也会随之做出调整。那么这种现象我们称之为双向数据流动。
然而,vue的作者敏锐的认识到,双向数据流带来便捷的同时,也存在着极大的安全隐患。
父组件将变化传递给子组件(父影响子),这是没问题的,在我们日常生活中也是极为普遍的现象(老子教训儿子是天经地义的),然而反过来子影响父的话,这就变得不可理喻了(儿子教训老子?)
子组件修改父组件,增大了组件之间的耦合度。有时开发者根本没有意识到这种修改,这犹如埋下一颗定时炸弹,随着日后项目代码的膨胀,一旦引爆,问题排查难度也会呈指数级的徒增。
为了斩断这种安全隐患,vue提倡的是单向数据流动——也就是只能父影响子,而反过来则不成立。
父传子,我们利用props作为桥梁。下面看一个例子。
首先我将目录调整一下:
其中,helloworld.vue组件,我们设定其为父组件;而children目录下的child.vue,我们设定为其子组件。
Helloworld.vue代码如下:
<!--模板部分-->
<template>
<div class="container">
<h1>我是父亲</h1>
<!--绑定父组件的某个变量myMsg-->
<div>
<!--注意子组件接受变量时,需要变为驼峰命令法sendMessage-->
<child v-bind:send-message="myMsg"></child>
</div>
</div>
</template>
<!--js部分-->
<script>
//引入子组件,需要设定子组件的name为child
import child from './children/child.vue'
export default {
name:'helloworld',
data(){
return {
myMsg:'hello,my son!'
};
},
components:{child}//局部注册子组件
}
</script>
<!--样式部分-->
<style>
.container{
background: #ccc;
color:greenyellow;
}
</style>
大家注意下别把组件和路由的概念搞混了,二者之间一毛钱关系都没有。要使用组件,需做局部或者全局注册。我这里只做局部注册,大家仔细看一下写法。
我们在父组件定义了一个myMsg这个变量,然后通过v-bind绑定到了child组件中。这时,child组件就可以通过props来接收这个变量了。
child.vue代码如下:
<!--模板部分-->
<template>
<div class="sub-container">
<h3>我是儿子</h3>
<div>我从父亲那边接收过来的信息:</div>
<div>{{sendMessage}}</div>
</div>
</template>
<!--js部分-->
<script>
//子组件
export default {
name:'child',//必须设定name,否则无法在父组件import
props:['sendMessage'],
data(){
return {
};
}
}
</script>
<!--样式部分-->
<style>
.sub-container{
background: blue;
color:red;
}
</style>
一个简单的父子通信案例就完成了,看一下路由router/index.js,代码如下:
import Vue from 'vue'
import Router from 'vue-router'
import Hello from '@/components/Hello'
import HelloWorld from '@/components/Helloworld' //我们新定义的组件
Vue.use(Router)
export default new Router({
routes: [{
path: '/',
name: 'Hello',
component: Hello
},
{ //新路由
path: '/helloworld/:id',
name: 'HelloWorld',
component: HelloWorld,
}
]
})
运行一下npm run dev,看一下结果:
可以看到,子组件顺利接收到了父组件传来的信息。
那么,到底子组件能否影响父组件呢?我们将以上代码做一下调整。
调整后的Helloworld.vue
<!--模板部分-->
<template>
<div class="container">
<h1>我是父亲</h1>
<input type="text" v-model="myMsg">
<br>
<!--绑定父组件的某个变量myMsg-->
<div>
<!--注意子组件接受变量时,需要变为驼峰命令法sendMessage-->
<child v-bind:send-message="myMsg"></child>
</div>
</div>
</template>
<!--js部分-->
<script>
//引入子组件,需要设定子组件的name为child
import child from './children/child.vue'
export default {
name:'helloworld',
data(){
return {
myMsg:'hello,my son!'
};
},
components:{child}//局部注册子组件
}
</script>