vue 组件中通讯

组件

组件系统是 Vue 的另一个重要概念,因为它是一种抽象,允许我们使用小型、独立和通常可复用的组件构建大型应用。仔细想想,几乎任意类型的应用界面都可以抽象为一个组件树

  • 创建组件的两种方式:1 全局组件 2 局部组件
  • Vue实例中的配置项(如:methods、filters、watch、computed、directives、生命周期钩子函数)都可以在组件中使用

全局组件

  • 说明:全局组件在所有的vue实例中都可以使用
  • 注意:先注册组件,再初始化根实例
  • 注意:组件中的 data 必须是函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 1 注册全局组件
Vue.component('my-component', {
template: '<p>A custom component!</p>',
data() {
return {
msg: '注意:组件的data必须是一个函数!!!'
}
}
})

// 2 使用:以自定义元素的方式
<div id="example">
<my-component></my-component>
</div>

// =====> 渲染结果
<div id="example">
<p>A custom component!</p>
</div>
  • template属性的值可以是:
    • 1 模板字符串
    • 2 模板id
1
2
3
4
5
6
<!-- 2 模板id 示例 -->
<script type="text/x-template" id="tpl">
<p>A custom component!</p>
</script>

template: '#tpl'
  • extend:使用基础 Vue 构造器,创建一个“子类”。参数是一个包含组件选项的对象。
1
2
3
4
5
6
7
8
9
10
11
12
// 注册组件,传入一个扩展过的构造器
Vue.component('my-component', Vue.extend({ /* ... */ }))

// 注册组件,传入一个选项对象 (自动调用 Vue.extend)
Vue.component('my-component', { /* ... */ })

// 内部执行过程:
var Home = Vue.extend({
template: '',
data() {}
})
Vue.component('home', Home)

局部组件

  • 说明:局部组件,是在某一个具体的vue实例中定义的,只能在这个vue实例中使用
1
2
3
4
5
6
7
8
9
10
11
var Child = {
template: '<div>A custom component!</div>'
}

new Vue({
// 注意:此处为 components
components: {
// <my-component> 将只在当前vue实例中使用
'my-component': Child
}
})
  • 具体实例:<div id="app"> <parent></parent></div>
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
  <script>
// Vue.component('child', {
// template: `
// <div>
// <h2>子组件:小刚</h2>
// </div>
// `
// })

const vm = new Vue({
el: '#app',
data: {},

// 局部组件
// 因为这两个组件都是注册在 vm实例中的,所以在vm实例管理的范围内(#app),直接可以使用这两个组件
components: {
parent: {
template: `
<div>
<h1>父组件:老王</h1>
<child></child>
</div>
`,

// 组件中定义子组件:
// !!!组件是独立的个体,只有形成包含关系,才能够变为父子级嵌套组件
// 因为这个child组件是注册在 parent组件中的,所以在parent组件管理的范围内容,直接可以使用这个组件
components: {
child: {
template: `
<div>
<h2>子组件:小刚</h2>
</div>
`
}
}
},

// 这个组件无法在 上面parent组件 中使用!!!
// child: {
// template: `
// <div>
// <h2>子组件:小刚</h2>
// </div>
// `
// }
}
})
</script>

组件通讯

父组件到子组件

  • 方式:通过props属性来传递数据
  • 注意:属性的值必须在组件中通过props属性显示指定,否则,不会生效
  • 说明:传递过来的props属性的用法与data属性的用法相同
1
2
3
4
5
6
7
8
9
10
11
12
13
<hello msg="120"></hello>
<hello my-msg="'abc'"></hello>

<!-- js -->
<script>
components: {
hello: {
// 显式创建props及其传递过来的属性
props: ['msg', 'myMsg'],
template: '<h1>这是 hello 组件,这是消息:{{msg}} --- {{myMsg}}</h1>'
}
}
</script>

子组件到父组件

  • 方式:父组件给子组件传递一个函数,由子组件调用这个函数
  • 说明:借助vue中的自定义事件(v-on:cunstomFn=”fn”)
  • $emit():触发事件
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
<hello @pfn="parentFn"></hello>

<script>
new Vue({
methods: {
// 父组件:提供方法
parentFn(data) {
console.log('父组件:', data)
}
}
})

Vue.component('hello', {
template: '<button @click="fn">按钮</button>',
methods: {
// $emit 是Vue中内置的一个方法,用来调用方法的
//1 要调用的方法,作为第一个参数
// fn 是父组件传递过来的
// 2 第二个参数:表示要传递给方法fn的参数
fn() {
this.$emit('pfn', '这是子组件传递给父组件的数据')
}
}
})
</script>

非父子组件通讯

在简单的场景下,可以使用一个空的 Vue 实例作为事件总线

  • $on():绑定事件
1
2
3
4
5
6
7
8
9
var bus = new Vue()

// 触发组件 A 中的事件
bus.$emit('id-selected', 1)

// 在组件 B 创建的钩子中监听事件
bus.$on('id-selected', function (id) {
// ...
})
  • 示例:组件A —> 组件B
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
<!-- 组件A: -->
<com-a></com-a>
<!-- 组件B: -->
<com-b></com-b>

<script>
var bus = new Vue()

var vm = new Vue({
el: '#app',
components: {
comB: {
template: '<p>组件A告诉我:{{msg}}</p>',
data() {
return {
msg: ''
}
},
created() {
// 定义事件:
bus.$on('tellComB', (msg) => {
this.msg = msg
})
}
},

comA: {
template: '<button @click="emitFn">告诉B</button>',
methods: {
emitFn() {
// 调用组件B中定义的事件:
bus.$emit('tellComB', '我的vue')
}
}
}
}
})
</script>