Vue 兄弟组件之间的传参

经过之前的学习,我们已经大致了解到了数据在组件之间的传递

  1. 父组件通过 props 属性将数据传递给子组件
  2. 子组件通过自定义事件将数据传递给父组件

那么我们之前所了解到的都是父子组件之间的数据传递,那么有时候我们就会碰到不是父子关系的组件也需要数据的传递,这个时候我们怎么办呢?

不是父子关系的组件可能会有下面的两种情况:

  1. 两个组件,有一个共同的父组件的兄弟组件.
  2. 两个组件之间并没有太大的关系,甚至要找好几层才能找到共同的祖先组件.

1.兄弟组件之间的数据传递

兄弟关系的组件拥有一个共同的父组件,那么就是说我们可以在父组件上定义一个数据,加入这两个组件分别为 AB ,我们希望子组件 A 的数据传递给 B 组件.

那么我们就可以先将 A 组件中的数据通过自定义事件传递给父组件,然后父组件再通过 props 将数据传递给组件 B ,这样我们就达到了将 A 组件的数据传递给 B 组件的目的.

一个简单的案例:

  <div id="app">
       <one-com :count="count"></one-com>
       <two-com @add = "addNumber"></two-com>
  </div>

   <script>
       let oneCom= ({
           props:["count"],
           template:`
               <div>
                   <p>你点击了{{count}}次</p>
               </div>
           `
       })

       let TwoCom = ({
           template: `
               <button @click = "handleClick">点击+1</button>
           `,
           methods:{
               handleClick() {
                   this.$emit("add")
               }
           }
       })

       let vm = new Vue({
           el:"#app",
           data:{
               count:0,
           },
           methods:{
               addNumber() {
                   this.count++;
                   console.log(222)
               }

           },
           components:{
               oneCom,TwoCom
           }
       })
   </script>

点击组件2中的按钮,组件一中的数据会发生改变.
在这里插入图片描述
上面是一个简单易懂的兄弟组件之间数据传递的案例,下面我们来看一个比较经典的todoList 的案例,先展示传统的写法:

 <!--全部都写在实例化对象中-->
    <div id="app">
        <div>
            <input type="text" v-model = "message">
            <button @click="addBtn">发表</button>
        </div>
        <div>
            <h2>评论内容</h2>
            <ul>
                <li  v-for="(comment,index) in comments" :key="index" >
                    {{comment}}
                    <button @click = "delBtn(index)">X</button>
                </li>

            </ul>
        </div>
    </div>
    <script>
        let vm  = new Vue({
            el :"#app",
            data:{
                message: '',
                comments:[],
            },
            methods:{
                //点击发表,评论区会增加一条内容
                addBtn() {
                    this.comments.push(this.message)
                    this.message = ""
                },
                //点击删除,会删掉对应的评论区内容
                delBtn(index) {
                    // console.log(index);
                    this.comments.splice(index,1)
                }
            }
        })
    </script>

在这里插入图片描述
将它改写为组件的形式,利用的就是兄弟组件之间的数据传递:

    <!--拆分成组件的形式-->
    <div id="app">
        <my-input @add = "addComment"></my-input>
        <show-comment :comments = "comments" @delete = "deleteComment"></show-comment>
    </div>

    <!--发表评论部分组件-->
    <template id="MyInput">
        <div>
            <input type="text" v-model = "message">
            <button @click="addBtn">发表</button>
        </div>
    </template>

    <!--展示评论部分组件-->
    <template id="ShowComment">
        <div>
            <h2>评论内容</h2>
            <ul>
                <li  v-for="(comment,index) in comments" :key="index" >
                    {{comment}}
                    <button @click = "delBtn(index)">X</button>
                </li>
            </ul>
        </div>

    </template>

    <script>
        let MyInput = ({
            template:"#MyInput",
            data(){
                return{
                    message:"",
                }
            },
            methods:{
                addBtn() {
                    let message = this.message.trim();
                    if(message === "") {
                        console.log("请输入合法的评论内容");
                        return;
                    }
                    this.$emit("add",message);
                    this.message = "";
                }
            }

        })

        let ShowComment = ({
            props:["comments"],
            template:"#ShowComment",
            methods:{
                delBtn(index) {
                    //console.log(index)
                    this.$emit("delete",index);
                }
            }
        })

        let vm = new Vue({
            el:"#app",
            data:{
                comments:[],
            },
            methods:{
                addComment(msg) {
                    this.comments.push(msg);
                },
                deleteComment(index){	
                //删除对应的评论
                   this.comments.splice(index,1);             					    		                                 
                }
            },
            components:{
                MyInput,ShowComment
            }
        })
  </script> 

在这个过程中我们利用的是父组件实现的兄弟组件之间的数据传递.

2. Bus/总线/发布订阅模式

用于解决平级组件或者跨级组件之间的通信,因为如果全部用父子组件通信,有的不是父子组件就很繁琐,所以我们利用一个公共的 vue 实例订阅和发布事件来达到不是父子组件间的通信

其实就是利用 $emit() 方法触发自定义事件 和 $on() 监听自定义事件,给自定义事件添加事件处理函数

   <div id="app">
        <one-com ></one-com>
        <two-com ></two-com>
   </div>

    <script>
        Vue.prototype.$bus = new Vue();
        let oneCom= ({
            template:`
                <div>
                    <p>你点击了{{count}}次</p>
                </div>
            `,
            data(){
                return{
                    count:0,
                }
            },
            mounted(){
                console.log(this)
                let This = this
                this.$bus.$on("increment", function(num){
                    console.log(This)
                    This.count+= num
                })
            }
        })

        let TwoCom = ({
            template: `
                <button @click = "handleClick">点击+1</button>
            `,
            methods: {
                handleClick() {
                    this.$bus.$emit("increment",1)
                }
            }
        })

        let vm = new Vue({
            el:"#app",
            components:{
                oneCom,TwoCom
            }
        })
    </script>

通过示例我们机会发现,我们不需要每次都将数据传来传去, 变得复杂.
发布/订阅模式很好的帮我们处理了非父子组件间的数据传递.

但是回头在思考一下, 我们需要每次都实例化一个vue来作为我们的总线吗?其实不需要, 如果每次都创建vue实例反而不好, 因为帮我们处理发布/订阅模式的总线一个就好, 那么我们可以如何处理呢,

其实我们可以将这个总线的vue实例绑定为Vue原型上, 这样在每个vue实例上都可以使用这个总线.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值