父子组件通信: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>