Vue2.0笔记——组件3

非父子组件之间的通信

非父子关系的两个组件之间也需要通信。在简单的场景下,可以使用一个空的 Vue 实例作为事件总线。

这句话呢是官网原话,我们看官网的说明和例子。其通信的方法还是,触发与监听事件的方式,与子向父组件传递数据为相同的元素。也就是$emit方法和$on方法。接下来我们具体看看这个例子。
示例:

//空的Vue实例
var emptyVm = new Vue();

var vm = new Vue({
    el:'#app',
    components:{
        'xiao-x':xiao_x,
        'xiao-y':xiao_y,
        'xiao-z':xiao_z
    }
});

var xiao_x={
    template:'<div><p>组件x:{{name}}</p><button @click="send">传递数据</button></div>',
    data:function(){
        return {
            name:'xiao',
            username:'yao'
        }
    },
    methods:{
        send(){
            emptyVm.$emit('xiao-x',this.name);
        }
    }
}
var xiao_y={
    template:'<div><p>组件y:{{age}}</p><button @click="send">传递数据</button></div>',
    data:function(){
        return {
            age:18
        }
    },
    methods:{
        send(){
            emptyVm.$emit('xiao-y',this.age);
        }
    }
}

var xiao_z={
    template:'<p>组件z:{{name}},{{age}}</p>',
    data:function(){
        return {
            name:'',
            age:''
        }
    }
}

<div id="app">
    <xiao-x></xiao-x>
    <xiao-y></xiao-y>
    <xiao-z></xiao-z>
</div>

运行实例,我们已经把该准备的已经准备好了。
x和y的模板呢,因为不想写那么高的篇幅代码,就是稍微挤一块了,接下来就是点击按钮触发,然后z里监听就好了。

但是需要注意:必须先监听,再触发,才能够监听到,不然当然是接收不到的。所以监听一定是在触发执行前的。

代码:

//x组件的事件方法
methods:{
    send(){
        emptyVm.$emit('xiao-x',this.name);
    }
}
//y的事件方法
methods:{
    send(){
        emptyVm.$emit('xiao-y',this.age);
    }
}
//z,在挂载组件模板实例之后就进行监听,所以需要用的生命周期钩子函数
mounted(){//模板挂载之后执行
    emptyVm.$on('xiao-x', function(name){
        vm.$children[2].name=name;
    });
    emptyVm.$on('xiao-y',age =>{
        this.age=age;
    });
}

好了,如此如此这般这般,就好了。运行案例,单击按钮,可以显示出来。

接下来,解释一下这些代码:

  • 首先呢,三个组件拉出来单独写,没问题吧,声明一个变量,对象赋给它就行
  • 然后就是模板问题,我单独挤一块了,代码多的话还是单独写吧
  • 按钮单击事件触发这个这个这两个事件,给它参数,另一边写上事件名,加上回调函数。
  • 然后,你要想监听必须是在触发前吧,什么时候最早,挂载之后呗,所以整个$on监听,回调函数里跟上实参,就好了。

说明两个问题:

1.就是为什么要空的Vue实例:

主要就是创建一个空的实例作为中转站继而能通过$emit和$on这两个函数来实现,为什么呢,因为,这两个方法是,触发当前实例/监听当前实例的事件,所以你需要一个共同的实例啊,所以搞一个空的实例咯。

2.$on事件方法回调问题:
就例如第一个监听name的,如果你直接this.name=name,你觉得会不会错。之所以这么写肯定是有问题的,但是它不会报错。只不过赋值赋错了,打印一下这个this,通过data属性在某个实例中的方法发现这个this是emptyVm的实例,因为回调函数里的this是新的this,指向emptyVm。所以你需要得到z的组件实例才能复制,所以通过$children得到子实例才能赋值,当然这个$children可能是有问题的,因为官方说它是不保证顺序的,我也不太清楚。
所以你需要使用的是第二种,箭头的方式,它不会在函数中创建一个新的this。
箭头函数的格式是:实参列表 =>{//操作内容}

slot内容分发

原意是,槽,插槽的意思。
有什么用呢,我们先看一下下面的例子。
示例:

<div id="app">
    <my-xiao></my-xiao>
</div>

<template id="xiao">
    <div>
        {{arr.join(' ')}}<br/>
    </div>
</template>

components:{
    'my-xiao':{
        template:'#xiao',
        data:function(){
            return {
                name:'xiao',
                arr:['what','are','you','doing']
            }
        }
    }
}

这个例子看起来也没怎么样,但是呢,你会发现<my-xiao>这个标签内空空如也,是不是想加点文字,可是无论怎么加,都会被模板替换掉的。
1.
这时,就是使用插槽的时候了,它使用<slot></slot>标签来显示,只需将它放在模板中任意为值即可,要注意的是,slot也是一个组件哦,内置的

<div id="app">
    <my-xiao>空空如也 —— 任然</my-xiao>
</div>

<template id="xiao">
    <div>
        {{arr.join(' ')}}<br/>
        <slot></slot><!-- 代替标签内的文字 -->
    </div>
</template>
//或者,当内有内容时显示默认的值
<template id="xiao">
    <div>
        {{arr.join(' ')}}<br/>
        <slot>只有在没有要分发的内容时才会显示。</slot>
    </div>
</template>

2.你更可以在<my-xiao>标签中添加任意代码,如常用的ul,li.同样会显示。

<my-xiao>
        <ul>
            <li>111</li>
            <li>222</li>
            <li>333</li>
            <li>444</li>
        </ul>
</my-xiao>

3.你可以通过<slot></slot>指定某个元素在模板的哪里显示

<my-xiao>
    <ul slot="one">
        <li>111</li>
        <li>222</li>
        <li>333</li>
        <li>444</li>
    </ul>
    <p slot="QianSiXian">你褴褛我彩绘 并肩行过山与水</p>
</my-xiao>

<template id="xiao">
    <div>
        <slot name="QianSiXian"></slot>
        {{arr.join(' ')}}<br/>
        <slot name="one"></slot>
    </div>
</template>

你可以为元素设置slot属性,并随意设置一个值,只需要在slot标签中通过name指定名称即可。

猜你喜欢

转载自blog.51cto.com/zouzhelu/2107003
今日推荐