文章目录

  • 一、案例概述
  • 二、代码
    • 准备工作:
    • 案例1.1:父组件向子组件传值(或者叫:子组件使用父组件属性),采用v-bind方式实现
    • 案例1.2:子组件向父组件传值(或者叫:子组件调用父组件方法),修改父组件属性,采用$emit和v-on(或者叫@自定义事件)方式实现
    • 案例1.3:父组件调用子组件方法,修改子组件属性值,采用$refs方式实现
    • 案例1.4:父组件直接修改子组件属性值,采用$refs方式实现
    • 案例2.1:平行组件之间通信:Student2组件内打印展示Student1组件传递过来的属性,采用v-bind方式实现
    • 案例2.2:平行组件之间通信:Student2组件内调用Student1组件方法修改Student1组件属性,采用\$refs和v-on(或者叫@自定义事件)方式实现
    • 案例2.3:平行组件之间通信:Student2组件内打印展示Student1组件传递过来的属性,采用“全局事件总线”实现
    • 案例2.4:平行组件之间通信:Student2组件内打印展示Student1组件传递过来的属性,采用“消息订阅与发布”实现
    • 案例2.5:平行组件之间通信:Student1组件和Student2组件共同读取vuex共享数据,并实现修改vuex数据,采用“vuex方式”实现
    • 案例3.1:嵌套父子组建通信,实现父组件一次性给所有子孙组件传值,采用“provide/inject”方式
    • 案例4.1:获取父 / 子组件实例,采用“$parent / $children与 ref”方式
  • 三、html项目页面实现平行组件通信案例
  • 四、使用方式总结
  • 本人其他相关文章链接

一、案例概述

说明点1:我使用vue-cli也就是脚手架创建的vue项目,即模拟真实项目创建School.vue组件文件,通过组建引入方式练习,而不是在html页面中引入vue.js练习。

说明点2:vue我目前只学习到组件,所以通信方式较单一,如果想多方式实现请查看下面别人的文章 vue组件间通信六种方式(完整版)

说明点3:该案例练习包含两大分类

第一类:父子组件之间通信

  • 案例1.1:父组件向子组件传值(或者叫:子组件使用父组件属性),采用v-bind方式实现
  • 案例1.2:子组件向父组件传值(或者叫:子组件调用父组件方法),修改父组件属性,采用$emit和v-on(或者叫@自定义事件)方式实现
  • 案例1.3:父组件调用子组件方法,修改子组件属性值,采用$refs方式实现
  • 案例1.4:父组件直接修改子组件属性值,采用$refs方式实现

第二类:平行组件间之间通信

注意点1:默认情况两个子组件之间是无法直接通信的,所以需要构建父组件,通过把父组件当做一个传递桥梁进而实现平行组件间之间通信。(即“子组件student1”把数据传递给“父组件school”,然后“父组件school”再把数据传递给“子组件student2”使用)

  • 案例2.1:平行组件之间通信:Student2组件内打印展示Student1组件传递过来的属性,采用v-bind方式实现
  • 案例2.2:平行组件之间通信:Student2组件内调用Student1组件方法修改Student1组件属性,采用$refs和v-on(或者叫@自定义事件)方式实现
  • 案例2.3:平行组件之间通信:Student2组件内打印展示Student1组件传递过来的属性,采用“全局事件总线”实现
  • 案例2.4:平行组件之间通信:Student2组件内打印展示Student1组件传递过来的属性,采用“消息订阅与发布”实现
  • 案例2.5:平行组件之间通信:,Student1组件和Student2组件共同读取vuex共享数据,并实现修改vuex数据,采用“vuex方式”实现

第三类:provide/inject,嵌套父子组建通信

  • 案例3.1:嵌套父子组建通信,实现父组件一次性给所有子孙组件传值,采用“provide/inject”方式

第四类:$parent / $children与 ref,获取父 / 子组件实例

  • 案例4.1:获取父 / 子组件实例,采用“$parent / $children与 ref”方式

二、代码

准备工作:

模拟真实项目目录准备如下:图1红框部分为模拟项目使用的必须文件,图2整体流程图如下,

图1

图2

index.html 创建首页

<!DOCTYPE html>
<html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1.0"><link rel="icon" href="<%= BASE_URL %>favicon.ico"><title><%= htmlWebpackPlugin.options.title %></title></head><body><noscript><strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body>
</html>

App.vue 创建App组件,它是所有组件的根部爸爸

<template><div><img alt="Vue logo" src="./assets/logo.png"><hr><School></School></div>
</template><script>
import School from './components/School'export default {name: 'App',components: {School}
}
</script><style>
#app {font-family: Avenir, Helvetica, Arial, sans-serif;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;text-align: center;color: #2c3e50;margin-top: 60px;
}
</style>

main.js 程序主入口,用来绑定id=App的div标签

import Vue from 'vue'
import App from './App.vue'Vue.config.productionTip = falsenew Vue({render: h => h(App),template:`<App></App>`
}).$mount('#app')

案例1.1:父组件向子组件传值(或者叫:子组件使用父组件属性),采用v-bind方式实现

采用v-bind方式实现

注意点1:
语法:父组件配置v:bind传值,子组件配置props:{}接收
大白话讲:父组件通过使用子组件标签,在内部配置v:bind指令传属性,也就是:number=“count” :ids="arr"等等,而子组件通过配置props:{}来接收父组件传递过来的属性

父组件School.vue

<template><div>  <student1 :number="count" :ids="arr" :person="p" ></student1></div>
</template><script>
import Student1 from './Student1'export default {name: "School",components: {Student1},data() {return {count: 5,arr: [1, 2, 3],p: {username: "zhangsan", age: 23}}}
}
</script><style scoped></style>

子组件Student1.vue

<template><div><h1>案例1.1:父组件向子组件传值(或者叫:子组件使用父组件属性):</h1><p>这是学生1子组件</p><p>学生1子组件的属性size:{{size}}</p><p>父组件传递过来的属性值:{{number}}--{{ids}}--{{person}}</p>    </div>
</template><script>
export default {name: "Student1",data() {return {size:110}},//给组件添加属性 -》 是组件用来接收父组件数据对象的props: {//父传子属性:普通属性numbernumber: null,//父传子属性:数组属性idsids: [],//父传子属性:对象属性personperson: {} }
}
</script><style scoped></style>

页面展示效果

案例1.2:子组件向父组件传值(或者叫:子组件调用父组件方法),修改父组件属性,采用$emit和v-on(或者叫@自定义事件)方式实现

采用$emit和v-on(或者叫@自定义事件)方式实现

注意点1:

语法:子组件配置 $emit传值, 父组件配置 v-on 接收。
大白话讲:父组件使用子组件标签时配置v-on指令接收子组件传递过来的属性,也就是@receivePCount="add(arguments)",而子组件配置this.$emit()来触发调用函数并传参给父组件

注意点2:

问题:子组件调用父组件方法时传参,父组件如何接收到参数值?

1)如果只传递一个参数,比如:this.$emit('update-count', "你是谁?");
那么子组件标签形参可不带参数或者形参使用$event
比如<child v-on:update-count="changeCount"></child>
或者<child v-on:update-count="changeCount($event)"></child>
那么父组件(vue实例)方法中通过value即可接收参数比如:  changeCount:function(value)2)如果传递多个参数,比如: this.$emit('update-count', "ldz",29);,
那么子组件标签形参请使用arguments
<child v-on:update-count="changeCount(arguments)"></child>
那么父组件(vue实例)通过value[index]即可接收参数,比如:
changeCount:function(value){
console.log("@" + value[0]);
console.log("@" + value[1]);

父组件School.vue

<template><div><p>父组件属性count:{{count}}--msg:{{msg}}</p><student1  @receivePCount="add(arguments)" ></student1></div>
</template><script>
import Student1 from './Student1'export default {name: "School",components: {Student1},data() {return {count: 5,msg:""}},methods: {//子组件向父组件通信add(args){this.count += args[0];this.msg += args[1];}    }
}
</script><style scoped></style>

子组件Student1.vue

<template><div>    <h1>案例1.2:子组件向父组件传值(或者叫:子组件调用父组件方法),修改父组件属性count,msg值</h1><button @click="childTransmitParentProperty()">子组件内调用父组件方法修改count,msg值</button></div>
</template><script>export default {name: "Student1",data() {return {}},methods: {//案例1.2:父组件传递子组件方法(或者叫:子组件调用父组件方法修改父组件属性值)childTransmitParentProperty() {this.$emit("receivePCount", 70, "你是个der")}}
}
</script><style scoped></style>

页面展示效果

点击前:

点击后:

案例1.3:父组件调用子组件方法,修改子组件属性值,采用$refs方式实现

采用$refs方式实现

注意点1:
语法:父组件使用子组件标签时配置ref=“student1”,父组件方法中this.$refs.student1= 子组件的vue实例
大白话讲:在父组件中想调用子组件的属性或者方法,需要获取子组件的vue实例,通过ref标签即可获取

父组件School.vue

<template><div><student1 ref="student1"></student1><h2>案例1.3:父组件调用子组件方法,修改子组件属性值</h2><button @click="pRemSize()">父组件调用子组件方法减少size值</button><hr></div>
</template><script>
import Student1 from './Student1'export default {name: "School",components: {Student1},data() {return {}},methods: {    //案例1.3:父组件直接使用子组件方法,修改子组件属性值pRemSize() {this.$refs.student1.remSize()}   }
}
</script><style scoped></style>

子组件Student1.vue

<template><div><p>这是学生1子组件</p><p>学生1子组件的属性size:{{size}}</p> </div>
</template><script>
export default {name: "Student1",data() {return {size:110}},methods: {remSize() {this.size--;}   }
}
</script><style scoped></style>

页面展示效果

点击前:

点击后:

案例1.4:父组件直接修改子组件属性值,采用$refs方式实现

采用$refs方式实现

注意点1:
语法:父组件使用子组件标签时配置ref=“student1”,父组件方法中this.$refs.student1= 子组件的vue实例
大白话讲:在父组件中想调用子组件的属性或者方法,需要获取子组件的vue实例,通过ref标签即可获取

父组件School.vue

<template><div>   <student1 ref="student1"></student1><h2>案例1.4:父组件直接修改子组件属性值</h2><button @click="parentModifyChildProperty()">父组件直接修改子组件属性size值</button><hr></div>
</template><script>
import Student1 from './Student1'export default {name: "School",components: {Student1},data() {return {}},methods: {   //案例1.4:父组件直接修改子组件属性值parentModifyChildProperty() {this.$refs.student1.size = -1;}   }
}
</script><style scoped></style>

子组件Student1.vue

<template><div><p>这是学生1子组件</p><p>学生1子组件的属性size:{{size}}</p>    </div>
</template><script>
export default {name: "Student1",data() {return {size:110}}
}
</script><style scoped></style>

页面展示效果

点击前:

点击后:

案例2.1:平行组件之间通信:Student2组件内打印展示Student1组件传递过来的属性,采用v-bind方式实现

采用v-bind方式实现

注意点1:默认情况两个子组件之间是无法直接通信的,所以需要构建父组件,通过把父组件当做一个传递桥梁进而实现平行组件间之间通信。(即“子组件student1”把数据传递给“父组件school”,然后“父组件school”再把数据传递给“子组件student2”使用)

父组件School.vue

<template><div>   <student1 ref="student1" @receivePCount="add(arguments)" ></student1><student2 ref="student2" :stu1TransformCount="count" :stu1TransformMsg="msg"></student2></div>
</template><script>
import Student1 from './Student1'
import Student2 from './Student2'export default {name: "School",components: {Student2, Student1},data() {return {count: 5,msg:""}},methods: {//子组件向父组件通信add(args){this.count += args[0];this.msg += args[1];}}
}
</script><style scoped></style>

子组件Student1.vue

<template><div><h2>案例2.1:平行组件之间通信:Student2组件内打印展示Student1组件传递过来的属性</h2><button @click="childTransmitParentProperty()">平行组件Student1发送数据给Student2</button><hr></div>
</template><script>
export default {name: "Student1",data() {return {}},methods: {    //案例1.2:父组件传递子组件方法(或者叫:子组件调用父组件方法修改父组件属性值)childTransmitParentProperty() {this.$emit("receivePCount", 70, "你是个der")}}
}
</script><style scoped></style>

子组件Student2.vue

<template><div><p>这是子组件学生2</p><p>平行组件通信:接收的学生组件1发过来的数据:{{stu1TransformCount}}--{{stu1TransformMsg}}</p>    </div>
</template><script>
export default {name: "Student2",data() {return {}},props:{stu1TransformCount:null,stu1TransformMsg:null}
}
</script><style scoped></style>

页面展示效果

点击前:

点击后:

案例2.2:平行组件之间通信:Student2组件内调用Student1组件方法修改Student1组件属性,采用$refs和v-on(或者叫@自定义事件)方式实现

采用$refs和v-on(或者叫@自定义事件)方式实现

注意点1:默认情况两个子组件之间是无法直接通信的,所以需要构建父组件,通过把父组件当做一个传递桥梁进而实现平行组件间之间通信。(即“子组件student1”把数据传递给“父组件school”,然后“父组件school”再把数据传递给“子组件student2”使用)

父组件School.vue

<template><div><student1 ref="student1"></student1>   <student2 ref="student2"  @receiveStu1Method="invokeStu1Method"></student2></div>
</template><script>
import Student1 from './Student1'
import Student2 from './Student2'export default {name: "School",components: {Student2, Student1},data() {return {}},methods: {   invokeStu1Method() {this.$refs.student1.remSize()}},
}
</script><style scoped></style>

子组件Student1.vue

<template><div><p>这是学生1子组件</p><p>学生1子组件的属性size:{{size}}</p></div>
</template><script>
export default {name: "Student1",data() {return {size:110}},methods: {remSize() {this.size--;}}
}
</script><style scoped></style>

子组件Student2.vue

<template><div><h2>案例2.2:平行组件之间通信:Student2组件内调用Student1组件方法修改Student1组件属性</h2><button @click="invokeStu1Method()">平行组件Student2调用Student1方法,修改size值</button><hr></div>
</template><script>
export default {name: "Student2",data() {return {}},props:{receiveStu1Method:function () {}},methods:{invokeStu1Method() {this.$emit("receiveStu1Method")}}
}
</script><style scoped></style>

页面展示效果

点击前:

点击后:

案例2.3:平行组件之间通信:Student2组件内打印展示Student1组件传递过来的属性,采用“全局事件总线”实现

采用“全局事件总线”实现

说明:使用“全局事件总线”只需要2个平行组件通信就行,跟v-bind方式区别在于,v-bind方式需要使用父组件当一个传递者,而“全局事件总线”不需要传递者这么个角色。

注意点1:

问题:“全局事件总线”需要哪些特点?

答案:
1)被所有组件(vc、vm)能够看得见
2)能够调用$on、$emit、$off

注意点2:

问题:Vue原型对象上面的所有属性和方法是给谁用的?

答案:是给所有的vm和vc使用的

注意点3:

问题:为什么定义“全局事件总线”要放在main.js文件中?

答案:因为哪里引入Vue,哪里才会去定义“全局事件总线”

注意点4:

问题:为什么定义“全局事件总线”要放在beforeCreate的钩子函数中?

答案:原因1,beforeCreate钩子函数里this指代new出来的vm,原因2,在beforeCreate钩子函数里模板还没解析,数据监测和数据代理也还没完成呢。也就是说借助这个beforeCreate钩子函数你把想做的事儿做好了,原型上该放的放好了,随后模板开始解析,等组件执行的时候你该放的都放好了,后续才做都不会产生影响。

注意点5:

问题:如何避免在使用“全局事件总线”时自定义函数名重名使用问题?比如组件1使用自定义函数名叫demo,那组件2不全文搜索也使用了自定义函数名也叫demo,这就混了

答案:真实项目中src目录下创建一个config文件夹,里面创建个constants常量文件,里面用来定义要使用的自定义函数名,方便别人查看并避免重名问题。

注意点6:

问题:为什么要在组件销毁之前,把“全局事件总线”中定义的自定义事件函数解绑?那“知识点3.13自定义事件”中咋没说解绑的事儿呢?

答案:“知识点3.13自定义事件”中组件销毁了== vc销毁了,vc销毁了自定义事件也就销毁了,而“全局事件总线”中定义的自定义函数是一直存在的,哪怕使用组件销毁了,但是Vue实力定义的“全局事件总线”中还是会存在自定义事件,所以需要在组件销毁之前进行解绑。

注意点7:销毁“全局事件总线”中定义的自定义事件请放在beforeDestroy()钩子中

注意点8:子组件中使用“全局事件总线”时this.$bus.$on()中回调配置要使用箭头函数,不要使用普通函数,箭头函数中this才指代vc,而普通函数中this指代vue实例,因为最终要在school组件上接收平行组件发过来的消息,所以要使用vc,而不是要使用vue实例,因为vue实例不是我们最终要的。

项目结构

完整代码

main.js

//引入Vue
import Vue from 'vue'
//引入App
import App from './App.vue'
//关闭Vue的生产提示
Vue.config.productionTip = false//创建vm
new Vue({el:'#app',render: h => h(App),beforeCreate() {Vue.prototype.$bus = this},
})

App.vue

<template><div id="app"><div><School></School></div></div>
</template><script>import School from "./components/School";export default {name:'App',components:{School},data() {return {}},methods: {}}
</script>

School.vue

<template><div><student1></student1><student2></student2></div>
</template><script>
import Student1 from './Student1'
import Student2 from './Student2'export default {name: "School",components: {Student2, Student1},data() {return {}},methods: {},
}
</script><style scoped></style>

Student1.vue

<template><div class="student"><h2>学生1姓名:{{name}}</h2><h2>学生1性别:{{sex}}</h2><button @click="sendToStudent2">把学生名给School组件</button></div>
</template><script>
export default {name:'Student',data() {return {name:'张三',sex:'男',}},methods: {sendToStudent2(){this.$bus.$emit('hello',this.name, this.sex)}},
}
</script><style lang="less" scoped>
.student{background-color: pink;padding: 5px;margin-top: 30px;
}
</style>

Student2.vue

<template><div class="school"><h2>学生2名称:{{name}}</h2><h2>学生2地址:{{address}}</h2></div>
</template><script>
export default {name:'School',data() {return {name:'李四',address:'女',}},mounted() {this.$bus.$on('hello',(arguements)=>{console.log('我是Student2组件,收到了数据:',arguements[0], arguements[1])})},beforeDestroy() {this.$bus.$off('hello')},
}
</script><style scoped>
.school{background-color: skyblue;padding: 5px;
}
</style>

结果展示

案例2.4:平行组件之间通信:Student2组件内打印展示Student1组件传递过来的属性,采用“消息订阅与发布”实现

使用步骤:

采用“消息订阅与发布”实现

注意点0:这块知识点如果不太懂,可以查看我自己总结的博客:vue2知识点:消息订阅与发布

注意点1:由于“消息订阅与发布”可依赖的第三方太多了,这里使用pubsub-js

注意点2:使用语法

消息订阅语法

import pubsub from 'pubsub-js'mounted() {this.pubId = pubsub.subscribe('hello',(msgName,data)=>{// console.log('有人发布了hello消息,hello消息的回调执行了',msgName,data)
})
},
beforeDestroy() {// this.$bus.$off('hello')pubsub.unsubscribe(this.pubId)
}

消息发布语法

import pubsub from 'pubsub-js'pubsub.publish('hello',666)

注意点3:取消订阅方式和“全局事件总线”不同,取消订阅指定订阅返回的id,且每次返回的id都不同,而“全局事件总线”指定的是“自定义事件名称”

注意点4:订阅回调配置一定要使用箭头函数或者外部定义方法,在订阅中引用也行,千万不要使用普通函数,因为普通函数中this不指代vc,而是undefine,这一点跟“全局事件总线”中的注意点8很像,但还是略有不同

注意点5:消息订阅会接收到2个参数,第1个参数为消息名称,第2个参数才是传递过来的值,如写法1,但是实际msgName参数1他跟用不到它,所以可使用下划线“_”占个位,如写法2

写法1:

this.pubId = pubsub.subscribe('hello',(msgName,data)=>{// console.log('有人发布了hello消息,hello消息的回调执行了',msgName,data)
})

写法2:

this.pubId = pubsub.subscribe('hello',(_,data)=>{// console.log('有人发布了hello消息,hello消息的回调执行了',_,data)
})

注意点6:箭头函数中的名称(msgName,data)=>{}可以随便写,但是避免使用使用关键字名字

注意点7:如果想传递多个参数,需使用{}
发送方

sendToStudent2(){pubsub.publish('hello',{name:this.name, sex:this.sex})
}

接收方

mounted() {this.pubId = pubsub.subscribe('hello',(msgName, object)=>{console.log('有student1平行组件发布了hello消息,hello消息的回调执行了:',object.name, object.sex)})}

项目结构

完整代码

main.js

//引入Vue
import Vue from 'vue'
//引入App
import App from './App.vue'
//关闭Vue的生产提示
Vue.config.productionTip = false//创建vm
new Vue({el:'#app',render: h => h(App)
})

App.vue

<template><div id="app"><div><School></School></div></div>
</template><script>import School from "./components/School";export default {name:'App',components:{School},data() {return {}},methods: {}}
</script>

School.vue

<template><div><student1></student1><student2></student2></div>
</template><script>
import Student1 from './Student1'
import Student2 from './Student2'export default {name: "School",components: {Student2, Student1},data() {return {}},methods: {},
}
</script><style scoped></style>

Student1.vue

<template><div class="student"><h2>学生1姓名:{{name}}</h2><h2>学生1性别:{{sex}}</h2><button @click="sendToStudent2">把学生名给School组件</button></div>
</template><script>
import pubsub from 'pubsub-js';export default {name:'Student',data() {return {name:'张三',sex:'男',}},methods: {sendToStudent2(){pubsub.publish('hello',{name:this.name, sex:this.sex})}},
}
</script><style lang="less" scoped>
.student{background-color: pink;padding: 5px;margin-top: 30px;
}
</style>

Student2.vue

<template><div class="school"><h2>学生2名称:{{name}}</h2><h2>学生2地址:{{address}}</h2></div>
</template><script>
import pubsub from 'pubsub-js';export default {name:'School',data() {return {name:'李四',address:'女',}},mounted() {this.pubId = pubsub.subscribe('hello',(msgName, object)=>{console.log('有student1平行组件发布了hello消息,hello消息的回调执行了:',object.name, object.sex)})},beforeDestroy() {pubsub.unsubscribe(this.pubId)},
}
</script><style scoped>
.school{background-color: skyblue;padding: 5px;
}
</style>

结果展示

案例2.5:平行组件之间通信:Student1组件和Student2组件共同读取vuex共享数据,并实现修改vuex数据,采用“vuex方式”实现

使用步骤:






注意点0:如果vuex相关知识点不太了解,可以查看我自己总结的博客进行了解学习。
vue2知识点:理解vuex、安装vuex、搭建vuex环境

项目目录

main.js

//引入Vue
import Vue from 'vue'
//引入App
import App from './App.vue'
//关闭Vue的生产提示
Vue.config.productionTip = false
//引入store
import store from './store'//创建vm
new Vue({el:'#app',render: h => h(App),store
})

App.vue

<template><div id="app"><School></School></div>
</template><script>
import School from "./components/School";export default {name:'App',components: {School}
}
</script>

index.js

//该文件用于创建Vuex中最为核心的store
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//应用Vuex插件
Vue.use(Vuex)//准备actions——用于响应组件中的动作
const actions = {//响应式组件中加的动作jia(context, value) {context.commit('JIA', value);}
}
//准备mutations——用于操作数据(state)
const mutations = {//执行加JIA(state, value) {state.sum += value;}
}
//准备state——用于存储数据
const state = {sum:0
}//创建并暴露store
export default new Vuex.Store({actions,mutations,state,
})

School.vue

<template><div><Student1></Student1><hr><Student2></Student2></div>
</template><script>
import Student1 from './Student1'
import Student2 from './Student2'export default {name: "School",components:{Student1, Student2}
}
</script>

Student1.vue

<template><div><h1>我是子组件Student1</h1><h2>读取vuex中的共享数据sum值:{{$store.state.sum}}}</h2><button @click="add">点击sum+1</button></div>
</template><script>
export default {name: "Student1",methods:{add() {this.$store.dispatch("jia", 1);}}
}
</script>

Student2.vue

<template><div><h1>我是子组件Student2</h1><h2>读取vuex中的共享数据sum值:{{$store.state.sum}}}</h2><button @click="add">点击sum+2</button></div>
</template><script>
export default {name: "Student2",methods:{add() {this.$store.dispatch("jia", 2);}}
}
</script>

结果展示

案例3.1:嵌套父子组建通信,实现父组件一次性给所有子孙组件传值,采用“provide/inject”方式

Vue2.2.0新增API,这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。一言而蔽之:祖先组件中通过provider来提供变量,然后在子孙组件中通过inject来注入变量。
provide / inject API 主要解决了跨级组件间的通信问题,不过它的使用场景,主要是子组件获取上级组件的状态,跨级组件间建立了一种主动提供与依赖注入的关系。:

注意点1:provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的属性还是可响应的。仔细看最终案例结果展示username属性传递的是对象,所以是响应式的;而otherNme传递的是普通字符串,是非响应的,因为子组件值未更新。

使用场景:祖先组建一次性给所有子孙组件传递属性。

优点是:节省代码,不需要每个子组件使用v-bind之类的挨个绑定

项目目录,其中School是父组件,Student1是子组建

项目代码

main.js

//引入Vue
import Vue from 'vue'
//引入App
import App from './App.vue'
//关闭Vue的生产提示
Vue.config.productionTip = false//创建vm
new Vue({el:'#app',render: h => h(App),
})

App.vue

<template><div id="app"><School></School></div>
</template><script>
import School from "./components/School";export default {name:'App',components: {School}
}
</script>

School.vue

<template><div><h1>我是嵌套父组件School,我的name属性值为:{{obj.name}}</h1><button @click="modifyName">修改School组件的name值</button><h1>我是嵌套父组件School,我的otherName属性值为:{{otherName}}</h1><button @click="modifyOtherName">修改School组件的otherName值</button><hr><Student1 ref="MyStudent"></Student1></div>
</template><script>
import Student1 from './Student1'export default {name: "School",components:{Student1},data() {return {name: "我是嵌套父组件School",otherName: "小白",obj: {name: "cat"}}},methods:{modifyName() {this.obj.name = "cow";},modifyOtherName() {this.otherName = "小黑";}},provide() {return {otherName: this.otherName,  //此处provice一个普通字符串,测试实现数据的响应式username: this.obj          //此处provice一个对象,测试实现数据的响应式}}
}
</script>

Student1.vue

<template><div><h1>我是子组件Student1</h1><h2>获取嵌套父组件School传过来的对象username值:{{username}}</h2><h2>获取嵌套父组件School传过来的普通字符串otherName值:{{otherName}}</h2></div>
</template><script>
export default {name: "Student1",inject: ["username", "otherName"],data() {return {name: "我是子组件Student1"}}
}
</script>

结果展示

案例4.1:获取父 / 子组件实例,采用“$parent / $children与 ref”方式

  • ref:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例
  • $parent / $children:访问父 / 子实例

注意点1:这两种都是直接得到组件实例,使用后可以直接调用组件的方法或访问数据。

改动地方,School.vue组件中使用子组件Student1 标签中,定义ref属性,同时打印parent和parent和parent和children

<Student1 ref="MyStudent"></Student1>mounted() {console.log("输出子组建Student1的父实例:" ,this.$refs.MyStudent.$parent)console.log("输出父组件School的子实例:" ,this.$children)}

结果展示:
输出子组建Student1的父实例,调用$parent实例结果

输出父组件School的子实例,调用$children实例结果

三、html项目页面实现平行组件通信案例

上面的代码是针对vue-cli创建的vue项目实现组件通信的方案,然而在刚学习vue时都是创建html页面引入vue.js去练习vue技术的,接下来介绍的方案就是针对html页面中组件通信的。

语法:$emit和$on,同一页面中通过创建Event实例去传递使用数据

问题要求:有<v-a>、<v-b>、<v-c>3个子组件,他们三个处于平行关系,用来接收或者组件发过来的消息

子组件中调用Event.$emit(‘asend’, this.ipt)调用
子组件中接收Event.$on(‘bsend’, function (msg) { _this.strb = msg;})

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Vue练习</title><!--引入Vue--><script type="text/javascript" src="../../static/vue/vue.js" ></script>
</head>
<body><!--平行组件间调用属性和方法:问题要求:有<v-a>、<v-b>、<v-c>3个子组件,他们三个处于平行关系,用<v-c>来接收<v-a>或者<v-b>组件发过来的消息子组件中调用Event.$emit('asend', this.ipt)调用子组件中接收Event.$on('bsend', function (msg) {_this.strb = msg;})--><div id="app"><v-a></v-a><hr><v-b></v-b><hr><v-c></v-c></div><template id="a"><div><p>这是a组件</p><button @click="a()">发送a组件</button></div></template><template id="b"><div><p>这是b组件</p><button @click="b()">发送b组件</button></div></template><template id="c"><div><p>这是c组件</p><p>接收的a数据:{{stra}}</p><p>接收的b数据:{{strb}}</p></div></template><script type="text/javascript">var Event = new Vue();new Vue({el: '#app',data: {},methods: {},components: {"v-a": {template: "#a",data() {return {ipt:"我是a组件发过来数据"}},methods: {a() {Event.$emit('asend', this.ipt)}}},"v-b": {template: '#b',data() {return{ipt:"我是b组件发过来数据"}},methods: {b() {Event.$emit('bsend', this.ipt)}}},"v-c": {template: '#c',data() {return {stra:"",strb:""}},mounted() {var _this = this;//接收a数据Event.$on('asend', function (msg) {_this.stra = msg;})//接收b数据Event.$on('bsend', function (msg) {_this.strb = msg;})}}}})</script>
</body>
</html>

点击按钮前:

点击按钮后:

四、使用方式总结

常见使用场景可以分为三类:

父子通信:

  • 父向子传递数据是通过 props,子向父是通过$emit和$on或者v-on
  • 多级父子组件嵌套想获取父/子的vc实例,请使用$parent / $children
  • ref 也可以访问组件实例
  • 父组件一次性给所有子孙组件传递属性,请使用provide / inject
  • $attrs/$listeners不常用,可忽略或者了解即可

平行组件通信:

  • 全局事件总线,请使用Bus(推荐使用),优点vue开发完全友好支持,适用于很小项目或者练习
  • 消息订阅发布,属于使用第三方(不太推荐使用)
  • vuex,共享数据(推荐使用),同样是vue开发完全友好支持,vuex和全局事件总线区别是:大项目请使用vuex,因为共享数据多,小范围共享数据请使用全局事件总线Bus

跨级通信:

  • Bus
  • Vuex
  • provide / inject API
  • $attrs/$listeners

本人其他相关文章链接

1.《基础篇第1章:vue2简介》包含Vue2知识点、个人总结的使用注意点及碰到的问题总结

2.《基础篇第2章:vue2基础》包含Vue2知识点、个人总结的使用注意点及碰到的问题总结

3.《进阶篇第3章:vue进阶-组件》包含组件、自定义事件、插槽、路由等等扩展知识点

4.《基础篇第4章》:使用vue脚手架创建项目

5.vue2知识点:数据代理

6.vue2知识点:事件处理

7.vue2知识点:列表渲染(包含:v-for、key、取值范围、列表过滤、列表排序、vue监视对象或数组的数据改变原理、总结vue数据监测)

8.vue2知识点:计算属性与监听属性

9.vue2知识点:生命周期(包含:生命周期介绍、生命周期钩子、整体流程图详解)

10.vue2知识点:非单文件组件和单文件组件

11.vue2知识点:组件is属性

12.vue2知识点:组件模板定义

13.vue2知识点:组件的props属性、非props属性、props属性校验

14.vue2知识点:组件自定义事件

15.vue2知识点:组件插槽分发

16.vue2知识点:动态组件

17.vue2知识点:混入

18.vue2知识点:浏览器本地缓存

19.vue2知识点:全局事件总线(GlobalEventBus)

20.vue2知识点:消息订阅与发布

21.vue2知识点:nextTick语法

22.vue2知识点:Vue封装的过度与动画

23.vue2知识点:路由

24.vue2知识点:vm调用待$命令介绍

25.vue组件通信案例练习(包含:父子组件通信及平行组件通信)

26.vue表单案例练习:vue表单创建一行数据及删除数据的实现与理解

27.vue2基础组件通信案例练习:待办事项Todo-list案例练习

28.vue2基础组件通信案例练习:把案例Todo-list改写成本地缓存

29.vue2基础组件通信案例练习:把案例Todo-list改成使用自定义事件

30.vue2基础组件通信案例练习:把案例Todo-list改成使用全局事件总线

31.vue2基础组件通信案例练习:把案例Todo-list改成使用消息订阅与发布

32.vue2基础组件通信案例练习:把案例Todo-list新增编辑按钮

33.vue2基础组件通信案例练习:把案例Todo-list改成使用动画与过度

34.学习vue2遇到过的问题及个人总结

vue组件通信案例练习(包含:父子组件通信及平行组件通信)相关推荐

  1. Android与uni-app 互相通信案例(包含源代码)

    一.背景 在uni-app开发过程中,有时候会遇到uni-app插件或者提供的api对硬件操作不太友好,需要使用原生Android开发对应模块,为了使得双方通信方便,特意封装了一个接口,可实现Andr ...

  2. Vue第七章:项目环境配置及单文件组件 vue脚手

    第七章:项目环境配置及单文件组件 vue脚手架 回顾: 组件之间的通信 父传子:正向传递 vue允许 自动触发 ​ props ​ 1.先在子组件中定义期待的属性名和类型 ​ 2.在父组件中调用子组件 ...

  3. 三菱fx-5u轴定位,Modbus RTU RS-485与测微计通信案例

    三菱fx-5u轴定位,Modbus RTU RS-485与测微计通信案例 ,包含编程软件,plc和维伦触摸屏程序,plc地址规划表,手册,轴定位和Modbus通信视频教程,设备运行视频等. plc程序 ...

  4. 四、Vue组件化开发学习笔记——父子组件通信,父级向子级传值(props),子级向父级传值(自定义事件),slot插槽

    一.父子组件的通信 在上一篇博文中,我们提到了子组件是不能引用父组件或者Vue实例的数据的. 但是,在开发中,往往一些数据确实需要从上层传递到下层: 比如在一个页面中,我们从服务器请求到了很多的数据. ...

  5. vue -- watch侦听器与父子组件间通信

    watch侦听器 方式一 1.默认有两个参数 newValue与oldValue 2.如果是对象类型那么拿到的是代理对象 如果要进行深度监听 需要加上 deep : true 如果想要第一次渲染直接执 ...

  6. 组件通信、传值(父子、爷孙、多层级)(prop、$emit、provide、inject)(vue)

    问题: 组件之间的通信无非就那种:兄弟组件间.父子组件间.爷孙(多层级间),兄弟组件之间通信我前面的文章已经讲过(点击此链接: 兄弟组件:(38条消息) 兄弟组件通信(vue-bus)(vue)_秃秃 ...

  7. 「后端小伙伴来学前端了」关于 Vue中 Slot 插槽的使用,实用且也是组件中必会的一个知识,另外也可以实现父子组件之间通信

    前言 插槽可以说是 Vue 中非常重要的一部分吧,在我学习和练习的过程中,当组件搭配着插槽一起使用的时候,会发挥的更好一些.更多时候也会更加方便. 今天介绍Vue中三种插槽吧:默认插槽.具名插槽.作用 ...

  8. 父组件访问子组件中的数据(父子组件通信案例:父组件访问子组件$refs[‘子组件‘],子组件传递数据给父组件(父组件中使用v-model))

    一.需求 二.在父组件upload-cover中: 通过$refs['子组件的ref属性值']就能拿到子组件对象 三.在子组件imgae-list(相对于父组件upload-cover来说,image ...

  9. Vue第二天学习总结—— Vue全家桶之组件化开发(组件化开发思想、组件注册、Vue调试工具用法、组件间数据交互传递、组件插槽、基于组件的案例——购物车)

    (一) 组件化开发思想 1. 现实中的组件化思想体现 组件化即是对某些可以进行复用的功能进行封装的标准化工作 标准:要想组件能够成功组合在一起,每个组件必须要有标准 分治:将不同的功能封装到不同的组件 ...

最新文章

  1. 东南亚Lazada平台3C数码市场概括,手机配件消费电子选品推荐
  2. 在网络中同时使用kfold和使用Dropout(基于Iris数据集)
  3. 企业有了程序员为什么还要用 低代码/无代码
  4. java递归单链表查找中间元素_《数据结构与算法——C语言描述》答案 3.11 查找单链表中的特定元素(递归)...
  5. 2017上海金马五校赛 丢史蒂芬妮 博弈问题
  6. yum 和 rpm安装mysql彻底删除
  7. daatable动态创建
  8. jmeter web服务器协议,【JMeter4.0学习(三)】之SoapUI创建WebService接口模拟服务端以及JMeter测试SOAP协议性能测试脚本开发(示例代码)...
  9. 利用js实现 禁用浏览器后退
  10. linux面试题(填空部分)
  11. Python移动应用开发
  12. PHP视频网站源码 带APP源代码 支持FFMPEG
  13. 惠普台式电脑引导不了系统_惠普电脑装完系统怎么硬盘启动不了怎么办
  14. 计算机word排版素材,WORD基础排版素材
  15. UNICODE和ANSI以及MBCS的问题
  16. java操纵excel文件2
  17. 牺牲一个存储空间的循环队列实现方法
  18. 数字SOC设计之低功耗设计入门(二)——功耗的分析
  19. Xilinx FPGA----ChipScope(硬件仿真 Core inserter方法)
  20. 游戏破解引发盈利模式思考

热门文章

  1. QSPI(QUAD SPI)基本信息
  2. 功能最强大的php框架,【精粹】架构合理+强大的PHP框架再次推荐,傲视群雄~
  3. 评价模型的方法Matthews correlation coefficient (MCC)
  4. mysql 主索引跟辅助索引_MySQL_MySQL索引之主键索引,在MySQL里,主键索引和辅助索 - phpStudy...
  5. 【Linux】Linux 修改主机名
  6. 垂直站爆品站,独立站运营模式怎么选择?
  7. DotNetBar界面按钮设置
  8. SwiftUI 实现一个 iOS 上 Files App 兼容的文件资源管理器
  9. 电商离线数仓项目实战(下)
  10. 自己开水果店步骤,开水果店的流程