vue组件通信的7种方案
props与$emit
父传子通过props,子传父通过emit,单向数据流(可以结合.sync形成双向数据流)
案例
// 父
<template>
<div>
<child @changeText="change" :text="text"></child>
</div>
</template>
<script>
import child from "./child";
export default {
components: {
child
},
data() {
return {
text: "hello"
};
},
methods: {
change(data) {
this.text = data;
}
}
};
</script>
<style scoped></style>
// 子
<template>
<div>
我来自子组件{{ text }}
<button @click="change">修改</button>
</div>
</template>
<script>
export default {
props: {
text: {
type: String,
default: ''
}
},
methods: {
change () {
this.$emit('changeText', 'child')
}
}
}
</script>
<style scoped></style>
provide/inject
https://cn.vuejs.org/v2/api/index.html#provide-inject
提示:provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的属性还是可响应的。
案例
// 父
<template>
<div>
<button @click="change">父修改</button>
<child></child>
</div>
</template>
<script>
import child from './child'
export default {
components: {
child
},
data () {
return {
arr: [
{ name: 'mike' },
{ name: 'john' },
{ name: 'sqe' },
{ name: 'dg' }
],
text: 'name'
}
},
provide: function () {
return {
arr: this.arr,
text: this.text
}
},
methods: {
change () {
this.arr.splice(0, 1, { name: 'mike' })
}
}
}
</script>
<style scoped></style>
// 子
<template>
<div>
<div v-for="item in arr" :key="item.id">{{ item.name }}</div>
{{ text }}
<button @click="change">修改</button>
</div>
</template>
<script>
export default {
inject: ['arr', 'text'],
methods: {
change () {
this.arr.splice(0, 1, { name: 'michale jackson' })
}
}
}
</script>
<style scoped></style>
在 2.5.0+ 的注入可以通过设置默认值使其变成可选项:
const Child = {
inject: {
foo: { default: 'foo' }
}
}
如果它需要从一个不同名字的属性注入,则使用 from 来表示其源属性:
const Child = {
inject: {
foo: {
from: 'bar',
default: 'foo'
}
}
}
与 prop 的默认值类似,你需要对非原始值使用一个工厂方法:
const Child = {
inject: {
foo: {
from: 'bar',
default: () => [1, 2, 3]
}
}
}
eventBus
原理:运用了vue实例上的$emit和$on事件来监听和触发对应的通信
新建一个 eventBus.js文件
import Vue from 'vue'; export default new Vue();
组件中触发事件
Bus.$emit("getUserName", data.username);
组件中监听事件
Bus.$on("getUserName", data => {
this.userName = data;
});
vuex
https://vuex.vuejs.org/zh/guide/state.html
细节不再阐述,文档讲的很详细了,这里列出一些技巧和需要注意的点。
import Vuex from 'vuex'
const store = new Vuex.Store({ ...options })
需要注意的点
1.mutations是同步的,actions是异步的
2.项目较大时,state,getters,mutations和actions分文件,或者按模块来分。
3. 善于利用辅助函数mapState,mapGetters,mapActions,mapMutations 可以减少代码冗余
https://vuex.vuejs.org/zh/api/#mapstate
$attrs/$listeners
https://cn.vuejs.org/v2/api/#vm-attrs
$attrs
vm.$attrs{ [key: string]: string }
概括:$attrs就是接收父组件传值在子组件没有定义的prop属性,可以使用$attr向子组件或者更深层次的子组件传值
这里经常会结合inheritAttrs属性,该属性主要控制组件上的属性

inheritAttrs 默认为true,将会带上如上属性,设置为false将去除
$listeners
vm.$listeners { [key: string]: Function | Array<Function> }
包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件——在创建更高层次的组件时非常有用。
案例
// 父
<template>
<div>
<button @click="change">父修改</button>
<child :arr="arr" :text="text" :name="name" @change="change"></child>
</div>
</template>
<script>
import child from './child'
export default {
components: {
child
},
data () {
return {
arr: [
{ name: 'mike' },
{ name: 'john' },
{ name: 'sqe' },
{ name: 'dg' }
],
text: Math.floor(Math.random() * 10).toFixed(0),
name: 'mike'
}
},
created () {
console.log(this.$data, 'father')
},
methods: {
change () {
console.log('修改')
this.text = Math.floor(Math.random() * 10).toFixed(0)
}
}
}
</script>
<style scoped></style>
// 子
<template>
<div>
child {{ $attrs.text }}{{ $attrs.name }}
<button @click="handleChange">child修改</button>
<demo v-bind="$attrs" v-on="$listeners"></demo>
</div>
</template>
<script>
import demo from './demo'
export default {
components: {
demo
},
props: ['arr'],
data () {
return {}
},
inheritAttrs: false,
mounted () {
console.log(this.$attrs, this.$listeners, 'child')
},
methods: {
handleChange () {
this.$listeners.change()
}
}
}
</script>
<style scoped></style>
// 孙子
<template>
<div>
grandChild {{ $attrs.text }}{{ $attrs.name }}
<button @click="handleChange">grandchild修改</button>
</div>
</template>
<script>
export default {
created () {
console.log(this.$attrs, this.$listeners, 'grand')
},
methods: {
handleChange () {
this.$listeners.change()
}
}
}
</script>
<style scoped></style>

$parent/$children
vm.$parent
父实例,如果当前实例有的话
vm.$children
Array<Vue instance>
案例
// 父
<template>
<div class="home">
{{father}}
<Child/>
</div>
</template>
<script>
import Child from '@/components/Child.vue'
export default {
name: 'home',
components: {
Child
},
data () {
return {
father: 'father'
}
},
mounted () {
console.log(this.$children[0].child) // child
}
}
</script>
// 子
<template>
<div>{{child}}</div>
</template>
<script>
export default {
data () {
return {
child: 'child'
}
},
created () {
console.log(this.$parent.father) // father
}
}
</script>
<style scoped>
</style>
当前实例的直接子组件。需要注意 $children 并不保证顺序,也不是响应式的。如果你发现自己正在尝试使用 $children 来进行数据绑定,考虑使用一个数组配合 v-for 来生成子组件,并且使用 Array 作为真正的来源。
localStorage/sessionStorage/cookie
总结
(包含层层递进情况)

转载请标明出处: