vue组件通信

[Toc]

#组件之间的通信

Vue推荐在构建大型应用时基于组件方式开发,使用组件意味着协同工作,通常父子组件会是这样的关系:组件 A 在它的模版中使用了组件 B 。它们之间必然需要相互通信:父组件要给子组件传递数据,子组件需要将它内部发生的事情告知给父组件。或者 A组件想告诉C组件。

###父子之间,用props传递数据

  • 组件实例的作用域是孤立的。这意味着不能并且不应该在子组件的模板内直接引用父组件的数据。可以使用 props 把数据传给子组件。
  • prop 是父组件用来传递数据的一个自定义属性。子组件需要显式地用 props 选项 声明 “prop”:

    1
    2
    3
    4
    5
    6
    7
    Vue.component('child', {
    // 声明 props
    props: ['message'],
    // 就像 data 一样,prop 可以用在模板内
    // 同样也可以在 vm 实例中像 “this.message” 这样使用
    template: '<span>{{ message }}</span>'
    })
  • 父组件中使用子组件并传值给子组件

    1
    <child message="hello!"></child>
单向数据流
  • prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。这是为了防止子组件无意修改了父组件的状态——这会让应用的数据流难以理解.
  • 另外,每次父组件更新时,子组件的所有 prop 都会更新为最新值。这意味着你不应该在子组件内部改变 prop 。如果你这么做了,Vue 会在控制台给出警告。
我们怎么修改 prop 的值?
1
2
3
4
5
props: ['size'], //定义一个局部computed属性,此属性从 prop 的值计算得出
computed:
{ normalizedSize: function ()
{ return this.size.trim().toLowerCase(
) } }
子传父 props
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
<div>
<multi :fu='onSubmit'></multi>
</div>
</template>
<script>
import multi from '../common/multi.vue';
export default {
methods: {
onSubmit(data) {
console.log(data);
}
}
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<template>
<div>
<div @click="fu('1')"></div>
<div @click="save('1')"></div>
</div>
</template>
<script>
import multi from '../common/multi.vue';
export default {
props: {
fu: {
type: [Function]
}
},
methods: {
save(data) {
this.fu(data);
}
}
};
</script>
数据反传—自定义事件
  • 监听:$on(eventName)
  • 触发:$emit(eventName)
  • 子组件$emit()触发,父组件$on()监听
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    子组件
    <template>
    <div class="hello">
    <button v-on:click="onClickMe">telltofather</button>
    </div>
    </template>
    <script>
    export default {
    methods: {
    onClickMe () {
    this.$emit('child-tell-me-something',this.msg)
    }
    }
    }
    </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
父组件
<template>
<div id="app">
<p>child tell me: {{childWords}}</p>
<component-a v-on:child-tell-me-something='listenToMyBoy'></component-a>
</div>
</template>
<script>
import Store from './store'
import ComponentA from './components/componentA'
export default {
components: {
ComponentA
},
data () {
return {
childWords: ''
}
},
methods: {
listenToMyBoy (msg) {
this.childWords = msg
}
}
}
</script>
  • 这里我们在父组件派发了一个 监听事件 v-on:child-tell-me-something=’listenToMyBoy’,那我们在子组件里面任意地方 进行触发 this.$emit(‘child-tell-me-something’,this.msg)

    子与子组件的通信(简单场景)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    //新建bus.js
    import Vue from 'vue'
    export var bus = new Vue()
    //App.vue里created方法里定义事件
    import { bus } from 'bus.js'
    // ...
    created () {
    bus.$on('tip', (text) => {
    alert(text)
    })
    }
    //Test.vue组件内调用
    import { bus } from 'bus.js'
    // ...
    bus.$emit('tip', '123')

vuex(复杂场景)

  • Vuex 是一个专为 Vue.js 应用程序开发的 状态管理模式
    *什么是‘状态管理模式’?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    //先看一个demo
    new Vue({
    // state
    data () {
    return {
    count: 0
    }
    },
    // view
    template: `
    <div>{{ count }}</div>
    `,
    // actions
    methods: {
    increment () {
    this.count++
    }
    }
    })

这个状态自管理应用包含以下几个部分:

  • state,驱动应用的数据源;

  • view,以声明方式将state映射到视图;

  • actions,响应在view上的用户输入导致的状态变化。

但是,当我们的应用遇到 多个组件共享状态 时,单向数据流的简洁性很容易被破坏:

  • 问题一:多个视图依赖于同一状态?

  • 问题二:来自不同视图的行为需要变更同一状态?

  • 1: 传参的方法对于多层嵌套的组件将会非常繁琐,并且对于兄弟组件间的状态传递无能为力

  • 2:我们经常会采用父子组件直接引用或者通过事件来变更和同步状态的多份拷贝。以上的这些模式非常脆弱,通常会导致无法维护的代码

*所以,就需要组件的共享状态抽取出来,以一个全局单例来模式管理。