Vue.js 组件通信

🌙
手机阅读
本文目录结构

Vue 组件间通信方式

快速原型开发

可以快速识别。vue 文件封装组件插件等功能

npm install @vue/cli -g
npm install -g @vue/cli-service-global
vue serve App.vue

一 Props 传递数据 和 $emit 触发

components
   ├── Grandson1.vue // 孙子1
   ├── Grandson2.vue // 孙子2
   ├── Parent.vue   // 父亲
   ├── Son1.vue     // 儿子1
   └── Son2.vue     // 儿子2

在父组件Parent.vue中使用儿子组件;

下面是普通用法

父组件如下:

<template>
  <div>
    父组件:{{mny}}
    <Son1 :mny="mny" @input="change"></Son1>
  </div>
</template>
<script>
import Son1 from "./Son1";
export default {
  data() {
    return { mny: 100 };
  },
  components: {
    Son1
  },
  methods: {
    change(mny) {
      console.log("App change");
      this.mny = mny;
    }
  }
};
</script>

子组件如下: 子组件触发父组件方法,通过回调的方式修改的内容传递给父组件

<template>
  <div>
    <h1>Hello, Son1!{{mny}}</h1>
    <button @click="$emit('input',200)">变</button>
  </div>
</template>

<script>
export default {
  props: {
    mny: {
      type: Number
    }
  }
};
</script>

二 $emit 触发

下面是同步父子组件的数据,语法糖的写法;

一个是.sync, 一个是v-model,这两种写法只需要提供值即可;

子模块可以使用'update:xxx' 的语法或者 "$emit('input',200)"这种用法;

.sync 写法

这种写法,

父组件用法:提供值即可,不需要有处理的方法;使用<Son1 :mny.sync="mny"></Son1>

子组件用法:<button @click="$emit('update:mny',200)">变</button> 使用 'update:mny' 的语法;


父组件

<template>
  <div>
    父组件:{{mny}}
    <!-- 1.普通传值 -->
    <!-- <Son1 :mny="mny" @input="change"></Son1> -->

    <!-- 2.sync -->
    <Son1 :mny.sync="mny"></Son1>
  </div>
</template>
<script>
import Son1 from "./Son1";
export default {
  data() {
    return { mny: 100 };
  },
  components: {
    Son1
  }
};
</script>

子组件

<template>
  <div>
    <h1>Hello, Son1!{{mny}}</h1>
    <!-- 1.普通传值 -->
    <!-- <button @click="$emit('input',200)">变</button> -->

    <!-- 2.sync -->
    <button @click="$emit('update:mny',200)">变</button>
  </div>
</template>

<script>
export default {
  props: {
    mny: {
      type: Number
    }
  }
};
</script>

v-model

父组件:提供值即可,不需要有处理的方法;使用<Son1 v-model="mny"></Son1>

子组件:父级传的值只能通过固定的value来接受,触发只能触发input事件,<button @click="$emit('input',200)">更改{{value}}</button>

<template>
  <div>
    父组件:{{mny}}
    <!-- 1.普通传值 -->
    <!-- <Son1 :mny="mny" @input="change"></Son1> -->

    <!-- 2.sync -->
    <!-- <Son1 :mny.sync="mny"></Son1> -->

    <!-- 3.v-model -->
    <Son1 v-model="mny"></Son1>
  </div>
</template>
<script>
import Son1 from "./Son1";
export default {
  data() {
    return { mny: 100 };
  },
  components: {
    Son1
  }
};
</script>
<template>
  <div>
    <h1>Hello, Son1:{{value}}</h1>
    <!-- 1.普通传值 -->
    <!-- <button @click="$emit('input',200)">变</button> -->

    <!-- 2.sync -->
    <!-- <button @click="$emit('update:mny',200)">变</button> -->

    <!-- 3.v-model -->
    <button @click="$emit('input',200)">更改{{value}}</button>
  </div>
</template>
<script>
export default {
  props: {
    // mny: {
    //   type: Number
    // }
    value: {
      // 3.v-model 接收到的属性名只能叫value
      type: Number
    }
  }
};
</script>

三。$parent、$children

父模块 引用 子模块子模块 引用 孙模块…..;

这种情况孙模块可以通过$parent来触发父模块

<!-- 子模块引用孙模块 -->
<Grandson1 :value="value"></Grandson1>

<!-- 孙模块 -->
<template>
    <div>
        <h1>Hello, Grandson1==== {{value}}</h1>
        <button @click="$parent.$emit('input',200)">更改</button>
    </div>
</template>

<script>
    export default {
        props: {
            value: {
                type: Number
            }
        }
    };
</script>

如果层级很深那么就会出现 $parent.$parent….. 我们可以封装一个 $dispatch 方法向上进行派发 既然能向上派发那同样可以向下进行派发

$dispatch

自定义dispatch, 向上派发

Vue.prototype.$dispatch = function $dispatch(eventName, data) {
  let parent = this.$parent;
  while (parent) {
    parent.$emit(eventName, data);
    parent = parent.$parent;
  }
};

$broadcast

自定义broadcast, 向下进行派发

Vue.prototype.$broadcast = function $broadcast(eventName, data) {
  const broadcast = function () {
    this.$children.forEach((child) => {
      child.$emit(eventName, data);
      if (child.$children) {
        $broadcast.call(child, eventName, data);
      }
    });
  };
  broadcast.call(this, eventName, data);
};

四。$attrs、$listeners

当批量拿属性和方法的时候(比如子组件批量向下传从父级接受的属性 / 方法),可以使用 $attrs$listeners来拿

$attrs

$attrs批量向下传入属性

$listeners批量向下传入方法

<Son2 name="anbang" age="29" @click="()=>{this.mny=500}"></Son2>

<!-- son2 -->
<template>
  <div>
    <h1>Hello {{$attrs.name}}, Son2 {{$attrs}}</h1>
    <Grandson2 v-bind="$attrs" v-on="$listeners"></Grandson2>
  </div>
</template>
<script>
import Grandson2 from "./Grandson2";
export default {
  components: {
    Grandson2
  }
};
</script>

<!-- Grandson2 -->
<template>
  <div>
    <h2>Hello, Grandson2{{$attrs}}</h2>
    <button @click="$listeners.click()">更改</button>
  </div>
</template>

五。Provide & Inject

父级模块暴露自己,然后在子模块注入父级数据

注意:父级模块暴露自己,只能子孙模块注入;非子孙模块不用侏儒

Provide 在父级中暴露数据 Inject : 在任意子组件中可以注入父级数据

<!-- parent 模块暴露 -->
provide() {
    return {
        parentMsg: "父亲 Parent123"
    };
}

<!-- son1 模块暴露 -->
  provide() {
    return {
      sonMsg: "son1Msg 信息"
    };
  }

  <!-- Grandson1模块引用 -->
  inject: ["parentMsg", "sonMsg"]
inject: ["parentMsg"] // 会将数据挂载在当前实例上

六。Ref 使用

获取组件实例

<Grandson2 v-bind="$attrs" v-on="$listeners" ref="anbang"></Grandson2>
mounted() { // 获取组件定义的属性
  console.log(this.$refs.anbang.name);
}

七。EventBus

EventBus 又称为事件总线。在 Vue 中可以使用 EventBus 来作为沟通桥梁的概念,就像是所有组件共用相同的事件中心,可以向该中心注册发送事件或接收事件,所以组件都可以上下平行地通知其他组件,但也就是太方便所以若使用不慎,就会造成难以维护的灾难,因此才需要更完善的 Vuex 作为状态管理中心,将通知的概念上升到共享状态层次。

用于跨组件通知 不复杂的项目可以使用这种方式,跨组件通信复杂的就用 Vuex 吧

Vue.prototype.$bus = new Vue();

Son2 组件和 Grandson1 相互通信

<!-- Son2 -->
 mounted() {
  this.$bus.$on("my", data => {
   console.log(data);
  });
 },
<!-- Grandson1 -->
mounted() {
  this.$nextTick(() => {
   this.$bus.$emit("my", "我是Grandson1");
  });
 },

八。Vuex 通信

https://www.fullstackjavascript.cn/vuex.png

AXIHE / 精选资源

浏览全部教程

面试题

学习网站

前端培训
自己甄别

前端书籍

关于朱安邦

我叫 朱安邦,阿西河的站长,在杭州。

以前是一名平面设计师,后来开始接接触前端开发,主要研究前端技术中的JS方向。

业余时间我喜欢分享和交流自己的技术,欢迎大家关注我的 Bilibili

关注我: Github / 知乎

于2021年离开前端领域,目前重心放在研究区块链上面了

我叫朱安邦,阿西河的站长

目前在杭州从事区块链周边的开发工作,机械专业,以前从事平面设计工作。

2014年底脱产在老家自学6个月的前端技术,自学期间几乎从未出过家门,最终找到了满意的前端工作。更多>

于2021年离开前端领域,目前从事区块链方面工作了