vue组件的几种通信方式-有详细代码

255 阅读3分钟

组件通信的几种方式...

1. 父传子

  • 值得注意的是,这种数据从父组件传值给子组件 是单向的, 也就是说 子组件无法直接修改父组件传递过来的数据, 如果强行修改 props里面的值,会报一个警告.
  • 如果真的需要修改这个值,推荐使用computed, 当然在data里定义一个变量接收props的值,也是可以的.

父组件---parent.vue

<template>
  <div>
    <Child :message="msg"></Child>
  </div>
</template>
<script>
  import Child from "./child";
  export default {
    components: {
      Child,
    },
    data() {
      return {
        msg: "hello vue!",
      };
    },
  };
</script>
<style scoped></style>

子组件---child.vue

<template>
  <div>
    <p>{{ message }}</p>

    <p>{{ myMsg }}</p>
  </div>
</template>
<script>
  export default {
    // props:["message"],
    props: {
      message: {
        type: String,
        // default: ""
        default() {
          return "";
        },
      },
    },
    data() {
      return {};
    },
    computed: {
      myMsg() {
        return this.message;
      },
    },
    methods: {},
  };
</script>
<style scoped></style>

2. 子传父

  • 这里需要使用自定义事件,在子组件中使用this.$emit(‘myEvent’, value)触发,然后在父组件中使用@myEvent监听.

子组件---child.vue

<template>
  <div>
    <button @click="toParent">传值给父组件</button>
  </div>
</template>
<script>
  export default {
    data() {
      return {
        message: "hello vue!",
      };
    },
    methods: {
      toParent() {
        this.$emit("pushValue", this.message);
      },
    },
  };
</script>
<style scoped></style>

父组件---parent.vue

<template>
  <div>
    <Child @pushValue="getChildValue"></Child>
  </div>
</template>
<script>
  import Child from "./child";
  export default {
    components: {
      Child,
    },
    data() {
      return {
        msg: "hello vue!",
      };
    },
    methods: {
      getChildValue(value) {
        console.log(value); // hello vue!
      },
    },
  };
</script>
<style scoped></style>

3. 兄弟组件之间的传值

  • 运用自定义事件$emit的触发和监听能力,定义一个公共的事件总线 eventBus,通过它作为中间桥梁,我们就可以传值给任意组件了。

事件总线---eventBus.js

import Vue from "vue";
export default new Vue();

子组件---child1.vue

<template>
  <div>
    <button @click="toBrother">传值给兄弟组件child2</button>
  </div>
</template>
<script>
  import eventBus from "./eventBus";
  export default {
    data() {
      return {
        num: 0,
      };
    },
    methods: {
      toBrother() {
        eventBus.$emit("pushValue", ++this.num);
      },
    },
  };
</script>
<style scoped></style>

子组件---child2.vue

<template>
  <div>
    <p>兄弟组件child1传过来的值: {{ myNum }}</p>
  </div>
</template>
<script>
  import eventBus from "./eventBus";
  export default {
    data() {
      return {
        myNum: 0,
      };
    },
    mounted() {
      eventBus.$on("pushValue", (value) => {
        this.myNum = value;
      });
    },
  };
</script>
<style scoped></style>

父组件---parent.vue

<template>
  <div>
    <brotherChild></brotherChild>
    <child></child>
  </div>
</template>
<script>
  import brotherChild from "./brotherChild";
  import child from "./child";
  export default {
    components: {
      brotherChild,
      child,
    },
  };
</script>
<style scoped></style>

4. 路由传值

  • 如果A组件跳转至B组件
// A组件
this.$router.push({
  name: "B",
  query: {
    id: 1,
    name: "Tom",
  },
  //   params: {
  //     id: 1,
  //     name: "Tom",
  //   },
});
// B组件
this.$route.query.id;
this.$route.query.name;
// this.$route.params.id;
// this.$route.params.name;

5. 使用 $ref

  • 通过$ref的能力,给子组件定义一个 ID,父组件通过这个 ID 可以直接访问子组件里面的方法和属性

父组件---parent.vue

<template>
  <div>
    <child ref="child1"></child>
    <button @click="useRefs">调用子组件的属性和方法</button>
  </div>
</template>
<script>
  import child from "./child";
  export default {
    components: { child },
    data() {
      return {
        number: 0,
      };
    },
    methods: {
      useRefs() {
        this.$refs.child1.updateNum();
      },
    },
  };
</script>
<style scoped></style>

子组件---child2.vue

<template>
  <div>
    <p>父组件调用子组件属性或方法: {{num}}</p>
  </div>
</template>
<script>
  export default {
    data() {
      return {
        num: 0,
      };
    },
    methods: {
      updateNum() {
        ++this.num;
      },
    },
  };
</script>
<style scoped></style>

6. 使用 provide 和 inject

  • provide允许我们指定我们想要提供给后代组件的数据/方法 然后在任何后代组件里,我们都可以使用inject来给当前实例 注入父组件的数据/方法

父组件---parent.vue

<template>
  <div>
    <child></child>
    <input v-model="message" />
    <input v-model.number="obj.age" />
  </div>
</template>
<script>
  import child from "./child";
  export default {
    components: { child },
    data() {
      return {
        message: "hello vue!",
        obj: {
          age: 18,
          name: "李四",
        },
      };
    },
    provide() {
      return {
        that: this,
        getObj: this.obj,
        putMethod: this.outPutLog,
      };
    },
    methods: {
      outPutLog(value) {
        console.log(value); // hello vue inject
      },
    },
  };
</script>
<style scoped></style>

任何后代组件---child.vue

<template>
  <div>
    <p>子组件注入依赖: {{that.message}}</p>
    <p>{{getObj.name + "今年" + getObj.age + "岁了"}}</p>
  </div>
</template>
<script>
  export default {
    data() {
      return {};
    },
    inject: ["that", "getObj", "putMethod"],
    mounted() {
      this.putMethod("hello vue inject");
    },
  };
</script>
<style scoped></style>

7. $parent

// 获父组件的数据
this.$parent.message;

// 写入父组件的数据
this.$parent.message = 2;

// 访问父组件的计算属性
this.$parent.bar;

// 调用父组件的方法
this.$parent.func1();

8. Vue.observable(object)

  • 随着组件的细化,多组件间的数据共享越来越普遍, vuex是可以解决组件数据共享的问题, 但是当开发一个不大的应用时, 为了避免代码的冗余繁杂,可以使用vue 2.6.0提供的一个API--observable API, 他可以简单的处理一些多组件数据共享的问题.
  • 如果项目vue版本低于2.6.0, 又要使用Vue.observable(object), 此时就需要升级vuevue-template-compiler版本, 两者的版本需要同步更新, 否则会报错.
// 升级版本
npm update vue -S "或者" yarn add vue -S

npm update vue-template-compiler -S "或者" yarn add vue-template-compiler -D

献上官方文档地址: Vue.observable(object)

下面献上代码实例

首先在src目录下创建一个store.js, 里面提供一个storemutations对象 提供一些方法.

Component1 可以跳转至 Component2

store.js

import Vue from "vue";

export let store = Vue.observable({ name: "李四", age: 18 });
export let mutations = {
  setAge(age) {
    store.age = age;
  },
  setName(name) {
    store.name = name;
  },
};

Component1

<template>
  <div>
    <p>{{ this.name + "今年" + this.age + "岁了" }}</p>
    <input
      type="text"
      v-model="myName"
      @change="changeName(myName)"
      placeholder="名字"
    />
    <input
      type="text"
      v-model="myAge"
      @change="changeAge(myAge)"
      placeholder="年龄"
    />
    <div>
      <button @click="routerPush">跳转至Component2</button>
    </div>
  </div>
</template>
<script>
  import { store, mutations } from "@/store";
  export default {
    name: "Component1",
    data() {
      return {
        message: "hello vue!",
        myName: "",
        myAge: "",
      };
    },
    computed: {
      name() {
        return store.name;
      },
      age() {
        return store.age;
      },
    },
    methods: {
      changeName: mutations.setName,
      changeAge: mutations.setAge,
      routerPush() {
        this.$router.push({
          name: "Component2",
        });
      },
    },
  };
</script>
<style scoped></style>

Component2

<template>
  <div>
    <p>{{ age }}</p>
  </div>
</template>
<script>
  import { store, mutations } from "./store";
  export default {
    name: "Component2",
    data() {
      return {};
    },
    computed: {
      age() {
        return store.age;
      },
    },
  };
</script>
<style scoped></style>

9. vuex

  • 不详细介绍,篇幅太长~~~~

请移步: Vuex