乐趣区

Vue组件通信

父子通信

props 和 emit

父组件通过 props 传递数据给子组件,子组件通过 emit 发送事件传递给父组件。

// 父组件
<div>
    <child :data="child" @send="getFromChild"></child>
</div>

data(){
    return{
        toChild: '大儿子',
        fromChild: ''
    }
},
methods: {getFromChild(val){this.fromChild=val}
}
// 子组件
<div @click="toParent">{{data}}</div>

props:[data],
methods: {toParent(){this.$emit('send', '给父亲')
    }
}

v-model

v-model 其实是 props,emit 的语法糖,v-model 默认会解析成名为 value 的 prop 和名为 input 的事件。

// 父组件
<children v-model="msg"></children>
<p>{{msg}}</p>

data(){
    return{msg:'model'}
}
// 子组件
<input :value="value" @input="toInput" />

props: ['value'],
methods: {toInput(e){this.$emit('input', e.target.value)
    }
}

$children 和 $parent

在父组件使用 $children 访问子组件,在子组件中使用 $parent 访问父组件

// 父组件
<child />

data(){
    return {msg: '父组件数据'}
},
methods: {test(){console.log('我是父组件的方法,被执行')
    }
},
mounted(){console.log(this.$children[0].child_msg); // 执行子组件方法
}
// 子组件
<div>{{$parent.msg}}</div>

data(){
    return{child_msg: '子组件数据'}
},
mounted(){
    // 子组件执行父组件方法
    this.$parent.test();}

.sync 方式

在 vue1.x 中是对 prop 进行双向绑定,在 vue2 只允许单向数据流,也是一个语法糖

// 父组件
<child :count.sync="num" />

data(){
    return {num: 0}
}
// 子组件
<div @click="handleAdd">add</div>

data(){
    return {counter: this.count}
},
props: ["count"],
methods: {handleAdd(){this.$emit('update:count', ++this.counter)
    }
}

跨多层次组件通信

依赖注入

可以使用 provide/inject,虽然文档中不推荐直接使用在业务中。
假设有父组件 A,然后有一个跨多层次的子组件 B

// 父组件 A
export default{
    provide: {data: 1}
}
// 子组件 B
export default{inject: ['data'],
    mounted(){
        // 无论跨几层都能获取父组件的 data 属性
        console.log(this.data); // 1
    }
}

$listeners 和 $attrs

$attrs– 包含了父作用域中不作为 prop 被识别 (且获取) 的特性绑定 (class 和 style 除外)。
inheritAttrs– 默认值 true,继承所有父组件属性(除 props),为 true 会将 attrs 中的属性当做 html 的 data 属性渲染到 dom 根节点上
$listeners– 包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器,v-on=”$listeners” 将所有事件监听器指向这个组件的某个特定子元素

// 父组件
<children :child1="child1" :child2="child2" @test1="onTest1"
@test2="onTest2"></children>

data(){
    return {
        child1: 'childOne',
        child2: 'childTwo'
    }
},
methods: {onTest1(){console.log('test1 running')
    },
    onTest2(){console.log('test2 running')
    }
}

// 子组件
<p>{{child1}}</p>
<child v-bind="$attrs" v-on="$listeners"></child>

props: ['child1'],
mounted(){this.$emit('test1')
}

// 孙组件
<p>{{child2}</p>
<p>{{$attrs}}</p>

props: ['child2'],
mounted(){this.$emit('test2')
}

任意组件

可以用 Vuex 或 Event Bus 解决

Event Bus

1. 新建一个 bus.js 文件

import Vue from 'vue';
export default new Vue();

2. 使用它

<div @click="addCart"> 添加 </div>
import Bus from 'bus.js';
export default{
    methods: {addCart(event){Bus.$emit('getTarget', event.target)
        }
    }
}
// 另一组件
export default{created(){
        Bus.$on('getTarget', target =>{console.log(target)
        })
    }
}

Vuex 方式

参考链接:
https://juejin.im/post/5c776e…
https://segmentfault.com/a/11…

退出移动版