vue通信的N种方式

967 阅读4分钟

组件通信可以分为父子组件通信、非父子组件通信,可以是数据的传递,也可以是方法的传递,先介绍数据的相互传递,再介绍方法的相互传递。

父组件到子组件传递数据:

一、通过props,父组件可以传递动态和静态数据。

//父组件
<template>
  <div id="app">
  	//第一种静态数据 <HelloWorld msg="我是父组件的数据"/>
    //第二种动态绑定 <HelloWorld :msg="message"/>
  </div>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'

export default {
  name: 'app',
  data(){
    return{
      message: '我来自父组件'
    }
  },
  components: {
    HelloWorld
  }
}
</script>

//子组件
<template>
  <div class="hello">
    来自父组件的值:{{msg}}
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  props: ['msg']
  //或者 props: { msg: String//指定传入的类型 }
  //或者 props: { msg: String,default: '默认值' //指定默认值 }
}
</script>

二、provide / inject

provide 和 inject 主要为高阶插件/组件库提供用例。并不推荐直接用于应用程序代码中。并且这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。

//父组件
<template>
   <div>
     <child-dom>
     </child-dom>
   </div>
</template>
<script>
   import childDom from "./components/ChildDom.vue";
   export default {
     data() {
       return{

       }
     },
     provide: {
      house: '房子',
      car: '车子',
      money: '¥10000'
    },
     methods:{
      
     },
     components:{childDom},
   }
</script>

//子组件
<template>
   <div>
    
   </div>
</template>
<script>

   export default {
     data() {
       return{

       }
     },
     inject: {
	    house: {
	      default: '没房'
	    },
	    car: {
	      default: '没车'
	    },
	    money: {
	      default: '¥4500'
	    }
	  },
	  created () {
	    console.log(this.house, this.car, this.money)
	  },
	  methods:{
      
      }
   }
</script>

子组件传值给父组件

一、通过props的回调

//父组件
<template>
  <div id="app">
    <HelloWorld :msg="message"/>
  </div>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'

export default {
  name: 'app',
  data(){
    return{
      
    }
  },
  methods: {
    message: (data)=>{
      console.log('我是父组件的方法,在子组件中被触发了')
      console.log('来自子组件的值是:'+data)
    }
  },
  components: {
    HelloWorld
  }
}
</script>

//子组件
<template>
  <div class="hello" @click="msg('来自子组件的值~~')">
    来自父组件的方法,点我执行
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  props: ['msg']
}
</script>

二、通过$emit

//父组件
<template>
  <div id="app">
    <HelloWorld @getData="message"/>
  </div>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'

export default {
  name: 'app',
  data(){
    return{
      
    }
  },
  methods: {
    message: (data)=>{
      console.log('来自子组件的值是:'+data)
    }
  },
  components: {
    HelloWorld
  }
}
</script>

//子组件
<template>
  <div class="hello" @click="goFun">
    点击传值给父组件
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  data(){
    return{
      s: 1111
    }
  },
  methods: {
    goFun(){
      this.$emit('getData',this.s)
    }
  }
}
</script>

三、.sync修饰实现双向绑定

//父组件
<template>
  <div id="app">
    <HelloWorld :show.sync='valueChild'/>
    父组件值:{{valueChild}}
    <button @click="changeValue">点击</button>
  </div>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'

export default {
  name: 'app',
  data(){
    return{
      valueChild:true
    }
  },
  methods: {
    changeValue(){
      console.log('父组件的值被修改:'+this.valueChild)
      this.valueChild =!this.valueChild
    }
  },
  components: {
    HelloWorld
  }
}
</script>

//子组件
<template>
  <div>
    <div>
      <p>子组件值:{{show}}</p>
      <button @click.stop="closeDiv">修改</button>
    </div>
    </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  methods: {
    closeDiv() {
      this.$emit('update:show', !this.show); //触发 input 事件,并传入新值
    }
  },
  props:['show']
}
</script>

关系型组件跨级传递(根组件、儿子组件、孙子组件)

一、使用 $attrs 和 $listeners

通过 $attrs 将值连续往下传递(和props传递类似),传递过程中可以只选择当前需要的值,组件中可以通过 inheritAttrs:false 保持当前组件的属性纯净度。通过 $listeners 可以在(…子组件)中 this. $emit(“upRocket”,11111)来触发父组件中的事件,从而达到传值给父组件的目的。

//父组件
<template>
   <div>
     <child-dom
      :foo="foo"
      :coo="coo"
      @upRocket="reciveRocket"
     >
     </child-dom>
   </div>
</template>
<script>
   import childDom from "./components/ChildDom.vue";
   export default {
     data() {
        return {
          foo:"Hello, world",
          coo:"Hello,rui"
        }
     },
     methods:{
       reciveRocket(data){
          console.log("我是根组件,这是接受的孙子组件的数据"+data)
       }
     },
     components:{childDom},
   }
</script>

//子组件
<template>
   <div>
      <p>foo:{{foo}}</p>
      <childDomChild v-bind="$attrs" v-on="$listeners"></childDomChild>
   </div>
</template>
<script>
import childDomChild from './childDomChild';
export default {
 name:'child-dom',
 props:["foo"],
 inheritAttrs:false,
 components:{childDomChild}
}
</script>

//孙子组件
<template>
   <div>
      <p>coo:{{coo}}</p> 
      <button @click="startUpRocket">发送数据到根组件</button>   </div>
</template>
<script>

export default {
 name:'child-dom',
 props:["coo"],
 methods: {
     startUpRocket() {
      this.$emit("upRocket");
     }
  }
}
</script>

二、$parent $children

其实通过 $ r e f 可以获取到子组件中的一些挂载属性和值, 父组件如果要获取子组件的方法可以通过this.$refs.mychild.funName("…");这种方式,给子组件指定ref名称。同理,通过 $parent $children可直接操作数据和方法。

  • this. $parent查找当前组件的父组件。
  • this.$children查找当前组件的直接子组件,可以获取到全部直接子组件, 需要注意$children 并不保证顺序,也不是响应式的。可以通过this.$root.$children[0].$children[0].$children[0].msg连续查找
  • this.$root查找根组件,并可以配合$children遍历全部组件

//父组件
<template>
   <div>
    父组件的值:{{msg}}
     <child-dom>
     </child-dom>
     <button @click="change">父组件点击修改</button>
   </div>
</template>
<script>
   import childDom from "./components/ChildDom.vue";
   export default {
     data() {
       return{
        msg: 0
       }
     },
     methods:{
      change(){
        this.msg = this.$children[0].childMsg
        this.$children[0].childMsg = '子组件的值被父组件修改了'
      }
     },
     mounted(){
     
     },
     components:{childDom},
   }
</script>

//子组件
<template>
   <div>
      子组件的值:{{childMsg}}
      <button @click="decrease()">子组件点击修改</button>
   </div>
</template>
<script>
export default {
  name:'child-dom',
  data() {
    return {
      childMsg : 111
    };
  },
  methods: {
    decrease() {
      this.childMsg = this.$parent.msg
      this.$parent.msg = "子组件修改了父组件的值"
    }
  }
}
</script>

非关系组件传值

一、EventBus

适用于小型项目,可以达到任意组件相互通信的效果

//组件a
<template>
   <div>
    {{fontCount}}
     <child-dom>
     </child-dom>
   </div>
</template>
<script>
   //import Vue from 'vue'   //export const EventBus = new Vue()
   import { EventBus } from "./assets/bus.js";
   import childDom from "./components/ChildDom.vue";
   export default {
     data() {
       return{
        fontCount: 0
       }
     },
     methods:{
     },
     mounted(){
      EventBus.$on("decreased", ({num}) => {
        this.fontCount -= num
      });
     },
     components:{childDom},
   }
</script>

//组件b
<template>
   <div>
      <button @click="decrease()">-</button>
   </div>
</template>
<script>
import { EventBus } from "../assets/bus.js";
export default {
  name:'child-dom',
  data() {
    return {
      num: 1,
      deg:180
    };
  },
  methods: {
    decrease() {
      EventBus.$emit("decreased", {
        num:this.num
      });
    }
  }
}
</script>

二、vuex

请移步官方文档查阅具体内容