1、父子组件
在上一篇随笔中展示了vue的组件,当我们继续在组件中写组件,形成组件嵌套的时候,就是我们所说的父子组件了。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>vue</title> <script src="bower_components/vue/dist/vue.js"></script> <style> </style> </head> <body> <div id="box"> <aaa></aaa> </div> <script> var vm=new Vue({ el:'#box', data:{ a:'aaa' }, components:{ 'aaa':{ template:'<h2>我是aaa组件</h2><bbb></bbb>', components:{ 'bbb':{ template:'<h3>我是bbb组件</h3>' } } } } }); </script> </body> </html>
在上面的例子中,外层的组件aaa就是父组件,内层的bbb组件便是子组件了。
2、子组件获取父组件的数据
我们知道,每个组件都可以有自己的data属性,组件的数据在整个组件的内部都是可以使用的,那么在下面的例子中,组件bbb是aaa的子组件,存在于组件aaa的内部,为什么不能使用aaa的数据呢?
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>vue</title> <script src="bower_components/vue/dist/vue.js"></script> </head> <body> <div id="box"> <aaa></aaa> </div> <template id="aaa"> <h1>11111</h1> <bbb></bbb> </template> <script> var vm=new Vue({ el:'#box', data:{ a:'aaa' }, components:{ 'aaa':{ data(){ return { msg2:'我是父组件的数据' } }, template:'#aaa', components:{ 'bbb':{ template:'<h3>我是bbb组件->{{msg2}}</h3>' } } } } }); </script> </body> </html>
这是因为,在vue中,组件实例的作用域是孤立的,默认情况下,父子组件的数据是不能共享的,也就是说,子组件是不能直接访问父组件的数据的。为此,vue给我们提供了一个数据传递的选项prop,用来将父组件的数据传递给子组件。具体使用如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>vue</title> <script src="bower_components/vue/dist/vue.js"></script> </head> <body> <div id="box"> <aaa></aaa> </div> <template id="aaa"> <h1>11111</h1> <bbb :m="msg"></bbb> </template> <script> var vm=new Vue({ el:'#box', data:{ a:'aaa' }, components:{ 'aaa':{ data(){ return { msg:'我是父组件的数据' } }, template:'#aaa', components:{ 'bbb':{ props:['m'], template:'<h3>我是bbb组件->{{m}}</h3>' } } } } }); </script> </body> </html>
在使用prop时,我们需要在子组件中使用v-bind将父组件数据和子组件的自定义属性m进行绑定,这个自定义m就是我们在子组件的props中定义。一个组件默认可以拥有任意数量的prop,任何值都可以传递给任何的prop,所以我们在上面使用的是props来存储prop列表,这个props既可以是个数组,也可以是个对象。需要注意的是,props中的prop列表需要使用驼峰式命令法。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>vue</title> <script src="bower_components/vue/dist/vue.js"></script> </head> <body> <div id="box"> <aaa></aaa> </div> <template id="aaa"> <h1>11111</h1> <bbb :m="msg2" :my-msg="msg"></bbb> </template> <script> var vm=new Vue({ el:'#box', data:{ a:'aaa' }, components:{ 'aaa':{ data(){ return { msg:111, msg2:'我是父组件的数据' } }, template:'#aaa', components:{ 'bbb':{ props:{ 'm':String, 'myMsg':Number }, template:'<h3>我是bbb组件->{{m}} <br> {{myMsg}}</h3>' } } } } }); </script> </body> </html>
在父组件通过props向子组件传递数据时,根据需求不同,分为静态props和动态props,所谓静态props,就是子组件要显示地用props选项声明它期待获取的数据;而动态props则是动态的绑定父组件的数据到子组件的props,使用v-bind进行绑定,当父组件的数据变化时,该变化也会传递给子组件。另外需要说明的是数字的传递,在使用静态props传递数字时,它在子组件中的值是字符串,如果想传递一个实际的 number,需要使用 v-bind,从而让它的值被当作JS表达式计算 ,可以使用动态props,在data属性中设置对应的数字1。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>vue</title> <script src="bower_components/vue/dist/vue.js"></script> </head> <body> <div id="box"> <aaa></aaa> </div> <template id="aaa"> <h1>11111</h1> <bbb message="静态props" c-message="ppp" :c-mess="pmsg" mess1="1" :mess2="2" :mess3="num"></bbb> </template> <script> var vm=new Vue({ el:'#box', data:{ a:'aaa' }, components:{ 'aaa':{ data(){ return { 'pmsg':'动态props', 'num':3, } }, template:'#aaa', components:{ 'bbb':{ props:['message','cMessage','c-mess','mess1','mess2','mess3'], template: ` <div> <div>{{message}} ---- {{cMessage}} --- {{cMess}}</div> <div> {{mess1}}是{{ type(mess1) }}类型<br> {{mess2}}是{{ type(mess2) }}类型<br> {{mess3}}是{{ type(mess3) }}类型<br> </div> <div> `, methods:{ type(text){ return typeof text; } } } } } } }); </script> </body> </html>
3、父组件获取子组件的数据
和上面不一样的是,父组件想要获取子组件的数据时,需要子组件通过emit主动将自己的数据发送给父组件。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>vue</title> <script src="bower_components/vue/dist/vue.js"></script> </head> <body> <div id="box"> <aaa></aaa> </div> <template id="aaa"> <span>我是父级 -> {{msg}}</span> <bbb @child-msg="get"></bbb> </template> <template id="bbb"> <h3>子组件-</h3> <input type="button" value="send" @click="send"> </template> <script> var vm=new Vue({ el:'#box', data:{ a:'aaa' }, components:{ 'aaa':{ data(){ return { msg:111, msg2:'我是父组件的数据' } }, template:'#aaa', methods:{ get(msg){ this.msg=msg; } }, components:{ 'bbb':{ data(){ return { a:'我是子组件的数据' } }, template:'#bbb', methods:{ send(){ this.$emit('child-msg',this.a); } } } } } } }); </script> </body> </html>
首先,我们需要在子组件中触发一个主动发送数据的事件,上面的例子中是一个点击事件send;其次,在点击事件中使用emit方法,这个emit接收两个参数:传递数据的事件和需要传递的数据,这个传递数据的事件也是自定义的;然后在父组件中引用子组件,并在引用的子组件中使用on监听上一步传递数据的事件,上面的例子中是child-msg;最后在父组件中使用这个事件,这个事件带有一个参数,就是从子组件发送过来的数据。
4,sync
首先,在下面的例子中,子组件获取了父组件的数据后进行了更改,但是更改的是子组件的内部。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>vue</title> <script src="vue1.0.js"></script> </head> <body> <template id="child"> <div> <span>我是子组件</span> <input type="button" value="按钮" @click="change"> <strong>{{msg}}</strong> </div> </template> <div id="box"> 父级: ->{{a}} <br> <child-com :msg="a"></child-com> </div> <script> new Vue({ el:'#box', data:{ a:'我是父组件数据' }, components:{ 'child-com':{ props:['msg'], template:'#child', methods:{ change(){ this.msg='被更改了' } } } } }); </script> </body> </html>
也就是说我们改变的并不是父组件的a,而是子组件的msg,那么如果我们需要同时改变父组件的数据呢,就需要用到sync了,只需要对上面的代码稍作改变就可以了。