组件基础

  1. 1. 组件名大小写
  2. 2. 案例
    1. 2.1. 运行截图:
    2. 2.2. 组件的复用
    3. 2.3. 选项必须是一个函数
    4. 2.4. 组件的组织
      1. 2.4.1. 全局组件
      2. 2.4.2. 局部组件
    5. 2.5. 组件模板
    6. 2.6. 父子组件
    7. 2.7. 组件之间的通信
      1. 2.7.1. 子组件获取父组件数据
      2. 2.7.2. 父组件获取子组件数据

组件名大小写

定义组件名的方式有两种:

使用 kebab-case:

1
Vue.component('my-component-name', { /* ... */ })

使用 PascalCase:

1
Vue.component('MyComponentName', { /* ... */ })

当使用 PascalCase (首字母大写命名) 定义一个组件时,你在引用这个自定义元素时两种命名法都可以使用。也就是说 都是可接受的。注意,尽管如此,直接在 DOM (即非字符串的模板) 中使用时只有 kebab-case 是有效的。

案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<div id="app">
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
</div>

<script>
Vue.component('button-counter', {
data() {
return {
count: 0
}
},
template: '<button @click="count++">You clicked me {{ count }} times.</button>'
});
var vm = new Vue({
el: '#app'
});
</script>

运行截图:


​ 组件是可复用的 Vue 实例,且带有一个名字:在这个例子中是 <button-counter>。我们可以在一个通过 new Vue 创建的 Vue 根实例中,把这个组件作为自定义元素来使用:

1
2
3
4
5
<div id="app">
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
</div>
1
2
3
var vm = new Vue({
el: '#app'
});

组件的复用

你可以将组件进行任意

1
2
3
4
5
<div id="app">
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
</div>

次数的复用:注意当点击按钮时,每个组件都会各自独立维护它的 count。因为你每用一次组件,就会有一个它的新实例被创建。

选项必须是一个函数

因此每个实例可以维护一份被返回对象的独立的拷贝

1
2
3
4
5
data: function () {
return {
count: 0
}
}

如果 Vue 没有这条规则,点击一个按钮就可能会几个按钮同时显示同一个值,互相影响。

组件的组织

了能在模板中使用,这些组件必须先注册以便 Vue 能够识别。这里有两种组件的注册类型:全局注册局部注册

全局组件

至此,我们的组件都只是通过 Vue.component 全局注册的:

1
2
3
Vue.component('my-component-name', {
// ... options ...
})

我们可以总结出全局组件的使用步骤:

  1. 使用vue.component()注册组件,需要提供2个参数:组件的标签名和组件构造器。
  2. vue.component()内部会调用组件构造器,创建一个组件实例
  3. 将组建挂载到某个vue实例下。

注意:一个组件的template部分,必须要包裹在一个根容器中。

因为组件是可复用的vue实例,所以它们也能有data、computed、watch、methods以及生命周期钩子等。

组件模板的内容,可以写在一对反引号中(``),这样就可以不使用字符串拼接的形式了。

局部组件

如果不需要全局注册,或者是让组件使用在其它组件内,可以用选项对象的components属性实现局部注册。 因此我们可以将上面的全局组件改为局部组件。

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
<div id="app">
<mycomponent></mycomponent>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let obj = {
template: `<div>
<h3>我是局部组件</h3>
{{num}} <button @click="add">加</button>
</div>`,
data(){
return {
num:1
}
},
methods:{
add(){
this.num++;
}
}
};
var vm = new Vue({
el: '#app',
components:{ //声明局部组件
mycomponent:obj
}
});
</script>

组件模板

如果组件中的template内容过多,那么可以使用组件模板来声明template中的内容

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
<div id="app">
<mycomponent></mycomponent>
</div>
<!-- 组件模板 -->
<template id="mytemplate">
<div>
<h3>我是局部组件</h3>
{{num}} <button @click="add">加</button>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let obj = {
template: '#mytemplate', //使用选择器应用组件模板
data() {
return {
num: 1
}
},
methods: {
add() {
this.num++;
}
}
};
var vm = new Vue({
el: '#app',
components: { //声明局部组件
mycomponent: obj //组件名:组件实例
}
});
</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
29
30
<div id="app">
<mycomponent></mycomponent>
</div>
<template id="mytemplate">
<div>
<h3>我是父组件</h3>
<!-- 在父组件中使用子组件 -->
<subcomponents></subcomponents>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let obj = {
template: '#mytemplate',
data() {
return {}
},
components:{ //声明子组件
subcomponents:{
template:`<div>我是子组件</div>`
}
}
};
var vm = new Vue({
el: '#app',
components: { //声明局部组件
mycomponent: obj //组件名:组件实例
}
});
</script>

组件之间的通信

组件与组件之间是可以互相通信的。包括父子组件之间、兄弟组件之间等等,都可以互相通信。 下面只讨论父子组件之间通信问题。

子组件获取父组件数据

在vue中,组件实例的作用域是孤立的,默认情况下,父子组件的数据是不能共享的,也就是说,子组件是不能直接访问父组件的数据的。为此,vue给我们提供了一个数据传递的选项prop,用来将父组件的数据传递给子组件。具体使用如下:

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
<div id="app">
<mycomponent></mycomponent>
</div>
<template id="mytemplate">
<div>
<h3>我是父组件</h3>
<subcomponents msg="hello world!"></subcomponents>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let obj = {
template: '#mytemplate',
data() {
return {}
},
components:{
subcomponents:{
template:`<div>我是子组件,我能获取父组件传递的数据:{{msg}}</div>`,
props:['msg']
}
}
};
var vm = new Vue({
el: '#app',
components: { // 声明局部组件
mycomponent: obj //组件名:组件实例
}
});
</script>

上面实例中,子组件获取父组件传递的数据的步骤为:

  1. 在子组件标签中,声明 msg 属性,属性值即为父组件向子组件传递的值。
  2. 在子组件中,使用props选项,声明接收父组件向子组件传递值的载体,即 ‘msg’
  3. 子组件中就可以使用 msg 获取父组件向子组件传递的值了。

也可以使用 v-bind 绑定子组件标签属性,这样就可以将父组件data数据传递个子组件了。

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
<div id="app">
<mycomponent></mycomponent>
</div>
<template id="mytemplate">
<div>
<h3>我是父组件</h3>
<subcomponents :msg="welcome"></subcomponents>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let obj = {
template: '#mytemplate',
data() {
return {
welcome:'hello world!'
}
},
components:{
subcomponents:{
template:`<div>我是子组件,我能获取父组件传递的数据:{{msg}}</div>`,
props:['msg']
}
}
};
var vm = new Vue({
el: '#app',
components: { //声明局部组件
mycomponent: obj //组件名:组件实例
}
});
</script>

父组件获取子组件数据

和上面不一样的是,父组件想要获取子组件的数据时,需要子组件通过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
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
<div id="app">
<mycomponent></mycomponent>
</div>
<template id="mytemplate">
<div>
<h3>我是父组件,接收子组件传递过来的数据:{{msg}}</h3>
<subcomponents @childmsg="get" msg="hello world!"></subcomponents>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let obj = {
template: '#mytemplate',
data() {
return {
msg:''
}
},
methods:{
get(msg) {
this.msg = msg;
}
},
components: {
subcomponents: {
template: `<div>
我是子组件,我能获取父组件传递的数据:{{msg}}
<input type="button" value="给父组件发数据" @click="send">
</div>`,
props: ['msg'],
data() {
return {
message: '我是子组件的数据'
}
},
methods: {
send() {
this.$emit('childmsg', this.message);
}
}
}
}
};
var vm = new Vue({
el: '#app',
components: { //声明局部组件
mycomponent: obj //组件名:组件实例
}
});
</script>
  1. 首先,我们需要在子组件中触发一个主动发送数据的事件,上面的例子中是一个点击事件send

  2. 其次,在点击事件中使用emit方法,这个emit接收两个参数:传递数据的事件和需要传递的数据,这个传递数据的事件也是自定义的;

  3. 然后在父组件中引用子组件,并在引用的子组件中使用on监听上一步传递数据的事件,上面的例子中是childmsg

  4. 最后在父组件中使用这个事件,这个事件带有一个参数,就是从子组件发送过来的数据。