组件通信

vue组件间传值

组件可大可小,小到把一个按钮封装成组件,大到一个页面就是一个组件。多数情况,我们的页面是由很多个组件组成,不可避免的要用到组件间的通讯。

一、 父组件向子组件传值

1. prop 属性传值

实现原理: 父组件里面的自定义属性 speaktoson 传到子组件里面作为变量 props :["speaktoson"]
<div id="app">
  <!-- 静态prop -->
  <my-local-com speaktoson="我是你爸爸"></my-local-com>
  <!-- 动态prop -->
  <my-local-com :speaktoson="fatherData"></my-local-com>
</div>
var myLocalCom = {
  template: `
        <div>
            <p>爸爸说:{{speaktoson}}</p>
        </div>
    `,
  props: ["speaktoson"]
};
new Vue({
  el: "#app",
  data: {
    fatherData: "这条数据来自父组件的data"
  },
  components: {
    //必须注册
    myLocalCom
  }
});

目前为止,我们已经能够在三个地方声明 vue 变量(数据)了,分别为 data,computed,props;

2. props 的数据结构

(1) 数组的写法

props: ["speaktoson"];

(2) 对象的写法

Vue.component("example", {
  props: {
    // 基础类型检测 (`null` 指允许任何类型)
    propA: Number,
    // 可能是多种类型
    propB: [String, Number],
    // 必传且是字符串
    propC: {
      type: String,
      required: true
    },
    // 数值且有默认值
    propD: {
      type: Number,
      default: 100
    },
    // 数组/对象的默认值应当由一个工厂函数返回
    propE: {
      type: Object,
      default: function() {
        return { message: "hello" };
      }
    },
    // 自定义验证函数
    propF: {
      validator: function(value) {
        return value > 10;
      }
    }
  }
});

!> 注意: prop 会在组件实例创建之前进行校验,所以在 default 或 validator 函数里,诸如 datacomputedmethods 等实例属性还无法使用。

二、 子组件向父组件传值

实现原理: 父组件监听自定义事件,子组件通过 $emit 触发自定义事件,父组件此时在事件对象里面拿到消息。 注意:vue 里面的 $on$emit 和原生 js 的 addEventListenerdispatchEvent 实现机制并不相同。

子组件中

var myLocalCom = {
  template: `
    <div>
        <p @click="sonSay">点击向爸爸组件发送消息</p>
    </div>
    `,
  data() {
    return {
      sonWords: "今晚吃鸡!"
    };
  },
  methods: {
    sonSay() {
      this.$emit("speaktobaba", this.sonWords);
    }
  }
};

父组件中

<div id="app">
  <my-local-com @speaktobaba="receivedSon"></my-local-com>
</div>
var app = new Vue({
  el: "#app",
  methods: {
    receivedSon(e) {
      console.log(e); //获取到了子组件的信息
    }
  }
});

.sync 修饰符

.sync 修饰符,它会被扩展为一个自动更新父组件属性的 v-on 监听器。

<comp :foo.sync="bar"></comp>

当子组件需要更新 foo 的值时,它需要显式地触发一个更新事件:

this.$emit("update:foo", newValue);

三、 非父子通信

有时候,非父子关系的两个组件之间也需要通信。在简单的场景下,可以使用一个空的 Vue 实例作为事件总线。但其实上父子间也可以利用这种方式实现通讯。

独立的 js 代码中

注意:这时已经有了两个 vue 实例

var busHub = new Vue(); //声明一个中央集线器

组件 A:

var myLocalCom = {
  template: `
    <div>
         <p @click="broSay">点击向兄弟传递消息</p>
    </div>`,
  data() {
    return {
      msg: "兄弟,妈妈喊我们回家吃饭"
    };
  },
  methods: {
    broSay() {
      busHub.$emit("speakToBro", this.msg);
    }
  }
};

组件 B:

var myGlobal = Vue.component("my-global-com", {
  template: "#my_template2",
  created() {
    //在created里面打开监听
    busHub.$on("speakToBro", function(e) {
      console.log(e); //获取兄弟组件传递过来的消息
    });
  }
});

这里的原理是利用的另一个 vue 的实例作为事件的监听 $on 和触发$emit,为了保证能够监听到组件 A 传过来的事件,组件 B 中在created钩子中注册了监听事件。

Last Updated:
Contributors: zerojs