乐趣区

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>
退出移动版