本文在具体实现上,主要是基于vue2.0并使用vue-cli脚手架搭建的一个基本项目,至于vue-cli这个脚手架,如果不懂也没关系,可以先用  ̄□ ̄||,主要介绍的是组件之间的通信。
0、前置
首先,肯定要有安装node和vue-cli了,具体怎么安装就不介绍了。
然后,创建一个初始化的项目vue_demo_2: vue init webpack vue_demo
生成的项目结构如下:
项目结构介绍:
| - build (运行文件夹,dev/prod运行时需要用到的相关文件,含webpack配置)
| - config (配置文件夹,比如说dev/prod两种对应的不同接口等设置)
| - dist (打包生成的部署文件夹,一开始没有的,跑命令npm run build之后可见!!!)
| - node_modules (一些安装的依赖模块)
| - src (项目代码)
| - assets (资源文件夹,为了区分static,这里存自己的资源)
| - components (页面文件夹,用来存放一些组件)
| - router (路由文件夹)
| - App.vue (vue主文件)
| - main.js (入口文件,webpack配置的entrance)
| - static (资源文件夹,为了区分assets,这里存第三方的资源)
| - .babelrc (转码规则配置)
| - .editorconfig (代码规范配置)
| - .eslintignore (eslint检查忽略配置)
| - .eslintrc.js (eslint配置文件)
| - .gitignore (git忽略配置)
| - .postcssrc.js (postcss的load的config,文件里有对应的github地址)
| - index.html (html主页面)
| - package.json (项目的一些基本介绍,比如项目的描述、用到哪些模块等)
| - README.md
接下来,就可以正常实现不同组件之间的数据传递了,即组件之间的通信。
1、父组件向子组件传递数据
将App.vue这个组件中删除原来模板中的东西只保留基本的框架,当前App.vue文件内容如下:
<template>
<div id="app">
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
<style>
</style>
在src/components
文件夹下,新建一个Child.vue
单文件组件,创建props用于接收数据,并包含一个message属性,内容结构如下:
<template>
<div class="child">
<h2>我是子组件</h2>
<p>这是我从父组件接收到的数据: {{cMessage}}</p>
</div>
</template>
<script>
export default {
name: 'Child',
props:["cMessage"]
}
</script>
<style>
.child{
border:1px solid blue;
width: 50%;
}
</style>
在App.vue
组件,相当于是父组件中,引入子组件文件,并调用该子组件,然后将数据传递给子组件,修改后App.vue代码如下:
<template>
<div id="app">
<h1>我是父组件</h1>
<child cMessage="hello child"></child> <!-- 调用子组件, 注意cMessage这个属性名称是由子组件中props定义 -->
</div>
</template>
<script>
import Child from './components/Child.vue' // 引入子组件文件
export default {
name: 'App',
components:{
Child // 声明子组件
}
}
</script>
<style>
#app{
width: 60%;
border: 1px solid red;
}
</style>
npm run dev
在浏览器打开之后我们可以看到,父组件已经把数据传递给子组件了。
这是父组件向子组件传递的静态数据,当动态传递数据时,需要用到v-bind绑定数据,修改App.vue
文件代码如下:
<template>
<div id="app">
<h1>我是父组件</h1>
<!-- <child cMessage="hello child"></child> 调用子组件 -->
<child v-bind:cMessage="pMessage"></child> <!-- 动态绑定父组件数据 ,cMessage还是子组件中props中的属性,pMessage是父组件的数据 -->
</div>
</template>
<script>
import Child from './components/Child.vue' // 引入子组件文件
export default {
name: 'App',
components:{
Child // 声明子组件
},
data(){
return {
pMessage:'hello child , 这是动态数据'
}
}
}
</script>
<style>
#app{
width: 60%;
border: 1px solid red;
}
</style>
结果如下:
以上就完全实现了父组件向子组件的通信了,总结:
第一步: 子组件在props中创建属性,用于接收父组件传递来的数据;
第二步:父组件先引入子组件文件,声明子组件,然后调用子组件,并在调用的子组件时,引用子组件props中声明的属性,将父组件数据赋值给该属性,就实现了父向子组件的数据传递,动态数据则是通过v-bind绑定父组件数据。
2、子组件向父组件传递数据
接着,继续实现子组件向父组件通信,修改Child.vue
子组件文件,添加一个button
并给该按钮绑定了一个点击事件,在该点击事件方法中使用$emit()
方法将数据传递给父组件,具体代码内容如下:
<template>
<div class="child">
<h2>我是子组件</h2>
<p>这是我从父组件接收到的数据: {{cMessage}}</p>
<button v-on:click="sendMessage">传数据给父组件</button>
</div>
</template>
<script>
export default {
name: 'Child',
props:["cMessage"],
methods:{
sendMessage(){
// 第一个参数:子组件触发的一个自定义事件, 第二个参数:子组件要向父组件传递的数据
this.$emit('childEvent','hello parent , 这是从子组件传来的数据');
}
}
}
</script>
<style>
.child{
border:1px solid blue;
width: 50%;
}
</style>
在App.vue
这个父组件文件中,同样调用子组件,同时利用v-on监听子组件自定义的事件,并绑定自己本身实现的方法,具体代码修改内容如下:
<template>
<div id="app">
<h1>我是父组件</h1>
<!-- <child message="hello child"></child> 调用子组件 -->
<!-- <child v-bind:cMessage="pMessage"></child> 动态绑定父组件数据 -->
<p>这是我从子组件接收到的数据:{{fromChild}}</p>
<!-- 父组件触发的childEvent是子组件中方法sendMessage中$emit()的第一个参数自定义的事件名称,showMessage是父组件methods中的方法 -->
<child v-bind:cMessage="pMessage" v-on:childEvent="showMessage"></child>
</div>
</template>
<script>
import Child from './components/Child' // 引入子组件文件
export default {
name: 'App',
components:{
Child // 声明子组件
},
data(){
return {
pMessage:'hello child , 这是动态数据',
fromChild:''
}
},
methods:{
showMessage(data){
this.fromChild = data;
}
}
}
</script>
<style>
#app{
width: 60%;
border: 1px solid red;
}
</style>
在浏览器中,点击数据传递按钮,可以看到:
这样,也实现了子组件向父组件的数据传递,总结:
第一步: 子组件需要用$emit()
触发一个自定义事件,事件名称即第一个参数名称,并将要传给父组件的数据作为$emit()的第二个参数。
第二步: 父组件同样需要引用子组件文件,声明子组件,然后调用子组件,在调用子组件时需要用v-on监听子组件中自定义的事件,绑定自身的方法,而该方法的参数就是子组件传递过来给父组件的数据。
3、组件之间的数据传递
在vue中,很多的一种情况就是组件之间并没有父子关系,就是很普通的两个组件,那么这种平级组件之间的通信是怎么的,在理解父子组件之间通信的基础上,我们接下来继续介绍它们的实现。
在src/assets
文件加下,新建一个mEvent.js
文件,该js文件代码如下:
import Vue from 'vue'
export default new Vue
可以看到mEvent.js里面放的是一个空的Vue实例对象,事实上,通过父子组件之间相互通信父组件向子组件传递数据是借助porps,子组件向父组件通信则是借助$emit(),可以发现都需要一个中介,而平级组件之间的通信则是可以通过这个mEvent.js作为中介来实现。
在src/componets
文件夹下新建3个单文件组件:FirstComponent.vue
,SecondComponent.vue
,ThirdComponent.vue
,并在在App.vue这个组件中引用,此时App.vue
中的代码为:
<template>
<div id="app">
<first-component></first-component> <!-- 调用组件 -->
<second-component></second-component>
<third-component></third-component>
</div>
</template>
<script>
import FirstComponent from './components/FirstComponent' // 引入单文件组件
import SecondComponent from './components/SecondComponent'
import ThirdComponent from './components/ThirdComponent'
export default{
name:'App',
components:{
FirstComponent, // 声明组件
SecondComponent,
ThirdComponent
}
}
</script>
<style>
#app{
width: 80%;
border: 1px solid black;
}
</style>
在第1个组件中,将数据传递给第3个组件,FirstComponent.vue
具体代码如下:
<template>
<div class="firstComponent">
<h2>我是第1个组件</h2>
<button v-on:click="oneSendToThird">向组件3传递数据</button>
</div>
</template>
<script>
import mEvent from '../assets/mEvent.js' // 引入做问中介的单一事件
export default{
name:'FirstComponent',
methods:{
oneSendToThird(){
mEvent.$emit('firstComponentMessage','hello,这是来自第1个组件的数据');
}
}
}
</script>
<style>
.firstComponent{
width: 60%;
border: 1px solid red;
}
</style>
同样,在第2个组件中也将数据传递给第3个组件,SecondComponent.vue
具体实现如下:
<template>
<div class="secondComponent">
<h2>我是第2个组件</h2>
<button v-on:click="twoSendToThird">向组件3传递数据</button>
</div>
</template>
<script>
import mEvent from '../assets/mEvent.js' // 引入做问中介的单一事件
export default{
name:'SecondComponent',
methods:{
twoSendToThird(){
mEvent.$emit('secondComponentMessage','hi,这是来自第2个组件的数据');
}
}
}
</script>
<style>
.secondComponent{
width: 60%;
border: 1px solid green;
}
</style>
此时,第3个组件要接收来自第1和第2个组件传递过来的数据,ThirdComponent.vue
具体实现如下:
<template>
<div class="thirdComponent">
<h2>我是第3个组件</h2>
<p>这是从第1个组件发过来的数据:{{msg1}}</p>
<p>这是从第2个组件发过来的数据:{{msg2}}</p>
</div>
</template>
<script>
import mEvent from '../assets/mEvent.js' // 引入做问中介的单一事件
export default{
name:'ThirdComponent',
data(){
return{
msg1:'',
msg2:''
}
},
mounted() {
/*要借用es6的箭头函数,如果不用箭头函数
在触发$on()事件前先:_this=this; 然后在普通函数中将数据赋值:_this.msg = data1;
如果事先不暂存this,则会由于this的问题无法将数据添加
*/
mEvent.$on('firstComponentMessage', (data1)=> {
this.msg1 = data1;
})
mEvent.$on('secondComponentMessage', (data2)=> {
this.msg2 = data2;
})
},
}
</script>
<style>
.thirdComponent{
width: 60%;
border: 1px solid green;
}
</style>
那么在浏览器,分别点击按钮,可以看到数据已经传送成功了。
从代码实现来看,不难发现平级组件之间数据的通信主要通过借助一个中介mEvent.js,其实就是一个空的Vue实例对象,然后在利用$emit()
发数据,$on()
接数据,所以总结
一下就是:
第一步:创建一个单一的事件中心来管理组件之间的通信,事实上就是一个中介;
第二步:在需要传值的组件中$emit()
触发一个自定义事件,并传递参数;
第三步:在需要接收数据的组件中$on()
监听自定义事件,并在回调函数中处理传递过来的参数。
至此,父子组件之间和不同组件之间的通信就已经完全实现了。
4、非vue-cli项目中组件之间的通信示例
其实本文主要介绍的就是利用vue-cli搭建一个初始化项目,然后实现单文件组件之间的通信,但是考虑到有些情况下,可能并没有用到vue-cli,所以还是决定实现一下非单文件组件通信实现的写法。
4.1 父组件向子组件传递数据
在电脑任意文件夹下,新建一个componet_comunication1.html
,然后用在该文件中引入vue.js(2.0版本),实现父组件向子组件传递数据,具体代码如下:
<html>
<head>
<meta charset="utf-8">
<title>父组件向子组件传递数据</title>
</head>
<style>
#app{
width: 50%;
border: 1px solid red;
}
.child{
width: 60%;
border:1px solid blue;
}
</style>
<body>
<div id="app">
<h2>我是父组件</h2>
<child :msg="message"></child>
</div>
<template id="child">
<div class="child">
<h2>我是子组件</h2>
<p>这是父组件传递过来的数据:{{msg}}</p>
</div>
</template>
</body>
<script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.js"></script> <!-- 单独引入vue文件 -->
<script>
window.onload = function () {
new Vue({
el:'#app',
data:{
message:'hello child, 这是父组件的数据'
},
components:{ // 注册一个子组件
'child':{
props:['msg'],
template:'#child'
}
}
})
}
</script>
</html>
结果展示:
由于文章前面已经具体介绍过父组件如何向子组件传递数据的,所以就不再相信介绍了,只给出具体的实现demo。
4.2 平级组件之间数据传递
那么,平级组件之间传递数据componet_comunication_2.html
代码实现如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>平级组件数据通信</title>
</head>
<body>
<div id="box">
<com-a></com-a>
<com-b></com-b>
<com-c></com-c>
</div>
</body>
<script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.js"></script>
<script>
var Event=new Vue(); //准备一个空的实例对象
var A={ // 组件A
template:`
<div>
<span>我是A组件</span> -> {{a}}
<input type="button" value="把A数据给C" @click="send">
</div>
`,
methods:{
send(){
Event.$emit('a-msg',this.a);
}
},
data(){
return {
a:'我是a数据'
}
}
};
var B={ // 组件B
template:`
<div>
<span>我是B组件</span> -> {{a}}
<input type="button" value="把B数据给C" @click="send">
</div>
`,
methods:{
send(){
Event.$emit('b-msg',this.a);
}
},
data(){
return {
a:'我是b数据'
}
}
};
var C={ // 组件C
template:`
<div>
<h3>我是C组件</h3>
<span>接收过来的A的数据为: {{a}}</span>
<br>
<span>接收过来的B的数据为: {{b}}</span>
</div>
`,
data(){
return {
a:'',
b:''
}
},
mounted(){
Event.$on('a-msg',function(a){ //接收A组件的数据
this.a=a;
}.bind(this));
Event.$on('b-msg',function(a){ //接收B组件的数据
this.b=a;
}.bind(this));
}
};
window.onload=function(){
new Vue({
el:'#box',
components:{
'com-a':A,
'com-b':B,
'com-c':C
}
});
};
</script>
</html>
结果展示:
好了,简单易懂的vue组件通信介绍就到这,后续有遇到的更多知识会慢慢补充的。如果不足或者不对的地方,欢迎各位指出~
每天总结一点点,每天进步一点点(^-^)V