Vue组件通信的7种方式

前言

下周准备开始投简历了,这2天把vue相关的知识做一下整理,也算是一个复习了。主要涉及到vue双向绑定原理,组件通讯方式,自定义指令等等,有错误或者不足,后期再修改文章予以修正和补充。

一、Props & $emit()

父组件通过props想子组件传递数据,子组件通过$emit来触发父组件的监听事件,来抛出数据让父组件在事件处理函数中接收。
父组件:

<template>
  <div class="parent">
    <h1 id="parent">父组件</h1>
    <p>{{msg}}</p>
    <!-- 在页面上使用子组件(单标签使用) 绑定自定义属性msg,自定义事件changeMsg ,然后将$event赋值给msg -->
    <c1 :msg="msg" @changeMsg="msg = $event" />
  </div>
</template>

<script>
//引入子组件 然后在components中进行注册
import c1 from "@/components/c1.vue";
export default {
  components: {
    c1,
  },
  data() {
    return {
        msg:'这是第一种通信方式。'
    };
  }
};
</script>
<style lang='less' scoped>
</style>

子组件:

<template>
  <div>
    <h1>子组件</h1>
    <p>{{msg}}</p>
    <button @click="handleClick">按钮1</button>
  </div>
</template>

<script>
export default {
  name: "c1",
  //在props中使用父组件传过来的msg
  props: ["msg"],
  data() {
    return {};
  },
  methods: {
    handleClick() {
      //通过$emit触发父组件的自定义事件,并将bye-bye传递,父组件通过$event接收
      this.$emit("changeMsg", "bye-bye");
    },
  }
};
</script>
<style lang='less' scoped>
</style>

二、callback

使用回调函数来实现组件通信

父组件:

<template>
  <div class="parent">
    <h1 id="parent">父组件</h1>
    <p>{{msg}}</p>
    <!--  绑定自定义属性msg,changeMsg ,然后再methods中定义回调函数修改msg,将回调函数作为自定义属性传递给子组件 -->
    <c2 :msg="msg" :changeMsgFn="changeMsg" />
  </div>
</template>

<script>
//引入子组件 然后在components中进行注册
import c2 from "@/components/c2.vue";
export default {
  components: {
    c2,
  },
  data() {
    return {
      msg: "这是第二种通信方式。",
    };
  },
  methods: {
    changeMsg() {
      this.msg = "bye-bye";
    },
  },
};
</script>
<style lang='less' scoped>
</style>

子组件:

<template>
  <div>
    <h1>子组件</h1>
    <p>{{msg}}</p>
    <button @click="changeMsgFn">按钮2</button>
  </div>
</template>

<script>
export default {
  name: "c2",
  //在props中使用父组件传过来的msg,changeMsgFn
  props: ["msg","changeMsgFn"]
};
</script>
<style lang='less' scoped>
</style>

三、$parent & $children

父组件:

<template>
  <div class="parent">
    <h1 id="parent">父组件</h1>
    <p>{{msg}}</p>
    <button @click="changeChildNumber">父按钮</button>
    <c3 />
  </div>
</template>

<script>
//引入子组件 然后在components中进行注册
import c3 from "@/components/c3.vue";
export default {
  components: {
    c3,
  },
  data() {
    return {
      msg: "这是第三种通信方式。",
    };
  },
  methods: {
    changeChildNumber() {
      // 通过vue实例上的$children[0].number(可能有多个子组件,这里只有一个,所以取第0项)来获取子组件data中的number并将其改变值为666
      this.$children[0].number = 666;
    },
  },
};
</script>
<style lang='less' scoped>
</style>

子组件:

<template>
  <div>
    <h1>子组件</h1>
    <p>{{msg}}</p>
    <p>{{number}}</p>
  </div>
</template>

<script>
export default {
  name: "c3",
  data() {
    return {
      number: 0,
    };
  },
  computed: {
    //示例 通过计算属性 在子组件中显示父组件的msg的值
    msg() {
      return this.$parent.msg;
    },
  },
};
</script>
<style lang='less' scoped>
</style>

四、provide & inject

父组件通过provide来提供变量,子组件通过inject来注入变量。

父组件:

<template>
  <div class="parent">
    <h1 id="parent">父组件</h1>
    <c4 />
  </div>
</template>

<script>
//引入子组件 然后在components中进行注册
import c4 from "@/components/c4.vue";
export default {
  components: {
    c4,
  },
  // 通过provide提供一个变量
  provide: {
    msg: "这是第四种通信方式。",
  },
};
</script>
<style lang='less' scoped>
</style>

子组件:

<template>
  <div>
    <h1>子组件</h1>
    <!-- 消费之后也可以在子组件中进行使用了 -->
    <p>{{msg}}</p>
  </div>
</template>

<script>
export default {
  name: "c4",
  //在inject进行消费
  inject: ["msg"],
};
</script>
<style lang='less' scoped>
</style>

五、$attrs & $listeners

如果组件多层嵌套,孙组件甚至曾孙组件想和父组件通信,不可能使用props一级级传递,所以Vue2.4开始提供了 a t t r s 和 attrs和 attrslisteners来解决这个问题。
父组件:

<template>
  <div class="parent">
    <h1 id="parent">父组件</h1>
    <p>N{{name}}</p>
    <p>A{{age}}</p>
    <c5 :name="name" :age="age" @changeName="changeNameToAlex" />
  </div>
</template>

<script>
//引入子组件 然后在components中进行注册
import c5 from "@/components/c5.vue";
export default {
  components: {
    c5,
  },
  data() {
    return {
      name: "Gary",
      age: "27",
    };
  },
  methods: {
    changeNameToAlex() {
      this.name = 'Alex'
    },
  },
};
</script>
<style lang='less' scoped>
</style>

子组件:

<template>
  <div>
    <h1>子组件</h1>
    <!-- 通过$listener可以获取到父组件的事件监听器(也就是父组件中写在子组件上的自定义事件),从而去执行绑定的对应的事件处理函数changeNameToAlex -->
    <button @click="$listeners.changeName">按钮5</button>
    <!-- $attrs包括了从父组件传递过来的name age自定义属性 -->
    <gc5 v-bind="$attrs" />
  </div>
</template>

<script>
import gc5 from "./gc5";

export default {
  name: "c5",
  components: {
    gc5,
  },
};
</script>
<style lang='less' scoped>
</style>

孙组件:

<template>
  <div>
    <h1>孙组件</h1>
    <!-- 孙组件中可以直接通过$attrs来访问这2个属性 -->
    <p>n:{{$attrs.name}}</p>
    <p>a:{{$attrs.age}}</p>
  </div>
</template>

<script>
export default {
  name: "gc5",
};
</script>
<style lang='less' scoped>
</style>

六、ref & $refs

父组件:

<template>
  <div class="parent">
    <h1 id="parent">父组件</h1>
    <button @click="changeNameF">按钮6</button>
    <!-- 这里可以理解为组件实例注册一个名字 -->
    <c6 ref="child6Comp" />
  </div>
</template>

<script>
//引入子组件 然后在components中进行注册
import c6 from "@/components/c6.vue";
export default {
  components: {
    c6,
  },
  methods: {
    changeNameF() {
      // 通过$refs.实例名字,可以获取到对应的组件实例,然后就可以访问该实例的属性和方法
      console.log("点击前", this.$refs.child6Comp.name);
      this.$refs.child6Comp.changeNameC();
      console.log("点击后", this.$refs.child6Comp.name);
    },
  },
};
</script>
<style lang='less' scoped>
</style>

子组件:

<template>
  <div>
    <h1>子组件</h1>
    <p>n:{{name}}</p>
  </div>
</template>

<script>
export default {
  name: "c6",
  data() {
    return {
      name: "Gary",
    };
  },
  methods: {
    changeNameC() {
      this.name = "Alex";
    },
  },
};
</script>
<style lang='less' scoped>
</style>

七、中央事件总线bus

BUS中央事件总线这种方便兄弟组件间通信的方式。
所谓BUS,就是创建一个Vue事件BUS对象,然后通过bus.$emit触发事件,然后通过bus.$on监听触发的事件这样来传递数据。
但实际上项目中我们可以使用vuex来实现这个功能。
看个例子:
创建一个utils下的bus.js

import Vue from 'vue'

const bus = new Vue()

export default bus

父组件:

<template>
  <div class="parent">
    <h1 id="parent">父组件</h1>
    <b1 />
    <b2 />
  </div>
</template>

<script>
//引入子组件 然后在components中进行注册
import b1 from "@/components/b1.vue";
import b2 from "@/components/b2.vue";

export default {
  components: {
    b1,
    b2,
  },
};
</script>
<style lang='less' scoped>
</style>

兄弟组件1:

<template>
  <div>
    <h1>兄弟组件1</h1>
    <p>{{msg}}</p>
    <p>小弟传递过来的数据:{{b2Msg}}</p>
  </div>
</template>

<script>
import bus from '../../utils/bus'

export default {
  name: "b1",
  components: {},
  data() {
    return {
      msg: "我是大哥。",
      b2Msg: "还没说话",
    };
  },
  mounted() {
    //   通过$on去绑定全局事件 busEvent 注意是全局事件!
    bus.$on("busEvent", (val) => {
      this.b2Msg = val;
    });
  },
};
</script>
<style lang='less' scoped>
</style>

兄弟组件2:

<template>
  <div>
    <h1>兄弟组件2</h1>
    <p>{{msg}}</p>
    <!-- 点击按钮 触发passData -->
    <button @click="passData('大哥是我!')">小弟喊话</button>
  </div>
</template>

<script>
import bus from '../../utils/bus'

export default {
  name: "b2",
  components: {},
  data() {
    return {
        msg:'我是小弟。'
    };
  },
  methods: {
      passData(val){
        //   通过关键字去触发全局事件busEvent
        bus.$emit('busEvent',val)
      }
  },
};
</script>
<style lang='less' scoped>
</style>

总结

以上就是vue中组件间通讯的7种方法。面试当中如果问起vue组件间通信,答出这7中应该这题能过了,下一篇就再整理一下vuex的相关知识以及使用。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值