说明:下面我总结了比较常用的vue组件之前通信的方式,最近准备面试,所以有些总结贴上来分享
props和$emit
只有父子关系才可以用这种方式,父组件向子组件传递参数用props,子向父传递使用触发$emit自定义事件
1.props
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
<!-- parent.vue, 可以传递`静态`的props和`动态`的props, 静态的参数只能是个String类型的,如果是其他类型的一定要记得加`:`来表示这是一个 js 表达式而不是一个字符串 --> <Child :name= "name" :age= "18" address= "xxxxx" ></Child> ... data () { return { name: 'marry' } } <!-- 传一个参数所有props, 虽然目前我没有这个需求,使用不带参数的 v-bind --> <blog-post v-bind= "post" ></blog-post> post: { id: 1, title: 'My Journey with Vue' } //等价于下面 <blog-post v-bind:id= "post.id" v-bind:title= "post.title" ></blog-post> <!-- child.vue --> ... //以字符串数组形式列出的 prop props: [ 'name' , 'age' , 'address' ] //prop验证, 当 prop 验证失败的时候,(开发环境构建版本的) Vue 将会产生一个控制台的警告 //注意:以下类型不能写成'String'这种带引号的形式 props: { // 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证) propA: Number, // 多个可能的类型 propB: [String, Number], // 必填的字符串 propC: { type: String, required: true }, // 带有默认值的数字 propD: { type: Number, default : 100 }, // 带有默认值的对象 propE: { type: Object, // 对象或数组默认值必须从一个工厂函数获取 default : function () { return { message: 'hello' } } }, // 自定义验证函数 propF: { validator: function (value) { // 这个值必须匹配下列字符串中的一个 return [ 'success' , 'warning' , 'danger' ].indexOf(value) !== -1 } } } //注意那些 prop 会在一个组件实例创建之前进行验证,所以实例的 property (如 data、computed 等) 在 default 或 validator 函数中是不可用的。 |
2.$emit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
<!-- parent.vue --> <Child @my-event= "myEvent" ></Child> ... methods: { myEvent(name){ this .name = name } } <!-- child.vue --> <div> <button @click= "$emit('my-event', name)" ></button> </div> //使用自定义事件将子组件的值抛给父组件 |
中央事件总线 bus
用于解决跨级和兄弟组件通信问题,巧妙的使用一个公共的vue实例,利用$on, $emit, $off(移除自定义事件监听器)
方法一:
可以在main.js中,在Vue的原型上挂载一个公共的Vue实例 $bus,这样全局任何一个地方都可以使用
1
|
Vue.prototype.$bus = new Vue() |
然后在需要的地方注册自定义事件和接收参数的回调函数
1
2
3
|
this .$bus.$on( 'changeName' , name => { this .name = name }) |
在需要改变的时候触发事件并抛出参数
1
|
this .$bus.$emit( 'changeName' , 'wzj' ) |
方法二:
定义一个util.js文件
1
2
3
4
|
import Vue from 'vue' const bus = new Vue() export default bus |
在需要用到bus的文件中引入
1
2
3
4
5
6
7
8
9
|
import bus from '../util' //文件路径不一定 //在一个文件定义事件 bus.$on( 'changeName' , name => { this .name = name }) //另一个文件抛出参数 bus.$emit( 'changeName' , 'wzj' ) |
vuex
对于项目比较复杂,多组件共享状态,不同层级需要通信
核心概念:
state, getter, mutation, action, module
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
29
|
//store/index.js import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export dafault new Vuex.Store({ state: { name: '' , age: 0 }, getters: { tranName(state){ return 'name: ' + state.name } }, mutations: { changeName(state, name){ state.name = name } }, /*Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit 提交一个 mutation,或者通过 context.state 和 context.getters 来获取 state 和 getters */ actions: { //异步函数,但还是要通过提交commit触发mutations函数操作state changeName(context, name){ context.commit( 'changeName' , name) } }, modules: {} }) |
在组件中使用
方法一:
1
2
3
4
5
6
7
8
|
//访问state属性 this .$store.state.name //访问getters属性 this .$store.getters.tranName //访问mutations this .$store.commit( 'changeName' , 'wzj' ) //访问actions this .$store.dispatch( 'changeName' , 'wzj' ) |
方法二:使用辅助函数映射到本地,这里只列举了简便的方式,更多查阅官网吧
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
import {mapState, mapGetters, mapMutations, mapActions} from 'vuex' //state 和 getters 映射到本地的computed属性中,作为计算属性使用 computed: { ...mapState([ 'name' , 'age' ]), ...mapGetters([ 'tranName' ]) } //mutations 和 actions methods: { // 将 `this.changeName()` 映射为 `this.$store.commit('changeName')` ...mapMutations([ 'changeName' ]) // 将 `this.changeName()` 映射为 `this.$store.dispatch('changeName')` ...mapActions([ 'changeName' ]) } |
$attrs 和 $listeners
父组件与后代组件,用以上方法有点大材小用或者第一种有些不方便
- $attrs 包含了父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定 ( class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 ( class 和 style 除外),并且可以通过 v-bind="$attrs" 传入内部组件。
- $listeners 包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件——在创建更高层次的组件时非常有用。
例子:
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
29
30
31
32
33
34
35
36
37
38
|
//app.vue <div> <One name= "wzj" :age= "age" address= "xian" @changeAge= "changeAge" ></One> </div> ... data(){ return { age: 10 } }, methods: { changeAge(age){ this .age = age } } //one.vue <div> <div>姓名:{{ name }}</div> <div>年龄:{{ age }}</div> <Two v-bind= "$attrs" v-on= "$listeners" ></Two> <button @click= "change" >点我2</button> </div> ... props: [ 'name' , 'age' ], //two.vue <div> <div>{{ address }}</div> <button @click= "change" >点我2</button> </div> ... props: [ 'address' ], //用$attrs传递到最后的属性,在使用的时候还是要声明props methods: { change(){ this .$emit( 'changeAge' , 30) } } |
理解:其实祖先组件的属性和事件还是一层层往下传,不过用$attrs 和 $listeners优化和简便了传递过程中书写,而且在传递的过程中,任何一个声明了 $listeners的组件都可以触发里面的所有事件,而声明了$attrs的组件只能使用之前未用props声明的剩下的属性。
以上就是vue组件之间的通信的详细内容,更多关于vue 组件通信的资料请关注服务器之家其它相关文章!
原文链接:https://segmentfault.com/a/1190000023818691?utm_source=tuicool&utm_medium=referral