vue中组件之间的通讯方式

[toc]

1.vue中组件之间的通讯方式

1.父 -> 子 使用prop

子组件Pack.vue

1
2
3
4
5
6
7
8
9
10
11
12
<template>
<div>
<el-card>
<p>{{ k }}</p>
</el-card>
</div>
</template>
<script>
export default {
props:['k']
}
</script>

父组件

1
<bike k="你好" />

2.子 -> 父 使用$emit 触发自定义事件

子组件 Pack.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<template>
<div>
<el-card>
<el-button @click="childMethod">点击触发父组件事件</el-button>
</el-card>
</div>
</template>
<script>
export default {
data() {
return {
name: "Mok"
};
},
methods: {
childMethod() {
this.$emit("tmpMethodParam", this.name);
},
},
};
</script>

父组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<template>
<div>
<el-row>
<el-card title="子组件->父组件">
<p><small>name:</small>{{ name }}</p>
<pack @tmpMethodParam="parentMethod" />
</el-card>
</el-row>
</div>
</template>
<script>
import pack from "./components/Pack";
export default {
data() {
return {
name:"default name."
};
},
components: {
pack
},
methods: {
parentMethod(name) {
this.name = name
},
}
};
</script>

3.其他方式 中央事件管理器vuex

见第二节。

4.如果是页面路由组件 ? Vue

5.eventBus

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 定义eventBus    ./eventBus/index.js
import Vue from 'vue'
export const eventBus = new Vue()
//或者在main.js直接定义:
Vue.prototype.$EventBus = new Vue()
// 在一个组件中调用
import {eventBus} from "@/eventBus"
export default {
methods: {
eventBusTest(){
eventBus.$emit("changeName", {
msg:"组件2发送事件"
})
}
}
}
//在另一个组件中监听执行
import {eventBus} from "@/eventBus"
export default {
mounted(){
eventBus.$on("changeName",({msg})=>{
alert(msg)
})
}
};

2.vuex 的简介

vue 官方提供的 状态管理器 整个项目中需要在多个地方共享的数据存放在同一的位置进行管理

vuex定义使用

(1)state:存放状态

1
2
3
4
5
6
7
8
9
10
11
12
//定义
const state = {
personName: 'Rick',
}
//调用
this.$store.state.personName
//使用mapState辅助函数调用
import { mapState } from 'vuex'
computed: {
...mapState(["personName"])
//作为子模块...mapState(["orange"]) =》使用 orange.personName
}

(2)getters:加工states成员给外界

1
2
3
4
5
6
//定义
const getters = {
personName: state => state.orange.personName + " today."
}
//调用
this.$store.getters.personName

(3)mutations: state成员操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//定义
const mutations = {
setPersonName: (state, payload) => {
state.personName = payload.newName
}
}
//调用
this.$store.commit("setPersonName", { newName: "Happy" });
//如果定义了子模块,orange为子模块名
this.$store.commit("orange/setPersonName", { newName: "Happy" });
//或者这样,没试过
store.commit({
type: 'increment',
amount: 10
})

mutations必须是同步函数。提交 mutation 是更改状态的唯一方法。

(4)actions:异步操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//注册
actions: {
setPersonName (context) {
context.commit('setPersonName')
}
}
//通常参数解构context,以下模拟一个异步操作
const actions = {
setPersonNameAsync: ({commit, state})=>{
setTimeout(()=>{
// 获取数据
let data = { newName: "HAHAH" }
// 执行mutations
commit('setPersonName', data)
},1000)
}
}
// 分发,Action 通过 store.dispatch 方法触发:
store.dispatch('setPersonName')

​ Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit 提交一个 mutation,或者通过 context.state 和 context.getters 来获取 state 和 getters。

​ Action 提交的是 mutation,而不是直接变更状态,异步逻辑都应该封装到 action 里面。

(5)modules:模块化状态管理

./store/modules/orange.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
const state = {
personName: 'Rick',
}

const mutations = {
setPersonName: (state, payload) => {
state.personName = payload.newName
}
}

const actions = {
setPersonNameAsync: ({commit, state})=>{
setTimeout(()=>{
// 获取数据
let data = { newName: "HAHAH" }
// 执行mutations
commit('setPersonName', data)
},1000)
}
}

export default {
namespaced: true,
state,
mutations,
actions
}

./store/getters.js

1
2
3
4
const getters = {
personName: state => state.orange.personName + " today."
}
export default getters

./store/index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import Vue from 'vue'
import Vuex from 'vuex'
import getters from './getters'
import orange from './modules/orange'

Vue.use(Vuex)

const store = new Vuex.Store({
modules: {
app,
settings,
user,
orange
},
getters
})

export default store

main.js

1
2
3
4
5
6
7
8
9
import Vue from 'vue'
import store from './store'
...
new Vue({
el: '#app',
router,
store,
render: h => h(App)
})

什么时候需要用vuex

1.使用了 vue- router,并且多个路由之间需要共享数据的时候

2.页面数据太多难以管理

使用vuex

(1)安装 vuex npm install --save vuex

(2)在 src 目录下创建一个 store/index.js 文件

​ 思考项目的哪些数据要放到仓库中;

(3)需要在 main.js 中,也就是 new Vue 的时候,配置 store 这个选项,选项的值就是 store 的实例对象

(4)如何使用仓库的数据

​ 使用 mapState 辅助函数;

(5)如何在组件中修改仓库的数据

​ 首先在仓库的 mutations 中定义一个修改 state 的方法;

​ 组件中使用 mapMutations 辅助函数;

3.特殊情况

1
2
3
4
1. $root 获取到根组件的实例对象
2. $parent 获取父组件的实例对象
3. $children 获取子组件的实例对象

ref调用子组件方法

子组件方法定义 使用\(refs 获取具体某个子组件的实例或者具体html元素的真实dom(常用) (1)首先需要标记。你想要获取的组件或者html元素,在他们身上定义一个 ref="xxx" (2)然后 this.\)refs.xxx (3)如果 ref 标记的是普通html元素,那么到通过 $refs.xxx 得到的将是这个html元素的dom对象 (4)如果 ref 标记的是一个子组件。那么通过 $refs.xxx 得到的将是这个子组件的实例对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
<div>
<span>子组件2</span>
</div>
</template>
<script>
export default {
methods: {
sayHi(){
alert("bike组件哈哈")
}
}
}
</script>

父组件调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//定义ref
<bike ref="bike"/>
import bike from "./components/Bike";
export default {
components: {
bike
},
methods: {
refTest(){
// 在父组件调用子组件方法
this.$refs['bike'].sayHi()
}
}
};