Vue组件传参:Vue非父子组件间的传参
前言:
上面知识点的学习,让我们知道了, 数据在组件间的传递,
父组件通过属性将数据传递给子组件,
子组件通过自定义事件将数据传递给父组件

那么问题来了,两个组件不是父子关系的组件,不是父子关系的组件也可能有两种情况:
一种是两个组件是有一个共同父组件的兄弟关系组件,
第二种是两个组件之间没有太大的关系, 甚至要像上追溯好几层才能找到共同的祖先组件.
那么我们就来看看这两种情况,如果处理数据传递
兄弟关系拥有一个共同的父组件, 那么也就是说我们可以在父组件上定义一个数据,假如这两个组件的名称分别为A组件和B组件, 如果希望子组件A的数据传递给B组件, 那么我们可以先将子组件A的数据通过自定义事件将数据传递给父组件, 然后父组件在通过props将数据传递给B组件, 这样我们就达到了将A组件的数据传递给B组件的目标
示例: 将上面todoList示例才分成两个组件
<div id="app"> <!-- 使用组件 --> <first-component @addcomment="addComment"></first-component> <second-component :comments="comments" @deletecomment="deleteComment" ></second-component></div><!-- 组件模板 --><template id="firstComponent"> <div> <input type="text" v-model="comment"> <button @click="handleClick">点击评论</button> </div></template><template id="secondComponent"> <ul> <li v-for="comment,index in comments" :key="index"> <span>{{comment}}</span> <button @click="deleteClick(index)">X</button> </li> </ul></template><script> // 组件选项对象 let firstComponent = { template: `#firstComponent`, data(){ return { comment: '' } }, methods: { handleClick(){ let comment = this.comment.trim(); if(!comment)return this.$emit("addcomment", comment); this.comment = '' } } }; let secondComponent = { props:["comments"], template: `#secondComponent`, methods:{ deleteClick(index){ this.$emit("deletecomment",index) } } } // 实例中注册组件 const vm = new Vue({ el:"#app", data:{ comments: [] }, components: { secondComponent, firstComponent, }, methods:{ addComment(value){ this.comments.push(value) }, deleteComment(index){ this.comments.splice(index,1) } } })</script>利用父组件来处理兄弟组件间的数据传递
用于解决平级组件或者跨级组件之间的通信,因为如果全部用父子组件通信,有的不是父子组件就很繁琐,所以我们利用一个公共的vue实例订阅和发布事件来达到不是父子组件间的通信
其实就是利用方法触发自定义事件 和 监听自定义事件,给自定义事件添加事件处理函数
示例: 修改todoList
<template id="firstComponent"> <div> <input type="text" v-model="comment"> <button @click="handleClick">点击评论</button> </div></template><template id="secondComponent"> <ul> <li v-for="comment,index in comments" :key="index"> <span>{{comment}}</span> <button @click="deleteClick(index)">X</button> </li> </ul></template><script> // 定义一个负责通信的公共vue实例,除了负责组件之间的通信,没有任何实际意义 let eventBus = new Vue(); // 组件选项对象 // 组件一 let firstComponent = { template: `#firstComponent`, data(){ return { comment: '' } }, methods: { handleClick(){ let comment = this.comment.trim(); if(!comment)return eventBus.$emit("addcomment",comment) this.comment = "" } } }; // 组件二 let secondComponent = { template: `#secondComponent`, data(){ return { comments: [] } }, // 创建组件的时候,监听自定义事件 // 注意函数中的this created(){ eventBus.$on("addcomment", (comment) =>{ this.comments.push(comment) }) }, methods:{ deleteClick(index){ this.comments.splice(index,1) } } } // 实例中注册组件 const vm = new Vue({ el:"#app", components: { secondComponent, firstComponent, } })</script>发布/订阅模式很好的帮我们处理了非父子组件间的数据传递.
但是回头在思考一下, 我们需要每次都实例化一个vue来作为我们的总线吗?其实不需要, 如果每次都创建vue实例反而不好, 因为帮我们处理发布/订阅模式的总线一个就好, 那么我们可以如何处理呢,
其实我们可以将这个总线的vue实例绑定为Vue原型上, 这样在每个vue实例上都可以使用这个总线,
修改示例: 将这个用来处理传递数据的的vue实例,绑定到Vue构造函数的原型上
<div id="app"> <!-- 使用组件 --> <first-component></first-component> <second-component></second-component></div><!-- 组件模板 --><template id="firstComponent"> <div> <input type="text" v-model="comment"> <button @click="handleClick">点击评论</button> </div></template><template id="secondComponent"> <ul> <li v-for="comment,index in comments" :key="index"> <span>{{comment}}</span> <button @click="deleteClick(index)">X</button> </li> </ul></template><script> // 将作为总线的vue实例绑定到构造函数上 Vue.prototype.bus = new Vue(); // 组件选项对象 // 组件一 let firstComponent = { template: `#firstComponent`, data(){ return { comment: '' } }, methods: { handleClick(){ let comment = this.comment.trim(); if(!comment)return this.bus.$emit("addcomment",comment) this.comment = "" } } }; // 组件二 let secondComponent = { template: `#secondComponent`, data(){ return { comments: [] } }, // 创建组件的时候,监听自定义事件 // 注意函数中的this created(){ this.bus.$on("addcomment", (comment) =>{ this.comments.push(comment) }) }, methods:{ deleteClick(index){ this.comments.splice(index,1) } } } // 实例中注册组件 const vm = new Vue({ el:"#app", components: { secondComponent, firstComponent, } })</script>除了以上监听事件外, 还有两个处理事件的方法:和.
的行为与一样, 只不过是绑定的事件监听器只会执行一次, 在事件第一次触发完毕后会自动解除事件绑定
方法则是用于移出一个事件监听器.
之前我们讲过ref在普通的DOM元素上使用,获取的是DOM元素,但是如果ref在组件上使用,获取的是组件的实例,
通过ref,我们就可以实现在父组件中调用子组件的方法
<div id="app"> <loading ref="load"></loading></div><template id="myalert"> <div> <h2 v-show="flag">加载中...</h2> </div></template><script> const loading = { data() { return { flag: true } }, template: '#myalert', methods: { hide() { this.flag = false; } } }; var vm = new Vue({ // 根实例 el: '#app', data: { }, components: { loading }, mounted() { // console.log(this.$refs.load) setTimeout(() => { this.$refs.load.hide() }, 2000) } });</script>