Vue 组件通信详解

父子组件通信: props、 $parent / $children、 provide / inject 、 ref 、  $attrs / $listeners
兄弟组件通信:EventBus 、 Vuex
跨级组件通信: EventBus 、 Vuex 、 provide / inject 、 $attrs / $listeners

父传子 子组件用 props 接收,父组件用 v-bind:prop 发送
父组件
<template>
  <div class="section">
    <com-article :articles="articleList"></com-article>
  </div>
</template>
<script>
import comArticle from "./comArticle";
export default {
  data() {
    return {
      articleList: ["红楼梦", "西游记", "三国演义", "水浒传"]
    }
  },
  components: { comArticle },
}
</script>
子组件
<template>
  <ul>
    <li v-for="(item, index) in articles" :key="index">{{item}}</li>
  </ul>
</template>
<script>
export default {
  props: ["articles"]
}
</script>


子传父 子组件用 v-on:click="" this.$emit('name', this.msg)(【有的版本名称只能小写】)发送,父组件自定义事件 v-on:name="getChildValue" 然后在 getChildValue(data){} 方法中接收
父组件
<template>
  <div class="section">
    <com-article @onEmitIndex="onEmitIndex"></com-article> 【不能加括号】
    <ul>
      <li v-for="(item, index) in articles" :key="index">{{item}}</li>
    </ul>
  </div>
</template>
<script>
import comArticle from "./com2";
export default {
  data() {
    return {
        articles:[]
    };
  },
  components: { comArticle },
  methods: {
    onEmitIndex(data) {
      this.articles = data;
    }
  }
}
</script>
子组件
<template>
  <div>
    <button @click="emitIndex()">点击把articleList传给父组件</button> 【可以传参】
  </div>
</template>

<script>
export default {
  data() {
    return {
      articleList: ["红楼梦", "西游记", "三国演义", "水浒传"]
    };
  },
  methods: {
    emitIndex() {
      this.$emit("onEmitIndex", this.articleList); // 
    }
  }
}
</script>


父子传参还可以用 $parent(对象)和 $children(数组)


provide / reject (上传下)
父辈组件中通过 provide 来提供变量,子孙组件中通过 reject 来注入变量。
父组件
<template>
  <div>
    com1 是父组件
    <com2></com2>
  </div>
</template>
<script>
  import com2 from './com2.vue'
  export default {
    provide: {
      msg: "这是父辈组件 com1 传出去的数据"
    },
    components:{
      com2
    }
  }
</script>
子组件
<template>
  <div>
    com2 是 com1 的子组件
    {{demo}}
    <com3></com3>
  </div>
</template>
<script>
  import com3 from './com3.vue'
  export default {
    inject: ['msg'],
    data() {
      return {
        demo: this.msg
      }
    },
    components: {
      com3
    }
  }
</script>
孙组件
<template>
  <div>
    com3 是 com1 的孙组件
    {{msg}}
  </div>
</template>
<script>
  export default {
    inject: ['msg']
  }
</script>


ref
如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例,可以通过实例直接调用组件的方法或访问数据 ref="xx" this.$refs.xx

eventBus(事件总线,项目较大难以维护,组件都可以传) $emit(name, data)发送 $on(name, data=>{})接收 【名称小写】
event-bus.js
import Vue from 'vue'
export const EventBus = new Vue()

com1.vue 发送事件
<button @click="additionHandle">加法器</button>
import {EventBus} from './event-bus.js'
data(){
  return {num: 1}
},
additionHandle(){
  EventBus.$emit('addition', {num: this.num++}
)

com2.vue 接收事件
<div>计算和: {{count}}</div>
data() {
  return {count: 0}
},
mounted() {
  EventBus.$on('addition', param => {
    this.count = this.count + param.num;
  })
}


localStorage / sessionStorage
因为 window.loacalStorage.setItem(key, value)、window.loacalStorage.getItem(key) 储存的是字符串,需要用 JSON.parse() / stringify() 转换
可结合 vuex,实现数据持久保存和解决数据及状态混乱问题


$attrs $listeners(仅仅是传递数据,而不做中间处理,使用 vuex 处理,未免有点大材小用)
test.vue
<template>
  <div>
    test.vue
    <child-com1 :name="name" :age="age" :gender="gender" :height="height" title="test.vue 传出的值"></child-com1>
  </div>
</template>
<script>
const childCom1 = () => import("./com1.vue");
export default {
  components: { childCom1 },
  data() {
    return {
      name: "zhangsan",
      age: "18",
      gender: "女",
      height: "158"
    };
  }
};
</script>
<style scoped>
div{
    background-color: #ddd;
}
</style>
com1.vue
<template>
  <div class="com1">
    com1
    <p>name: {{name}}</p>
    <p>childCom1的$attrs: {{$attrs}}</p>
    <child-com2 v-bind="$attrs"></child-com2>
  </div>
</template>
<script>
const childCom2 = () => import("./com2.vue");
export default {
  components: {
    childCom2
  },
  inheritAttrs: false, // 关闭自动挂载到组件根元素上的没有在 props 声明的属性
  props: {
    name: String
  },
  created() {
    console.log(this.$attrs);
    // {age: "18", gender: "女", height: "158", title: "test.vue 传 com1.vue"}
  }
};
</script>
<style scoped>
.com1{
  margin: 20px;
  background-color: #f00;
}
</style>
com2.vue
<template>
  <div>com2
    <p>age: {{age}}</p>
    <p>childCom2: {{ $attrs }}</p>
  </div>
</template>
<script>
export default {
  inheritAttrs: false,
  props: {
    age: String
  },
  created() {
    console.log('com2', this.$attrs);
    // { "name": "zhang", "gender": "女", "height": "158", "title": "程序员成长指北" }
  }
};
</script>
<style scoped>
div{
  background: #0f0;
  margin: 20px
}
</style>
阅读 667

推荐阅读