组件间的通讯
1 父子组件间的通讯
例如 要实现以下的效果
1.1 通过标签属性通讯
-
分析
如上图,可以把这个页面分成Add,List,Item三个组件,对于item如果实际评论内容就这些内容自然不用再分组件,确定组成部分后就可以先写html内容,定好结构
- main.js不用动
- 以App.vue作为最大的一层组件,在App.vue中写上如上图的html内容,标签的属性内容后面再说
-
准备组件
为了代码规范对组件引用和定义组件时用的名称应和html标签上的一致
在src下的components文件夹中定义子组件-
Add.vue
Add部分有两个输入和一个点击事件,我们约定数据定义在哪里,对数据的操作,行为也定义在哪里,显然对评论的内容在Add和List都有用到,那么数据应该定义在它们的父组件上,也就是App.vue,那么对于Add,两个输入不用多说,但添加事件就涉及到了组件间的通讯了,因为数据和更新数据的方法都定义在App.vue中。App.vue–start
data() { return { // 数据在哪个组件,更新数据的行为就定义在哪个组件 comments: [ { name: "name1", content: "vue so wanderful1" }, { name: "name2", content: "vue so wanderful2" }, { name: "name3", content: "vue so wanderful3" }, { name: "name4", content: "vue so wanderful4" } ] }; }, methods: { addComment(comment) { // 插在数组的最前面 this.comments.unshift(comment); }, delComment(index) { this.comments.splice(index, 1); } }, components: { Add, List }
App.vue–end
因此这里用到了第一种通讯方式直接在标签的属性上添加,其中comments是数据,addComment和delComment是更新数据的方法,在Add和List组件中,用props进行接收
Add.vue – startprops: { addComment: { type: Function, required: true } }, data() { return { name: "", content: "" }; }, methods: { add() { console.log("提交"); // 取出数据 const { name, content } = this; if (!name || !content) { alert("输入不合法!"); return; } const comment = { name, content }; this.addComment(comment); this.name = ""; this.content = ""; } }
Add.vue – end
然后就可以在Add.vue中调用App.vue中的方法了
List与Add一样 -
1.2 通过自定义事件通讯
如图,代码是List.vue的,这里的delComment是它的父组件,也就是App.vue中传来,从List到Item时可以直接在标签上写@自定义事件名=“要执行的方法”
在Item.vue中,可以通过emit事件分发,触发相应的自定义事件,第一个参数是自定义事件名,第二个传入的参数
2 兄弟组件间的通讯
从以上例子看可以看出,Item若想执行App.vue中的方法,至少App.vue要通过标签传入这个方法到List,如果Item还有子组件,还要层层传递,显然这样设计不合理,遇到这样的情况则需要换通讯方式了
2.1 通过发布订阅模式
发布订阅模式,从名字上看就可以看出个大概,一方发布,另一方订阅,换句话说,就是一方触发,一方调用,因此,App.vue上定义方法,是订阅者,然后其子组件,子组件的子组件等触发,是发布者
使用这个功能要引入pubsub-js