Vue 组件中的数据传递方式
大致分为两类通信方式:
- 父子组件之间通信
- 非父子组件之间通信(兄弟组件、隔代关系组件等)
Vue 的父子组件通信
props
这是一个学习过 Vue 的人都会使用的方法,将父组件的数据传递个子组件,在父组件中修改 props 中的数据,那么子组件也会动态的修改。
这个组件的信息传递方向是:父组件 -> 子组件;
Father.vue
<template>
<div id="father">
<p>这里是father组件</p>
<children
title="Vue中父子组件之间的通信方式"
date="2020/04/19">
</children>
</div>
</template>
将要传递的数据写在子组件的标签上,并且和对于的名字对应上。
Children
<script>
export default {
name: 'Children',
props: {
title: {
type: String,
default: '',
},
date: {
type: String,
default: '',
}
}
}
</script>
在子组件的 props 中设置相应的名称,用来接收父组件传递的数据。
这里只介绍了简单的使用,更多且更加详细的用法还是进入官网进行查看传送门。
总结: prop 只可以从上一级组件传递到下一级组件(父子组件),即所谓的单向数据流。而且 prop 只读,不可被修改,所有修改都会失效并警告。
$emit
这个方法也是在 Vue 中用的很多的一个,提交事件,由子组件提交一个事件,然后父组件进行调用,然后父组件通过这种方法察觉到子组件的变化,进行数据的更新。
这个方法是一个 Vue 上面的实例方法。
vm.$emit(eventName, [...args]);
$parent / $children
都是 Vue 上的一个实例,可以用来访问当前组件的子组件或者父组件,使用 this 可以直接调用。
使用方法
// 访问子组件信息
this.$children[0].messageA = 'this is new value';
// 访问父组件信息
this.$parent.msg;
其他通信方式
provide / inject
父组件中通过 provide
来提供变量,然后在子组件中通过 inject
来注入变量。
不论子组件嵌套有多深,只要调用了
inject
那么就可以注入provide
中的数据,而不局限于只能从当前父组件的props
属性中取数据。
使用案例:
假设有三个组件 A、B、C,B 为 A 的子组件,C 为 B 的子组件,形成嵌套关系。
在组件 A 中:
import comB from 'comB.vue';
export default {
provide: {
for: "deom"
},
components: {
comB
}
}
在组件 B 中:
import comC from 'comC.vue';
export default {
inject: ['for'],
data() {
return {
demo: this.for
}
},
components: {
comC
}
}
在组件 C 中
export default {
inject: ['for'],
data() {
return {
demo: this.for
}
}
}
ref / refs
ref
:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例,可以通过实例直接调用组件的方法或访问数据。
const comA = this.$refs.comA;
eventBus
eventBus
又称为事件总线,在vue中可以使用它来作为沟通桥梁的概念, 就像是所有组件共用相同的事件中心,可以向该中心注册发送事件或接收事件, 所以组件都可以通知其他组件。
eventBus也有不方便之处, 当项目较大,就容易造成难以维护的灾难
初始化
首先需要创建一个事件总线并将其导出, 以便其他模块可以使用或者监听它。
// event-bus.jsimport Vue from 'vue'
export const EventBus = new Vue()
发送事件
假设你有两个组件: additionNum
和 showNum
, 这两个组件可以是兄弟组件也可以是父子组件;这里我们以兄弟组件为例:
在 additionNum 中发送一个事件
// addtionNum.vue 中发送事件
<template>
<div>
<button @click="additionHandle">+加法器</button>
</div>
</template>
<script>
import {EventBus} from './event-bus.js'
console.log(EventBus)
export default {
data(){
return{
num:1
}
},
methods:{
additionHandle(){
EventBus.$emit('addition', {
num:this.num++
})
}
}
}
</script>
接收事件
在 showNum 中接收在 additionNum 中发送的事件
// showNum.vue 中接收事件
<template>
<div>计算和: {{count}}</div>
</template>
<script>
import { EventBus } from './event-bus.js'
export default {
data() {
return {
count: 0
}
},
mounted() {
EventBus.$on('addition', param => {
this.count = this.count + param.num;
})
}
}
</script>
这样就实现了在组件addtionNum.vue
中点击相加按钮, 在showNum.vue
中利用传递来的 num
展示求和的结果。
移除监听者
如果想移除事件的监听, 可以像下面这样操作:
import { eventBus } from 'event-bus.js'
EventBus.$off('addition', {})
Vuex
Vuex 介绍
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。 Vuex 解决了多个视图依赖于同一状态
和来自不同视图的行为需要变更同一状态
的问题,将开发者的精力聚焦于数据的更新而不是数据在组件之间的传递上。
Vuex 各个模块
state
:用于数据的存储,是store中的唯一数据源getters
:如vue中的计算属性一样,基于state数据的二次包装,常用于数据的筛选和多个数据的相关性计算mutations
:类似函数,改变state数据的唯一途径,且不能用于处理异步事件actions
:类似于mutation
,用于提交mutation
来改变状态,而不直接变更状态,可以包含任意异步操作modules
:类似于命名空间,用于项目中将各个模块的状态分开定义和操作,便于维护
localStorage / sessionStorage
本地存储的方式,将数据存储在本地,在其他地方可以直接获取。
window.localStorage.getItem(key)
获取数据window.localStorage.setItem(key,value)
存储数据
注意用
JSON.parse()
/JSON.stringify()
做数据格式转换localStorage
/sessionStorage
可以结合vuex
, 实现数据的持久保存,同时使用vuex解决数据和状态混乱问题。
$attrs / $listeners
当两个组件是隔代传递数据时,可以使用 $attrs
和 $listeners
。
使用案例:
// app.vue
// index.vue
<template>
<div>
<child-com1
:name="name"
:age="age"
:gender="gender"
:height="height"
title="程序员成长指北"
></child-com1>
</div>
</template>
<script>
const childCom1 = () => import("./childCom1.vue");
export default {
components: { childCom1 },
data() {
return {
name: "zhang",
age: "18",
gender: "女",
height: "158"
};
}
};
</script>
// childCom1.vue
<template class="border">
<div>
<p>name: {{ name}}</p>
<p>childCom1的$attrs: {{ $attrs }}</p>
<child-com2 v-bind="$attrs"></child-com2>
</div>
</template>
<script>
const childCom2 = () => import("./childCom2.vue");
export default {
components: {
childCom2
},
inheritAttrs: false, // 可以关闭自动挂载到组件根元素上的没有在props声明的属性
props: {
name: String // name作为props属性绑定
},
created() {
console.log(this.$attrs);
// { "age": "18", "gender": "女", "height": "158", "title": "程序员成长指北" }
}
};
</script>
// childCom2.vue
<template>
<div class="border">
<p>age: {{ age}}</p>
<p>childCom2: {{ $attrs }}</p>
</div>
</template>
<script>
export default {
inheritAttrs: false,
props: {
age: String
},
created() {
console.log(this.$attrs);
// { "gender": "女", "height": "158", "title": "程序员成长指北" }
}
};
</script>
总结
常见使用场景可以分为三类:
父子组件通信:
props
$parent
/$children
provide
/inject
ref
$attrs
/$listeners
兄弟组件通信:
eventBus
Vuex
跨级通信:
eventBus
Vuex
provide
/inject
$attrs
/$listeners