文章目录
1. props / $emit
父组件给子组件添加属性:msg="msg"
传值,子组件通过props:['msg']
接收;
子组件可以通过this.$emit('changeMsg','Welcome')
向父组件发送事件和数据,
父组件通过 @changeMsg="change"
监听事件和传递过来的数据。
代码
<!-- Parent.vue -->
<template>
<div>
<son :msg="msg" @changeMsg="change" />
</div>
</template>
<script>
import Son from './Son.vue'
export default {
name: 'Parent',
data () {
return {
msg: '你好'
}
},
components: {
Son
},
methods: {
change (msg) {
this.msg = msg
}
}
}
</script>
<!-- Son.vue -->
<template>
<div>
{{ msg }}
<button @click="sendToParent">传递到Parent</button>
</div>
</template>
<script>
export default {
name: 'Son',
props: ['msg'],
methods: {
sendToParent () {
this.$emit('changeMsg', 'Welcome')
}
}
}
</script>
效果
适用于父子组件通信
2. sync / update
v2.3
新增语法糖,会扩展成一个更新父组件绑定值的 v-on
侦听器;
<son :msg.sync="msg" />
子组件update:msg
直接修改数据,父组件无需定义监听事件来接收数据;
适合
基本数据类型
的传递和修改
<!-- Parent.vue -->
<template>
<div>
<son :msg.sync="msg" />
</div>
</template>
<script>
import Son from './Son.vue'
export default {
name: 'Parent',
data () {
return {
msg: '你好'
}
},
components: {
Son
}
}
</script>
<!-- Son.vue -->
<template>
<div>
{{ msg }}
<button @click="sendToParent">传递到Parent</button>
</div>
</template>
<script>
export default {
name: 'Son',
props: ['msg'],
methods: {
sendToParent () {
this.$emit('update:msg', 'Welcome')
}
}
}
</script>
3. provide / inject
父组件通过provide
传值,子组件通过inject:["msg"]
接收,provide
传递的数据, 不仅所有子组件
都可以接收,所有后代组件
均可以通过inject
接收到。
<!-- Parent.vue -->
<template>
<div>
<son />
</div>
</template>
<script>
import Son from './Son.vue'
export default {
name: 'Parent',
provide () {
return {
pdata: this
}
},
data () {
return {
msg: '你好'
}
},
components: {
Son
}
}
</script>
<!-- Son.vue -->
<template>
<div>
{{ text }}
<button @click="sendToParent">修改</button>
</div>
</template>
<script>
export default {
name: 'Son',
inject: ['pdata'],
computed: {
text () {
return this.pdata.msg
}
},
methods: {
sendToParent () {
this.pdata.msg = 'hello'
}
}
}
</script>
4. $attrs / $listeners
v2.4
新增
$attrs
包含了父作用域中不作为prop
被识别 (且获取) 的属性绑定 (class
和 style
除外)。
$listeners
包含了父作用域中的 (不含 .native
修饰器的) v-on
事件监听器,它可以通过 v-on="$listeners"
传入内部组件。
<!-- Home.vue -->
<template>
<div class="home">
<father :name="name" :age="age" @changeName="changeName" @changeAge="changeAge" />
</div>
</template>
<script>
import Father from './Father.vue'
export default {
name: 'Home',
components: {
Father
},
data () {
return {
name: '张三',
age: 30
}
},
methods: {
changeName (name) {
this.name = name
},
changeAge (age) {
this.age = age
}
}
}
</script>
<!-- Father.vue -->
<template>
<div>
{{ age }}
Father Comp: {{ $attrs }}
<button @click="updateName">修改Name</button>
<son v-bind="$attrs" v-on="$listeners" />
</div>
</template>
<script>
import Son from './Son'
export default {
name: 'Father',
props: ['age'],
components: {
Son
},
methods: {
updateName () {
this.$emit('changeName', '李四')
}
}
}
</script>
<!-- Son.vue -->
<template>
<div>
Son Comp:{{ $attrs }}
<button @click="updateAge">修改Age</button>
</div>
</template>
<script>
export default {
name: 'Son',
methods: {
updateAge () {
this.$emit('changeAge', 40)
}
}
}
</script>
效果
5. $children / $parent
父组件通过$children
访问子组件属性和方法,子组件通过$parent
访问父组件属性和方法, this.$children[0].age=2
修改子组件数据,同理this.$parent.age=30
修改父组件数据。
<!-- Father.vue -->
<template>
<div>
Father Age: {{ age }}
<button @click="updateSonAge">修改Son的Age</button>
<son />
</div>
</template>
<script>
import Son from './Son'
export default {
name: 'Father',
components: {
Son
},
data () {
return {
age: 30
}
},
methods: {
updateSonAge () {
this.$children[0].age = 15
}
}
}
</script>
<!-- Son.vue -->
<template>
<div>
Son Age: {{ age }}
<button @click="updateFatherAge">修改Father的Age</button>
</div>
</template>
<script>
export default {
name: 'Son',
data () {
return {
age: 10
}
},
methods: {
updateFatherAge () {
this.$parent.age = 35
}
}
}
</script>
效果
6. ref / refs
子组件绑定ref
属性,父组件通过this.$refs['xxx']
访问子组件,用法和 $children
相同。
this.$refs['son']===this.$children[0] //true
<!-- Father.vue -->
<template>
<div>
Father Age: {{ age }}
<button @click="updateSonAge">修改Son的Age</button>
<son ref='son' />
</div>
</template>
<script>
import Son from './Son'
export default {
name: 'Father',
components: {
Son
},
data () {
return {
age: 30
}
},
methods: {
updateSonAge () {
this.$refs.son.age = 20
}
}
}
</script>
<!-- Son.vue -->
<template>
<div>
Son Age: {{ age }}
</div>
</template>
<script>
export default {
name: 'Son',
data () {
return {
age: 10
}
}
}
</script>
7. Vuex
vuex可以说是万金油,因为它是vue的一个状态管理库,任何数据都可以存在这个库里,缺点就是使用方法略微麻烦一点,优点就是不用管什么层级之间的传递数据都是可以的,而且是共享数据,所以还是要看有没有必要使用这个方式,如果数据会在不同的层级,很多地方都需要使用或修改,且数据都是共享的,那么这种方式就是最好的。
<template>
<div id="app">
<ChildA/>
<ChildB/>
</div>
</template>
<script>
import ChildA from './components/ChildA'
import ChildB from './components/ChildB'
export default {
name: 'App',
components: {ChildA, ChildB}
}
</script>
<template>
<div id="childA">
<h1>我是A组件</h1>
<button @click="transform">点我让B组件接收到数据</button>
<p>{{BMessage}}</p>
</div>
</template>
<script>
export default {
data() {
return {
AMessage: 'Hello,B组件,我是A组件'
}
},
computed: {
BMessage() {
return this.$store.state.BMsg
}
},
methods: {
transform() {
this.$store.commit('receiveAMsg', {
AMsg: this.AMessage
})
}
}
}
</script>
<template>
<div id="childB">
<h1>我是B组件</h1>
<button @click="transform">点我让A组件接收到数据</button>
<p>{{AMessage}}</p>
</div>
</template>
<script>
export default {
data() {
return {
BMessage: 'Hello,A组件,我是B组件'
}
},
computed: {
AMessage() {
return this.$store.state.AMsg
}
},
methods: {
transform() {
this.$store.commit('receiveBMsg', {
BMsg: this.BMessage
})
}
}
}
</script>
/**
* store.js
*/
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const state = {
AMsg: '',
BMsg: ''
}
const mutations = {
receiveAMsg(state, payload) {
state.AMsg = payload.AMsg
},
receiveBMsg(state, payload) {
state.BMsg = payload.BMsg
}
}
export default new Vuex.Store({
state,
mutations
})
8. EventBus
eventBus
又称为事件总线,在vue中可以使用它来作为沟通桥梁的概念, 就像是所有组件共用相同的事件中心,可以向该中心注册发送事件或接收事件, 所有组件都可以通知其他组件。(维护困难,eventName
起名字困难,不易维护,不及时注销事件会产生各种问题,复杂项目中还是使用Vuex
)
//新建一个Vue实例作为中央事件总线
let EventBus = new Vue();
//监听事件
EventBus.$on('eventName', (val) => {
//......do something
});
//触发事件
EventBus.$emit('eventName', 'this is a message.');
//移除事件
EventBus.$off('eventName', {})
9. localStorage/sessionStorage
本地存储,某些业务中使用较多,比如记住用户token
、用户信息
、系统设置
等
window.localStorage.getItem(key)
获取数据,通过 window.localStorage.setItem(key,value)
存储数据;
注意:
value
只能是字符串
类型,需要用JSON.parse() / JSON.stringify()
转换
sessionStorage
同理。
总结
特点 | |
---|---|
props / $emit | 最常用的父子组件通信 |
sync/update | 父子组件基本数据类型,适用于子组件修改父组件数据 |
provide/inject | 多层级传递,不受子孙组件的影响,适用于插槽,嵌套插槽;不适合兄弟通讯,父级组件无法主动通信 |
$attrs / $listeners | 主要时解决了props 传递数据不能跨层的缺点,但无法兄弟传参 |
$children / $parent | 方便直接,但 this.$children 不可控性大,有一定风险。(尽量不用) |
ref / refs | 渲染完成后才可使用,不是响应式的,时不时配合$nextTick |
vuex | 处理复杂的组件通信的最佳方案,支持异步组件通信,缺点是流程相比稍微复杂 |
EventBus | 简单灵活,父子兄弟通信不受限制,通信方式不受框架影响,但维护困难,需要谨小慎微的命令规范,不利于组件化开发 |
localStorage / sessionStorage | 常用于存储用户信息,系统设置,token等 |
-
父子组件通信:
props / $emit
;.sync/update
;provide/inject
;$parent / $children
;ref/refs
;$attrs/$listeners
-
非父子组件/兄弟组件通信:
EventBus
;Vuex
;localStorage/sessionStorage