1.父组件向子组件通信:
总结:父组件通过props向下传递数据给子组件。注:组件中的数据共有三种形式:data、props、computed。
通信步骤:
1.1 在父组件中定义要传递的数据。
1.2 在父组件中调用子组件,并在组件上进行属性绑定,前者自定义名称便于子组件调用,后者是要传递的数据名称。
1.3 在组件件中通过props对象进行接收。
//父组件App组件
<template>
<div id="app">
//1.2 在父组件中调用子组件,并在组件上进行属性绑定,前者自定义名称便于子组件调用,后者是要传递的数据名称。前者childs1是自定义名称便于子组件调用,后者childs2是要传递数据名
<childs :childs1="childs2"></childs>
</div>
</template>
<script>
import Childs from "./components/childs";
export default {
name: 'App',
data(){
return{
//1.1 在父组件定义数据。
childs:["Henry","Bucky","Emily"]
}
},
components:{ childs,}
}
</script>
//子组件 childs
<template>
<div class="hello">
<ul>
//遍历传递过来的值childs1,然后呈现到页面
<li v-for="child in childs1">{{child }}</li>
</ul>
</div>
</template>
<script>
export default {
name: 'Childs',
//1.3 在组件件中通过props对象进行接收。
props:{
childs1:{ //这个就是父组件中子标签自定义名字
type:Array,
required:true
}
}
}
</script>
2.子组件向父组件通信:
总结:子组件通过$event给父组件发送消息,实际上就是子组件把自己的数据发送到父组件。通过事件形式。
通信步骤:
2.1 在子组件中定义要传递的数据。
2.2 在子组件中 methods 中定义一个函数,函数内部通过 .$emit(‘定义事件名称 childData’,‘要传递的数据 title’)向父组件传递数据。
2.3 在子组件中 将这个函数绑定到点击事件上。
2.4 在父组件中在调用的子组件上同样进行事件绑定,与子组件名称可以不同。
2.5 在父组件中methods 中,用这个绑定的事件去获取数据。
//子组件childs
<template>
<childs>
//2.3 在子组件中 将这个函数绑定到点击事件上。
<h1 @click="childData">{{title}}</h1>
</childs>
</template>
<script>
export default {
name: 'Childs',
data() {
return {
//2.1在子组件中定义要传递的数据。
title:"Vue.js Demo"
}
},
methods:{
changeTitle()
let _this. = this
//2.2 在子组件中 methods 中定义一个函数,函数内部通过 .$emit(‘定义事件名称 childData’,‘要传递的数据 title’)向父组件传递数据。
_this.$emit("childData", this.title)
}
}
}
</script>
//父组件App
<template>
<div id="app">
//2.4 在父组件中在调用的子组件上同样进行事件绑定,与子组件名称可以不同。
<childs @titleChanged="updateTitle($event)" ></childs>
<h2>{{title}}</h2>
</div>
</template>
<script>
import Childs from "./components/childs";
export default {
name: 'App',
components:{
childs
}
data(){
return{
title: ""
}
},
methods:{
//2.5 在父组件中methods 中,用这个绑定的事件去获取数据。
updateTitle(e){
let _this. = this
_this.title = e
}
}
}
</script>
3.跨级组件间的通信:
总结:多级组件嵌套需要传递数据时,通常使用的方法是通过vuex。但如果仅仅是传递数据,而不做中间处理,可以使用$attrs
/$listeners。
当前组件已接收的属性指的是当前组件在props中声明的属性。
$attrs:表示<父组件传递的属性集合>与<当前组件已接收的属性集合>的差集,也就是说已被当前组件接收的属性,在下面的层级中无法再获取到$attrs的值与inheritAttrs的值无关。
inheritAttrs: 默认true,也就是说当前组件如果没有在props中声明的剩余属性会继承到原始html元素的属性值上,改为false,在当前组件中props中没有声明的多余属性不会继承到原始html元素的属性。
$listeners是子组件通过$emit提交的所有事件集合 (由于冒泡,还包含子组件从下一层组件获得的所有事件),和$attrs不同的是,即使当前组件处理了子组件提交的某个事件,父组件仍然能获取到这个事件并处理,它应该是遵循了事件冒泡的原则。
使用步骤:
1. 在父级组件进行属性绑定和事件绑定。属性绑定用来向下级(子或孙组件)传递数据,事件绑定用来接收下级(孙组件)发送过来的数据
2. 在子级组件下面通过porps ,来接收父级组件传递过来的数据。 通过v-bind="$attrs" v-on="$listeners" 向孙级组件传递数据。通过事件绑定来接收孙级组件发送过来的数据。
3. 在孙级组件通过porps 接收父级组件传递过来的数据。定义点击事件,通过 this.$emit('事件名称',要发送的数据) 向上级(子级或父级)发送数据。
//父组件
<template>
<div id="App"><h2>父级组件:({{name}},{{age}}</h2>
<child
:fatherName="name"
:fatherAge="age"
@toGrandFather="grandChildValue"
@toFather="grandChildValue">
</child>
</div>
</template>
<script>
import child from "./Child"
export default {
name: "App",
components:{child},
data(){
return {
name: "小辛",
age: 27
}
},
methods:{
grandChildValue(value){
console.log("孙组件对我说:"+value)
}
}
}
</script>
//子组件child<template>
<div id="Child">
<h2>我是子组件</h2>
<p>我的父组件名叫{{fatherName}}</p>
<grandson v-bind="$attrs" v-on="$listeners" @toFather="childValue"></grandson>
</div>
</template>
<script>
import grandson from "./Grandson"
export default {
name: "Child",
components: {grandson},
// 1.默认true,也就是说当前组件如果没有在props中声明的剩余属性会继承到原始html元素的属性值上。2.改为false,在当前组件中props中没有声明的多余属性不会继承到原始html元素的属性
inheritAttrs: false,
// 定义:当前组件已接收的属性指的是当前组件在props中声明的属性
props: ["fatherName"],
methods: {
childValue(value){
console.log("子组件对我说:"+value)
}
}
}
</script>
//孙组件grandson
<template>
<div id="grandson">
<h2>我是孙组件</h2>
<p>我父组件定义的name名叫{{fatherName}},今年{{fatherAge}}岁</p>
<button @click="toGrandFather">叫爷爷</button>
<button @click="toFather">叫爸爸</button>
</div>
</template>
<script>
export default {
name: "Grandson",
props: ["fatherAge","fatherName"],
methods: {
toGrandFather(){
this.$emit("toGrandFather","App.vue,我是您孙组件")
},
toFather(){
this.$emit("toFather","Child.vue,我是您子组件")
}
}
}
</script>
4.轻量级任何组件间(父子、兄弟、跨级)的通信:
总结:通过一个空的Vue实例作为$EventBus中央事件总线(事件中心),用它来触发事件和监听事件,巧妙而轻量地实现了任何组件间的通信,包括父子、兄弟、跨级。当我们的项目比较大时,可以选择更好的状态管理解决方案 vuex。EventBus事件不会随着组件的关闭而自行销毁,所以当路由切换时,EventBus事件会不停的触发,如果数据量比较多的时候,可能会比较影响性能吧,所以需要及时销毁所绑定的EventBus事件。在destroyed()生命周期时执行this.$EventBus.$off('事件名称') 进行事件销毁。
通信步骤:
3.1 首先在main.js将$EventBus绑定在vue实例上。Vue.prototype.$EventBus = new Vue()。在组件出通过this.$EventBus调用。
3.2 在任意A组件发出数据,this.$EventBus.$emit('事件名','数据');
3.3 在任意B组件接收数据,this.$EventBus.$on(‘与A组件定义的事件名保持相同',data => {});
//父组件
<template>
<div id="app">
<child-a></child-a>
<child-b></child-b>
<child-c></child-c>
<div>
<p>{{name }}</p>
<p>{{sex}}</p>
<p>{{age}}</p>
<div>
</div>
</template>
<script>
import child-a from "./components/child-a";
import child-b from "./components/child-b";
import child-c from "./components/child-c";
export default {
name: 'App',
components:{
child-a ,
child-b,
child-c
},
data(){
return {
name : '',
sex: '',
age: ''
}
},
mounted(){
let _this. = this
_this.fromDataChildB()
_this.fromDataChildC()
_this.fromDataChildA()
},
methods:{
//父组件接收来自任意子组件B的发送的数据
fromDataChildB(){
let _this. = this
_this.$EventBus.$on('sendName', (data)=>{
_this.name= data.name
})
},
//父组件接收来自任意子组件C的发送的数据
fromDataChildC(){
let _this. = this
_this.$EventBus.$on('sendSex', (data)=>{
_this.sex= data.sex
})
},
//父组件接收来自任意子组件A的发送的数据
fromDataChildA(){
let _this. = this
_this.$EventBus.$on('sendAge', (data)=>{
_this.age= data.age
})
}
},
destroyed(){
//事件销毁
let _this =this
_this.$EventBus.$off('sendName')
_this.$EventBus.$off('sendSex')
_this.$EventBus.$off('sendAge')
}
}
</script>
//组件child-a
<template>
<div id="childA">
<div>{{age}}</div>
<button @click="toSendChildB"></button>
</div>
</template>
<script>
export default {
name: 'childA',
data(){
return {
age: '',
name : 'xiaoXin',
}
},
mounted(){
let _this. = this
_this.fromDataChildC()
},
methods:{
//接收来自统计C组件发送的数据
fromDataChildC(){
let _this. = this
_this.$EventBus.$on('sendAge', (data)=>{
_this.age= data.age
})
},
//在任意A组件发出数据,this.$EventBus.$emit('事件名','数据');
toSendChildB(){
let _this. = this
_this.$EventBus.$emit('sendName', _this.name)
}
},
destroyed(){
let _this =this
_this.$EventBus.$off('sendAge')
}
}
</script>
//组件child-b
<template>
<div id="childB">
<div>{{name}}</div>
<button @click="toSendChildC"></button>
</div>
</template>
<script>
export default {
name: 'childB',
data(){
return {
name : '',
sex: 'man',
}
},
mounted(){
let _this. = this
_this.fromDataChildA()
},
methods:{
//接收来自统计A组件发送的数据
fromDataChildA(){
let _this. = this
_this.$EventBus.$on('sendName', (data)=>{
_this.name = data.name
})
},
//在任意B组件发出数据,this.$EventBus.$emit('事件名','数据');
toSendChildC(){
let _this. = this
_this.$EventBus.$emit('sendSex', _this.sex)
}
},
destroyed(){
let _this = this
_this.$EventBus.$off('sendName')
}
}
</script>
//子组件child-c
<template>
<div id="childC">
<div>{{sex}}</div>
<button @click="toSendChildA"></button>
</div>
</template>
<script>
export default {
name: 'childC',
data(){
return {
sex: '',
age: '27'
}
},
mounted(){
let _this. = this
_this.fromDataChildB()
},
methods:{
//接收来自统计B组件发送的数据
fromDataChildB(){
let _this. = this
_this.$EventBus.$on('sendSex', (data)=>{
_this.sex= data.sex
})
},
//在任意C组件发出数据,this.$EventBus.$emit('事件名','数据');
toSendChildA(){
let _this. = this
_this.$EventBus.$emit('sendAge', _this.age)
}
},
destroyed(){
let _this = this
_this.$EventBus.$off('sendSex')
}
}
</script>
5.状态管理器Vuex——万能组件间通信:
总结:Vuex实现了一个单向数据流,在全局拥有一个State存放数据,如果需要对state做计算,可以在getters中进行。当组件要更改State中的数据时,必须通过Mutation进行,Mutation同时提供了订阅者模式供外部插件调用获取State数据的更新。而当所有异步操作(常见于调用后端接口异步获取更新数据)或批量的同步操作需要走Action,但Action也是无法直接修改State的,还是需要通过Mutation来修改State的数据。最后,根据State的变化,渲染到视图上。
通信步骤:
1.创建store.js 文件,与main.js文件同级。
2.安装vuex库,在main.js文件里进行引入和注册到vue实例中。
安装:npm install --save vuex
引入:在store.js 中引入vue和vuex ,,
初始化:在store.js 中 Vue.use(vuex)
注册:在main.js 文件引入 store.js ,并注册到vue根实例中
import store from './store/store.js'
new Vue({
el: '#app',
store,
components: { App },
template: '<App/>'
})
3. 创建store模块,
export const store = new Vuex.Store({ //最重要的事就是保存应用的状态
state: { //状态存储,页面状态管理容器对象
num: 0
},
getters: {
doubleNum(state){ //对状态进行计算,state对象读取方法
return state.num* 2
},
},
mutations: {
increment(state){ //state状态改变并做同步提交操做
state.num ++
},
actions: {
submitNum({commit}){ //异步提交mutation中的状态,commit是context下的一个方法
commit('increment')
}
}
})
在组件中调用:
调用原始的状态:this.$store.state.num
调用gettes计算后的状态:this.$store.gettes.doubleNum
调用mutations改变后的状态:this.$store.commit('increment')
调用actions进行异步提交状态:this.$store.dispacth('submitNum')
Vuex与localStorage的配合:vuex 是 vue 的状态管理器,存储的数据是响应式的。但是并不会保存起来,刷新之后就回到了初始状态。具体做法应该在vuex里数据改变的时候把数据拷贝一份保存到localStorage里面,刷新之后,如果localStorage里有保存的数据,取出来再替换store里的state。由于vuex里,我们保存的状态,都是数组,而localStorage只支持字符串,所以需要用JSON转换。我们常用二者的结合做用户登录和用户登出,以及登录状态保留。
vuex最好的用法是模块化Module,将不同的的状态单独处理。减少彼此的耦合度。
本文如果存在错误之处欢迎指出。如有更好的vue.js组件间通信方式感谢指导。感谢观看。