vue基础----组件通信(props,$emit,$attrs,$listeners)
一、父传子,子传孙
1. props
1>在父组件中通过子组件自定义的标签属性来传递数据。
2>在子组件中通过props声明希望用到的数据
1 <body> 2 <div id="app"> 3 <my-father :msg1="msg" a="10" :b="20" @click1="fn"></my-father> 4 </div> 5 <script src="./node_modules/vue/dist/vue.js"></script> 6 <script> 7 let vm = new Vue({ 8 el:"#app", 9 data:{ 10 msg:"hello yilia" 11 }, 12 methods:{ 13 fn(){ 14 console.log("father"); 15 } 16 }, 17 components:{ 18 "my-father":{ 19 // props:['msg1'], 20 // template:`<div><h1>{{msg1}}</h1><my-son :msg2="msg1"></my-son></div>`, 21 created(){ 22 console.log(this.$attrs); 23 console.log(this.$listeners); 24 console.log(this); 25 26 }, 27 template:`<div><h1></h1><my-son v-bind="$attrs" v-on="$listeners"></my-son></div>`, 28 data(){ 29 return { 30 31 } 32 }, 33 components:{ 34 "my-son":{ 35 props:['msg1'], 36 template:`<p @click="$listeners.click1()">{{msg1}}</p>`, 37 inheritAttrs:true, 38 data(){ 39 return{ 40 } 41 } 42 } 43 } 44 } 45 } 46 }); 47 48 </script> 49 50 </body>
1.1这里需要注意的props 除了上述这种写法,还可以写成对象形式,来校验数据
1 props: { 2 a: { 3 type: Number, 4 default: 10 5 }, 6 b: { 7 type: String, 8 validator(val) { 9 return val>0; // "2">0 10 } 11 }, 12 arr: { 13 type: Array, 14 //假如属性是数组或对象 默认值需要通过函数返回 15 default:()=>([1]) 16 } 17 },
2.有时候my-father这块用不到数据,但需要把爷爷的数据传给孙子,可以用$attrs,在 my-son v-bind="$attrs"
this.$attrs 对没有使用的属性保留在this.$attrs (也就是props中没有申明的属性)
1 <body> 2 <div id="app"> 3 <my-father :msg1="msg" a="10" :b="20" @click="fn"></my-father> 4 </div> 5 <script src="./node_modules/vue/dist/vue.js"></script> 6 <script> 7 let vm = new Vue({ 8 el:"#app", 9 data:{ 10 msg:"hello Yilia" 11 }, 12 methods:{ 13 fn(){ 14 console.log("father"); 15 } 16 }, 17 components:{ 18 "my-father":{ 19 // props:['msg1'], 20 template:`<div><h1></h1><my-son v-bind="$attrs"></my-son></div>`, 21 data(){ 22 return { 23 } 24 }, 25 components:{ 26 "my-son":{ 27 props:['msg1'], 28 template:`<p>{{msg1}}</p>`, 29 inheritAttrs:true, //为false的时候,没有用到的数据不会显示在dom结构上 30 data(){ 31 return{ 32 } 33 } 34 } 35 } 36 } 37 } 38 }); 39 </script> 40 </body>
二、点击子组件,调用父组件的方法 (想在父组件中绑定原生事件给组件)
1.需要添加修饰符native,不添加就被当作一个属性对待
1 <body> 2 <div id="app"> 3 <!--想在父组件中绑定原生事件给组件 需要加.native 不加就被当作一个属性看待--> 4 <my-button @click.native="fn"></my-button> 5 </div> 6 <script src="./node_modules/vue/dist/vue.js"></script> 7 <script> 8 let vm = new Vue({ 9 el: "#app", 10 methods:{ 11 fn() { 12 console.log("fn() is called"); 13 } 14 }, 15 components: { 16 "MyButton": { 17 template: ` 18 <div> 19 点我 20 </div>` 21 } 22 } 23 }); 24 </script> 25 </body>
点击 “点我” 的时候父组件的fn函数被调用。
2.$listeners 绑定所有的方法,直接调用父组件的方法
1 <body> 2 <div id="app"> 3 <!--想在父组件中绑定原生事件给组件 需要加.native 不加就被当作一个属性看待--> 4 <my-button @click="fn"></my-button> 5 </div> 6 <script src="./node_modules/vue/dist/vue.js"></script> 7 <script> 8 let vm = new Vue({ 9 el: "#app", 10 methods:{ 11 fn() { 12 console.log("fn() is called"); 13 } 14 }, 15 components: { 16 "MyButton": { 17 mounted(){ 18 console.log(this.$listeners); 19 //{click: ƒ} 20 }, 21 template: `<div @click="$listeners.click()">点我</div>` 22 } 23 } 24 }); 25 </script> 26 </body>
3.子组件想调用父组件的方法 $emit
1> 在子组件中调用$emit()方法发布一个事件
2> 在父组件中提供一个在子组件内部发布的事件处理函数
3> 在父组件订阅子组件内部发布的事件
1 <body> 2 <div id="app"> 3 <!--想在父组件中绑定原生事件给组件 需要加.native 不加就被当作一个属性看待--> 4 <!--<my-button @click.native="fn"></my-button>--> 5 <my-button @click="fn" @mouseup="fn"></my-button> 6 </div> 7 <script src="../01-vue-basic/code/node_modules/vue/dist/vue.js"></script> 8 <script> 9 // 组件通信 props $emit $attrs $listeners 10 /* 11 子如何传父 12 1 在子组件中调用$emit()方法发布一个事件 13 2 在父组件中提供一个在子组件内部发布的事件处理函数 14 3 在父组件订阅子组件内部发布的事件 15 */ 16 let vm = new Vue({ 17 el: "#app", 18 data: { 19 content: "点我" 20 }, 21 methods:{ 22 fn(num) { 23 console.log(num,"fn() is called"); 24 } 25 }, 26 components: { 27 "MyButton": { 28 mounted() { 29 console.log(this.$listeners);// 绑定所有的方法 30 }, 31 template: ` 32 <div> 33 <button @click="$listeners.click(123);">点我</button> 34 <button @click="$emit('click2',23)">点我</button> 35 <button @click="$listeners.click(123);" @mouseup="$listeners.mouseup(123);">点我</button> 36 <button v-on="$listeners" >点我</button> 37 </div> 38 ` 39 } 40 } 41 }); 42 </script> 43 </body>