组件通信分类
- 父组件——子组件
- 子组件——父组件
- 兄弟组件
组件通信方式
1. props
通过使用props
将数据从父组件传递到子组件。
<!-- Parent Component -->
<template>
<div>
<child-component :msg="msg"></child-component>
</div>
</template>
<script>
import ChildComponent from './ChildComponent'
export default {
name: 'ParentComponent',
components:{
ChildComponent
}.
data() {
return {
msg: '我是父组件传的值'
}
}
}
</script>
<!-- Child Component -->
<template>
<div>
<p>{{msg}}</p>
</div>
</template>
<script>
export default{
name: 'ChildComponent',
props: {
msg: {
type: String
}
}
}
</script>
2. provide & inject
2.2.0版本新增API
// 父级组件提供 'foo'
var Provider = {
provide: {
foo: 'bar'
},
// ...
}
// 子组件注入 'foo'
var Child = {
inject: ['foo'],
created () {
console.log(this.foo) // => "bar"
}
// ...
}
provide 选项应该是一个对象或返回一个对象的函数。该对象包含可注入其子孙的属性。在该对象中你可以使用 ES2015 Symbols 作为 key,但是只在原生支持 Symbol 和 Reflect.ownKeys 的环境下可工作
inject 选项应该是:
- 一个字符串数组,或
- 一个对象,对象的 key 是本地的绑定名,value 是:
- 在可用的注入内容中搜索用的 key (字符串或 Symbol),或
- 一个对象,该对象的:
- from 属性是在可用的注入内容中搜索用的 key (字符串或 Symbol)
- default 属性是降级情况下使用的 value
provide 和 inject 绑定并不是可响应的
3. 自定义事件
通过使用自定义事件$emit
将数据从子组件传递给父组件。
<template>
<div>
<child-component :msg="msg" @to-parent="childMsg=$event"></child-component>
<p>{{childMsg}}</p>
</div>
</template>
<script>
import ChildComponent from './ChildComponent';
export default {
name: 'ParentComponent',
data(){
return {
msg: '这是来自父组件的值',
childMsg: ''
}
},
components: {
ChildComponent
},
}
</script>
<!-- Child Component -->
<template>
<div>
<h4>{{ msg }}</h4>
<button @click="$emit('to-parent', newMsg)">点击向父组件传值</button>
</div>
</template>
<script>
export default {
name: 'ChildComponent',
props: ['msg'],
data: () => ({
newMsg: '这是来自子组件的值'
})
}
</script>
4. EventBus事件线
通过创建一个新的全局Vue实例来支持独立组件之间订阅$on
和发布$emit
自定义事件。
创建bus.js
文件,在里面创建一个bus的Vue实例:
import Vue from 'vue';
export const bus = new Vue();
然后可以在组件中引用之后,使用bus的接口来发出事件。
<!-- ShowComponent.vue -->
<template>
<div>
<p>{{msg}}</p>
</div>
</template>
<script>
import {bus} from '../js/bus.js';
export default {
name: 'ShowComponent',
data(){
return {
msg: ''
}
},
created(){
bus.$on('to-other', msg => {
this.msg = msg;
})
}
}
</script>
<!-- InputComponent.vue -->
<template>
<div>
<input v-model="msg" type="text" />
<button @click="toOther">点击向其他组件传值</button>
</div>
</template>
<script>
import {bus} from '../js/bus.js';
export default {
name: 'InputComponent',
data(){
return {
msg: ''
}
},
methods:{
toOther(){
bus.$emit('to-ohter', msg);
}
}
}
</script>
<!-- App.vue -->
<template>
<div id="app">
<show-component></show-component>
<input-component></input-component>
</div>
</template>
<script>
import ShowComponent from './components/ShowComponent';
import InputComponent from './components/InputComponent';
export default {
name: 'App',
components: {
ShowComponent, InputComponent
}
}
</script>
5. 简单的状态管理
通过创建全局对象,可以将一些变量数据或者操作方法存储在该对象上,实现组件之间的共享。
创建store.js
,创建全局对象store
:
const store = {
state: {
msg: '通过自定义全局对象store进行传值'
},
changeMsg(newMsg) {
this.state.msg = newMsg;
}
}
export default store;
在组件中使用:
<!-- ShowComponent.vue -->
<template>
<div>
<p >{{storeState.msg}}</p>
</div>
</template>
<script>
import store from '../js/store.js';
export default {
name: 'ShowComponent',
data() {
return {
storeState: store.state
}
}
}
</script>
<!-- ChangeComponent.vue -->
<template>
<div>
<input v-model="msg" type="text" />
<button @click="changeMsg">点击向其他组件传值</button>
</div>
</template>
<script>
import store from '../js/store.js';
export default {
name: 'ChangeComponent',
data(){
return {
msg: ''
}
},
methods:{
changeMsg(){
store.changeMsg(msg);
}
}
}
</script>
6. Vuex
一个动作(Action)提交给一个变量(Mutation)。变量会改变状态,然后影响视图或组件。视图或组件使用 getter
检索存储数据。
Vuex存储(Vuex Store)包含四个对象:state
、mutations
、actions
和 getters
。
state
state
定义共享变量。
mutations
mutations
同步修改共享变量。
actions
actions
异步请求数据。
getters
getters
过滤修改共享变量。
module
由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter。
import axios from 'axios';
// user.js
const state = {
userName: ''
}
const getters = {
userName: state => state.userName
}
const mutations = {
USERNAME: (state, userName) => {
state.userName = userName
}
}
const actions = {
getUser({commit}, userInfo) {
return new Promise((resolve, reject) => {
axios({
method: 'post',
url: '/login',
data: userInfo
}).then(res => {
commit('USERNAME', res.userName);
resolve(res);
}).catch(err => {
reject(err)
})
})
}
}
export default {
state,
getters,
mutations,
actions
}
// store.js
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
// 引入定义好的模块
import user from './modules/user'
const store = new Vuex.Store({
modules: {
user
// ...
}
})
有了Vuex存储之后,组件通常可以执行以下两种操作之一,
- 获取(GET)状态信息(通过访问store中state或getters)
- 调用(DISPATCH)actions。
<!-- ChangeComponent.vue -->
<template>
<div>
<input v-model="msg" type="text"/>
<button @click="changeMsg">点击向其他组件传值</button>
</div>
</template>
<script>
export default {
name: 'ChangeComponent',
data(){
return {
msg: ''
}
},
methods: {
changeMsg(){
this.$store.dispatch('changeMsg', this.msg)
}
}
}
</script>
<!-- ShowComponent.vue -->
<template>
<div>
<p>{{getMsg}}</p>
</div>
</template>
<script>
export default {
name: 'ShowComponent',
computed: {
getMsg() {
return this.$store.getters.getMsg
}
}
}
</script>
// message.js
const state = {
msg: '这是Vuex中存储的状态信息'
};
const mutations = {
CHANGE_MSG(state, msg) {
state.msg = msg;
}
};
const actions = {
changeMsg({commit}, msg) {
commit("CHANGE_MSG", msg);
}
};
const getters = {
getMsg(state) {
return `${state.msg} --vuex` ;
}
};
export default {
state,
mutations,
actions,
getters
}
项目src文件夹主要内容截图
下载模板,按照上图所示的目录结构创建文件夹,将文中代码复制到对应的文件中,执行即可查验。
# 安装基础模板
vue init webpack-simple my-project
# 切换到项目文件夹并安装依赖
cd my-project && npm install
# 如果需要安装vuex,执行下面的命令
npm install vuex -D