前言
在了解父子组件之前应先掌握组件开发基础。在实际开发过程中,组件之间可以嵌套,也因此生成父子组件。
父子组件创建流程
1.构建父子组件
1.1 全局注册
(1)构建注册子组件
1 2 //构建子组件child 3 4 var child = Vue.extend({ 5 6 template: '<div>这是子组件</div>' 7 8 }); 9 10 //注册名为'child'的组件 11 12 Vue.component('child',child);
(2)构建注册父组件
1 //构建父组件parent,在其中嵌套child组件 2 3 var parent = Vue.extend({ 4 5 template: '<div>这是父组件<child></child></div>' 6 7 }); 8 9 10 11 Vue.component('parent',parent);
(3)定义vue实例
1 var app = new Vue({ 2 3 el: '#app' 4 5 })
(4)使用父组件
<div id="app"> <parent></parent> </div>
打开浏览器查看
1.2 局部注册
(1)构建子组件
var child = Vue.extend({ template: '<div>这是子组件</div>' });
(2)构建父组件
在父组件中局部注册子组件
1 var parent = Vue.extend({ 2 3 template: '<div>这是父组件<child></child></div>', 4 5 components:{ 6 7 'child':child 8 9 } 10 11 });
(3)定义vue实例
在vue实例中局部注册父组件
var app = new Vue({ el: '#app', components:{ 'parent':parent } })
(4)使用父组件
1 <div id="app"> 2 3 <parent></parent> 4 5 </div>
2.父子组件间通信
2.1 父传子
父组件传消息到子组件使用props
,并且这传递是单向的,只能由父组件传到子组件。我们将上面例子中的父组件增加一个数据传递到子组件中渲染显示。如果父组件需要传多个数据给子组件,依次在后面加即可。
(1)在父组件中增加data,并绑定到子组件上
1 var parent = Vue.extend({ 2 3 template: '<div>这是父组件<child :pdata=data></child></div>', 4 5 data(){ 6 7 return{ 8 9 data:'这是父组件传来的数据' 10 11 } 12 13 }, 14 15 components:{ 16 17 'child':child 18 19 } 20 21 });
其中<child :pdata=data></child>
,:pdata
是v-bind:pdata
的缩写,pdata
是自定义传递数据的命名,子组件中也是用该名字获取数据,data
是父组件中数据的命名。
(2)在子组件中通过props获取数据,并渲染出来
var child = Vue.extend({ template: '<div>这是子组件 {{pdata}}</div>', props:['pdata'] });
查看浏览器
父组件中数据发生变化,子组件中自动更新
子组件不可直接修改通过props
获取到的父组件中的数据
下面我们通过一个例子更好的理解上面两句话
(1)使用<template>
标签创建子组件
为方便书写,我们使用<template>
标签创建组件
<template id="child"> <div> <p>这是子组件</p> <table> <tr> <td>name</td> <td>{{name}}</td> <td><input type="text" v-model="name"></td> </tr> <tr> <td>age</td> <td>{{age}}</td> <td><input type="text" v-model="age"></td> </tr> </table> </div> </template>
这里使用v-model
指令来双向绑定从父组件中获取到的数据
(2)使用<template>
标签创建父组件、
1 <template id="parent"> 2 3 <div> 4 5 <p>这是父组件</p> 6 7 <table> 8 9 <tr> 10 11 <td>name</td> 12 13 <td>{{name}}</td> 14 15 <td><input type="text" v-model="name"></td> 16 17 </tr> 18 19 <tr> 20 21 <td>age</td> 22 23 <td>{{age}}</td> 24 25 <td><input type="text" v-model="age"></td> 26 27 </tr> 28 29 </table> 30 31 //给子组件传递2个数据 32 33 <child :name="name" :age="age"></child> 34 35 </div> 36 37 </template>
(3)构建子组件
1 var child = Vue.extend({ 2 3 template: '#child', 4 5 props:['name','age'] 6 7 });
(4)构建父组件
var parent = Vue.extend({ template: '#parent', data(){ return{ age:16, name:'乔巴' } }, components:{ 'child':child } });
查看浏览器
接着,我们在父组件中修改输入框的值,这会引起v-model
绑定的值变化,同时也会改变子组件中的值
然后我们试着修改子组件中输入框的值,vue会警告不能直接修改父组件传过来的值。
如果我们需要修改从父组件中props传过来的值,最好一开始把这个值赋给另外一个data。
1 var child = Vue.extend({ 2 3 template: '#child', 4 5 props:['name','age'], 6 7 data(){ 8 9 return{ 10 11 name1: '', 12 13 age1: '' 14 15 } 16 17 }, 18 19 //页面挂载时将props的值赋给子组件中的data 20 21 mounted:function(){ 22 23 this.name1 = this.name 24 25 this.age1 = this.age 26 27 }, 28 29 //同时增加监听,当props的值发生变化时,也立即赋值给子组件的data 30 31 watch:{ 32 33 name:function(val){ 34 35 this.name1 = this.name 36 37 }, 38 39 age:function(val){ 40 41 this.age1 = this.name 42 43 } 44 45 } 46 47 });
同时修改v-model
绑定的name
值为name1
,age
为age1
现在修改子组件中的值,就不会报错了,这是因为子组件中修改的是name1
,并不是props传递过来的name
值
2.1 子传父
子组件给父组件传值通过emit
。父组件需在子组件标签上绑定emit
事件。
例子:
(1)构建子组件
1 var child = Vue.extend({ 2 3 template: '<div><button @click="change">点击给父组件传值</button></div>', 4 5 methods:{ 6 7 change: function(){ 8 9 this.$emit('posttoparent',10) 10 11 } 12 13 } 14 15 });
子组件按钮绑定了一个click
事件,当点击按钮执行change
方法,该方法触发emit
事件,事件名为posttoparent
,并且带了一个参数10。
(2)构建父组件
var parent = Vue.extend({ template: '<div>来自子组件的值为:{{datafromchild}} <child v-on:posttoparent="getfromchild"></child></div>', data(){ return{ datafromchild:'' } }, components:{ 'child':child }, methods: { getfromchild: function(val){ this.datafromchild = val } } });
父组件接收emit事件通过v-on指令,格式为:
v-on:emit方法名="父组件方法"
父组件将接收到的参数赋值给datafromchild
查看浏览器
3.兄弟组件间通信
兄弟组件间通信也是用的emit
。但原生vue.js需要新建一个空的vue实例来当桥梁。
下面直接贴代码
1 //新建一个空的vue实例bus 2 3 var bus = new Vue(); 4 5 6 7 var myCom1 = Vue.extend({ 8 9 template: '<div><button @click="change">点击给兄弟组件传值</button></div>', 10 11 methods:{ 12 13 change: function(){ 14 15 //通过空实例去触发emit 16 17 bus.$emit('posttobro',10) 18 19 } 20 21 } 22 23 }); 24 25 26 27 var myCom2 = Vue.extend({ 28 29 template: '<div>来自兄弟组件的值为:{{datafrombro}}</div>', 30 31 data(){ 32 33 return{ 34 35 datafrombro:'' 36 37 } 38 39 }, 40 41 mounted:function(){ 42 43 //接收emit事件 44 45 bus.$on('posttobro',function(val){ 46 47 this.datafrombro = val 48 49 }.bind(this)) 50 51 } 52 53 }); 54 55 56 57 Vue.component('my-com1',myCom1); 58 59 Vue.component('my-com2',myCom2); 60 61 62 63 var app = new Vue({ 64 65 el: '#app' 66 67 });
使用组件
1 <div id="app"> 2 3 <my-com1></my-com1> 4 5 <my-com2></my-com2> 6 7 </div>
查看浏览器