父组件向子组件传递数据是通过prop传递的,子组件传递数据给父组件是通过$emit触发事件来做到的
Vue.component("child",{ data () { return { mymessage:this.message } }, template:` <div> <input type="text" v-model="mymessage" @input="setFather(mymessage)"> </div> `, props:{ message:String }, methods:{ setFather (val){ this.$emit("getChildData",val) } } }) Vue.component("parent",{ data:function () { return { messageFather:"儿子,我是你爸爸啊" } }, template:` <div> <p> this is parentcomponent!</p> <child :message="messageFather" @getChildData="getChildData"></child> </div> `, methods:{ getChildData(val){ console.log(val) } } }) var app = new Vue({ el:"#app", })复制代码
2.$attrs和$listeners
第一种方式处理父子组件之间的数据传输有一个问题:如果父组件A下面有子组件B,组件B下面有组件C,这时如果组件A想传递数据给组件C怎么办呢? 如果采用第一种方法,我们必须让组件A通过prop传递消息给组件B,组件B在通过prop传递消息给组件C;要是组件A和组件C之间有更多的组件,那采用这种方式就很复杂了。Vue 2.4开始提供了$attrs和$listeners来解决这个问题,能够让组件A之间传递消息给组件C
<script> Vue.component("childs",{ data() { return{ mymessages:"我可能要接受到来自我爷爷的消息" } }, template:` <div> <p>我是儿子的儿子</p> <input type="text" v-model="$attrs.messageChilds" @input="getGrandChild($attrs.messageChilds)"> </div> `, methods:{ getGrandChild(val){ this.$emit("getGrandChild",val) } } }) Vue.component("child",{ data () { return { mymessage:this.message } }, template:` <div> <input type="text" v-model="mymessage" @input="setFather(mymessage)"> <childs v-bind="$attrs" v-on="$listeners"></childs> </div> `, props:{ message:String }, methods:{ setFather (val){ this.$emit("getChildData",val) } } }) Vue.component("parent",{ data:function () { return { messageFather:"儿子,我是你爸爸啊", messageGrandFather:"孙子我是你爸爸啊" } }, template:` <div> <p> this is parentcomponent!</p> <child :messageChilds="messageGrandFather" :message="messageFather" @getChildData="getChildData" @getGrandChild="getGrandChild"></child> </div> `, methods:{ getChildData(val){ console.log(val) }, getGrandChild(val){ console.log(val) } } }) var app = new Vue({ el:"#app", }) </script>复制代码
此方法是通过想目标的子组件 绑定 v-bind="$attrs" 与 v-listeners; 而子组件过的数据为$.attrs的对象,数据为 $attrs.messageChild,实现数据的接受,而子组件传递给父组件则是通过$meit传递事件来向父组件传递相应的数据.
3. 中央事件总线
上面两种方式处理的都是父子组件之间的数据传递,而如果两个组件不是父子关系呢?这种情况下可以使用中央事件总线的方式。新建一个Vue事件bus对象,然后通过bus.$emit触发事件,bus.$on监听触发的事件。
<script> Vue.component("brotherb",{ data () { return { mymessageBrotherB:"我是brotherb", brothera:'' } }, template:` <div> <p>{{mymessageBrotherB}}</p> <p>{{brothera}}</p> </div> `, props:{ message:String, }, mounted(){ bus.$on('globalEvent',(val)=>{ this.brothera=val }) } }) Vue.component("brothera",{ data:function () { return { messageBrotherA:"我是brotherA", mymessage:"你好 ,brotherB" } }, template:` <div> <p>{{messageBrotherA}}</p> <input type="text" v-model="mymessage" @input="passData(mymessage)"> </div> `, methods:{ passData(val){ bus.$emit("globalEvent",val) } } }) //中央事件总线 const bus=new Vue(); const app = new Vue({ el:"#app", }) </script>复制代码
首先我们或创建一个 bus实例, 父组件在mthods方法中,通过bus.$emit()中传递事事件携带参数,然后兄弟组件mounted钩子函数中 通过bus.$on()接受事件和方法.
4. provide和inject
父组件中通过provider来提供变量,然后在子组件中通过inject来注入变量。不论子组件有多深,只要调用了inject那么就可以注入provider中的数据。而不是局限于只能从当前父组件的prop属性来获取数据,只要在父组件的生命周期内,子组件都可以调用。
<script> Vue.component("child",{ inject:['for'], data () { return { mymessage:"我是儿子", messageFather:this.for } }, template:` <div> <p>{{mymessage}}</p> {{messageFather}} </div> `, mounted(){ } }) Vue.component("parent",{ data:function () { return { mymessage:"我是父亲" } }, provide:{ for:"你好儿子啊" }, template:` <div> <p>{{mymessage}}</p> <child></child> </div> `, methods:{ } }) const app = new Vue({ el:"#app", }) </script>复制代码
5. v-model
父组件通过v-model传递值给子组件时,会自动传递一个value的prop属性,在子组件中通过this.$emit(‘input',val)自动修改v-model绑定的值
Vue.component("child",{ props:{ value:String }, data () { return { mymessage:this.value, } }, template:` <div> <input type="text" v-model="mymessage" @change="changeValue"> </div> `, mounted(){ }, methods:{ changeValue() { this.$emit('input',this.mymessage) } } }) Vue.component("parent",{ data:function () { return { message:"son", } }, template:` <div> <p>{{message}}</p> <child v-model="message"></child> </div> `, methods:{ } }) const app = new Vue({ el:"#app", }) </script>复制代码
6. $parent和$children
<script> Vue.component("child",{ data () { return { mymessage:"我是儿子", } }, template:` <div> <input type="text" v-model="mymessage" @change="changeParent"> </div> `, mounted(){ }, methods:{ changeParent () { this.$parent.message=this.mymessage } } }) Vue.component("parent",{ data:function () { return { message:"我是父亲", } }, template:` <div> <p>{{message}}</p> <button @click="changeBtn">改变儿子</button> <child></child> </div> `, methods:{ changeBtn () { this.$children[0].mymessage="hello" } } }) const app = new Vue({ el:"#app", }) </script>复制代码
父组件通过methods事件 通过事件 触发 this.$children[1].message="hello"来向子组件中传递值,1为父组件中第一个子组件,
子组件通过this.$parent.message=this.mymessage来修改 父组件中message 的值.
7. vuex处理组件之间的数据交互
如果业务逻辑复杂,很多组件之间需要同时处理一些公共的数据,这个时候才有上面这一些方法可能不利于项目的维护,vuex的做法就是将这一些公共的数据抽离出来,然后其他组件就可以对这个公共数据进行读写操作,这样达到了解耦的目的。