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
总结
(包含层层递进情况)

转载请标明出处: