一、 组件间数据传递
1、 父子组件之间的规则
1、 在一个组件内部定义另一个组件,称为父子组件
2、子组件只能在父组件内部使用
3、默认情况下,子组件无法访问父组件中的数据,父组件也无法访问子组件中的数据,每个组件实例的作用域是独立的
2、组件间数据传递 (通信)
1、子组件访问父组件的数据
步骤1:父组件在调用子组件时,绑定子组件想要获取的父组件中的数据
步骤2:在子组件内部,使用props选项声明获取的数据,即接收来自父组件的数据
2、总结:
父组件通过props向下传递数据给子组件
组件中的数据共有三种形式:data、props、computed
3、父组件访问子组件的数据
在子组件中使用vm.$emit(事件名,数据)触发一个自定义事件,事件名自定义
父组件在使用子组件的地方监听子组件触发的事件,并在父组件中定义方法,用来获取数据 。
4、总结
子组件通过events给父组件发送消息,实际上就是子组件把自己的数据发送到父组件
5、示例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>父子组件及组件间数据传递</title> <script src="js/vue.js"></script> </head> <body> <div id="itany"> <my-hello></my-hello> </div> <template id="hello"> <div> <h3>我是hello父组件</h3> <h3>访问自己的数据:{{msg}},{{name}},{{age}},{{user.username}}</h3> <h3>访问子组件的数据:{{sex}},{{height}}</h3> <hr> <my-world :message="msg" :name="name" :age="age" @e-world="getData"></my-world>//子组件只能在父组件中使用,不能跨辈分使用,且父组件在调用子组件时,绑定子组件想要获取的父组件中的数据,即父组件给子组件传值 </div> </template> <template id="world"> <div> <h4>我是world子组件</h4> <h4>访问父组件中的数据:{{message}},{{name}},{{age}},{{user.username}}</h4>//子组件不能直接的访问父组件中的数据,组件之间数据都是独立的,但是通过props就可以了 <h4>访问自己的数据:{{sex}},{{height}}</h4> <button @click="send">将子组件的数据向上传递给父组件</button>//父组件在使用子组件的地方监听子组件触发的事件,并在父组件中定义方法,用来获取数据 。 </div> </template> <script> var vm=new Vue({ //根组件 el:'#itany', components:{ 'my-hello':{ //父组件 methods:{ getData(sex,height){ this.sex=sex; this.height=height; } }, data(){ return { msg:'网博', name:'tom', age:23, user:{id:9527,username:'唐伯虎'}, sex:'', height:'' } }, template:'#hello', components:{ 'my-world':{ //子组件 data(){ return { sex:'male', height:180.5 } }, template:'#world', // props:['message','name','age','user'] //简单的字符串数组,接受父组件传递过来的数据 props:{ //也可以是对象,允许配置高级设置,如类型判断、数据校验、设置默认值 message:String,//指定传递过来的message必须是个字符串,类型限制,限制条件可以是字面量 name:{ type:String, //指定类型和数据校验,限制条件可以是对象,required:true表示必须要有name值, required:true }, age:{ type:Number, default:18, //自定义默认值 validator:function(value){ //自定义校验规则,年龄必须大于0 return value>=0; } }, user:{ type:Object, default:function(){ //对象或数组的默认值必须使用函数的形式来返回 return {id:3306,username:'秋香'}; } } }, methods:{ send(){ // console.log(this); //此处的this表示当前子组件实例 this.$emit('e-world',this.sex,this.height); //使用$emit()触发一个事件,子组件发送数据给父组件 } } } } } } }); </script> </body> </html>
二、单向数据流
1、props是单向绑定的,当父组件的属性变化时,将传导给子组件,但是不会反过来,即父组件修改自身数据影响子组件,但子组件不能修改父组件数据。
2、不允许子组件直接修改父组件中的数据,否则报错。
解决方式:
方式1:如果子组件想把它作为局部数据来使用,可以将数据存入另一个变量中再操作,不影响父组件中的数据
方式2:如果子组件想修改数据并且同步更新到父组件,两个方法:
a.使用.sync(1.0版本中支持,2.0版本中不支持,2.3版本又开始支持)需要显式地触发一个更新事件
b.可以将父组件中的数据包装成对象,然后在子组件中修改对象的属性(因为对象是引用类型,指向同一个内存空间),推荐
3、示例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>单向数据流</title> <script src="js/vue.js"></script> </head> <body> <div id="itany"> <h2>父组件:{{name}}</h2> <input type="text" v-model="name"> <h2>父组件:{{user.age}}</h2> <hr> <my-hello :name.sync="name" :user="user"></my-hello>//父组件给子组件绑定这个name属性,如果子组件的name发送改变允许父组件的name也随之发送改变 </div> <template id="hello"> <div> <h3>子组件:{{name}}</h3> <h3>子组件:{{user.age}}</h3> <button @click="change">修改数据</button> </div> </template> <script> var vm=new Vue({ //父组件 el:'#itany', data:{ name:'tom', user:{ //包装成一个对象 name:'zhangsan', age:24 } }, components:{ 'my-hello':{ //子组件 template:'#hello', props:['name','user'], data(){ return { username:this.name //方式1:将数据存入另一个变量中再操作 } }, methods:{ change(){ // this.username='alice'; // this.name='alice'; // this.$emit('update:name','alice'); //方式2:a.使用.sync,需要显式地触发一个更新事件 this.user.age=18; } } } } }); </script> </body> </html>
三、非父子组件间的通信
1、通信方法:非父子组件间的通信,可以通过一个空的Vue实例作为中央事件总线(事件中心),用它来触发事件和监听事件
2、通信流程:
1、 var Event=new Vue(); //空的Vue实例作为中央事件总线
2、Event.$emit(事件名,数据);//触发事件
3、Event.$on(事件名,data => {});//监听事件
3、示例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>非父子组件间的通信</title> <script src="js/vue.js"></script> </head> <body> <div id="itany"> <my-a></my-a> <my-b></my-b> <my-c></my-c> </div> <template id="a"> <div> <h3>A组件:{{name}}</h3> <button @click="send">将数据发送给C组件</button> </div> </template> <template id="b"> <div> <h3>B组件:{{age}}</h3> <button @click="send">将数组发送给C组件</button> </div> </template> <template id="c"> <div> <h3>C组件:{{name}},{{age}}</h3> </div> </template> <script> //定义一个空的Vue实例 var Event=new Vue(); //A,B,C表示的是对象,注意对象和组件之间的区别 var A={ template:'#a', data(){ return { name:'tom' } }, methods:{ send(){ Event.$emit('data-a',this.name);//$emit用来触发事件, } } } var B={ template:'#b', data(){ return { age:20 } }, methods:{ send(){ Event.$emit('data-b',this.age); } } } var C={ template:'#c', data(){ return { name:'',//初始化数据 age:'' } }, mounted(){ //在模板编译完成后执行 Event.$on('data-a',name => {//$on用来监听事件。=>表示的是回调函数,在回调函数内部不会产生新的this,和普通function函数有本质区别,尤其是在this上的区别 this.name=name; // console.log(this); }); Event.$on('data-b',age => { this.age=age; }); } } var vm=new Vue({ el:'#itany', components:{ 'my-a':A, //本质就是一个对象 'my-b':B, 'my-c':C } }); </script> </body> </html>
四、 slot内容分发
1、本意:位置、槽
2、作用:用来获取组件中的原内容
3、示例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>slot内容分发</title> <script src="js/vue.js"></script> </head> <body> <div id="itany"> <!-- <my-hello>wbs17022</my-hello> -->/单一slot <my-hello> <ul slot="s1"> //多个slot <li>aaa</li> <li>bbb</li> <li>ccc</li> </ul> <ol slot="s2"> <li>111</li> <li>222</li> <li>333</li> </ol> </my-hello> </div> <template id="hello"> <div> <slot name="s2"></slot>//多slot用法 <h3>welcome to itany</h3> <!-- <slot>如果没有原内容,则显示该内容</slot> -->单slot用法 <slot name="s1"></slot> </div> </template> <script> var vm=new Vue({ el:'#itany', components:{ 'my-hello':{ template:'#hello' } } }); </script> </body> </html>