组件化开发2

组件数据的存放

  1. 组件不可以访问Vue实例数据
  2. 组件对象也有一个data属性(也可以有methods等属性)
  3. 只是这个data属性必须是一个函数,而且这个函数返回一个对象,对象内部保存着数据

为什么data在组件中必须是一个函数呢?原因是在于Vue让每个组件对象都返回一个新的对象,因为如果是同一个对象的,组件在多次使用后会相互影响。下面计数器的例子可以很好的说明这个问题

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id='app'>
<cpn></cpn>
<cpn></cpn>
<cpn></cpn>
</div>
<template id="div1">
<!-- 访问vue实例中的数据,不能显示 -->
<!-- <h1>{{message}}</h1> -->
<!-- 访问cpn组件中的数据,能显示 -->
<!-- <h1> {{message}}</h1> -->
<div>
<h3>{{count}}</h3>
<button @click=count++>+</button>
<button @click=count-->-</button>
</div>
</template>
<script src='https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js'></script>
<script>

const app = new Vue({
el: '#app',
data :{
message: '你好!!!'

},
components: {
'cpn':{template: '#div1',
data(){
return{
message: "你好!!我是组件中的数据!!!",
count: 0,

}
},
// methods: {
// add(){
// this.count++;
// },
// reduce(){
// this.count--;
// }
// }
}

}

})
</script>
</body>
</html>

父子组件通信

1.通过props向子组件传递数据

props基本用法

在组件中,使用选项props来声明需要从父级接收到的数据。

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id='app'>
<cpn :childmessage="message"> </cpn>
</div>
<template id="div1">
<div>
<h3>{{childmessage}}</h3>
</div>
</template>
<script src='https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js'></script>
<script>
const app = new Vue({
el: '#app',
data :{
message: '你好!!!我是父组件的数据'
},
components: {
'cpn':{
template: '#div1',
props: ['childmessage']
}
}
})
</script>
</body>
</html>
1
2
3
4
5
6
7
8
9
props: {
title: String,
likes: Number,
isPublished: Boolean,
commentIds: Array,
author: Object,
callback: Function,
contactsPromise: Promise // or any other constructor
}

2.通过事件向父组件发送消息

自定义事件的流程:

在子组件中,通过$emit()来触发事件。

在父组件中,通过v-on来监听子组件事件。

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
62
63
64
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>

<div id='app'>
<!-- 监听事件 -->
<cpn @item-click="change"></cpn>
<h1>我是传过来的id:{{Fid}}</h1>
</div>
<template id="div1">
<div>
<button v-for="item in categrories" @click="transfer(item)"> {{item.name}}</button>
{{Transferid}}
</div>
</template>
<script src='https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js'></script>
<script>
const app = new Vue({
el: '#app',
data :{
Fid: ''
},
methods:{
change(item){
console.log(item.name)
this.Fid = item.id
}
},
components:{
'cpn':{
template:'#div1',
data(){
return{
categrories:[
{id: 'aaa',name: '热门推荐'},
{id: 'bbb',name: '手机数码'},
{id: 'ccc',name: '家用家电'},
{id: 'ddd',name: '电器办公'},
{id: 'eee',name: '服装热卖'}

],
Transferid: 0
}
},
methods:{
transfer(item){
// console.log(item)
this.Transferid = item.id
//发射事件:自定义事件
this.$emit('item-click',item)
}
}
}
}
})
</script>
</body>
</html>

父子组件的访问方式

父组件访问子组件:使用$children或$refs

this.$children是一个数组类型,它包含所有子组件对象。可以通过一个遍历,取出所有子组件的message状态。

$children的缺陷:

通过$children访问子组件时,是一个数组类型,访问其中的子组件必须通过索引值。但是当子组件过多,我们需要拿到其中一个时,往往不能确定它的索引值,甚至还可能会发生变化。有时候,我们想明确获取其中一个特定的组件,这个时候就可以使用$refs

$refs的使用:

  • $refs和ref指令通常是一起使用的。
  • 首先,我们通过ref给某一个子组件绑定一个特定的ID。
  • 其次,通过this.$refs.ID就可以访问到该组件了。

子组件访问父组件:使用$parent

  • 尽管在Vue开发中,我们允许通过$parent来访问父组件,但是在真实开发中尽量不要这样做。子组件应该尽量避免直接访问父组件的数据,因为这样耦合度太高了。
  • 如果我们将子组件放在另外一个组件之内,很可能该父组件没有对应的属性,往往会引起问题。
  • 另外,更不好做的是通过$parent直接修改父组件的状态,那么父组件中的状态将变得飘忽不定,很不利于我的调试和维护。
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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- 父组件 -->
<div id='app'>
<cpn1 ref="cpn1"> </cpn1>
<button @click="parentclick">显示所有子组件信息</button>
</div>
<!-- 子组件1 -->
<template id="div1">
<div>
<h1>{{message}}</h1>
<cpn2 ref="cpn2"></cpn2>
</div>
</template>
<!-- 子组件2 -->
<template id="div2" >
<div>
<h1>{{message}}</h1>
<button @click="cpn2click">显示父组件信息</button>
</div>
</template>
<script src='https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js'></script>
<script>
const app = new Vue({
el: '#app',
data :{
message: '我是根组件,组件1的父组件'
},
methods:{
parentclick(){
//通过$children进行访问子组件
for(let i=0;i<this.$children.length;i++){
console.log(this.$children[i].message)
}
//通过$refs进行访问子组件
console.log(this.$refs.cpn1.message)
}
},
components:{
'cpn1': {
template:'#div1',
data(){
return{
message: '我是组件1,是根组件的子组件,组件2的父组件'
}
},
components:{
'cpn2': {
template:'#div2',
data(){
return{
message: '我是组件2'
}
},
methods:{
cpn2click(){
//通过$parent进行访问父组件
console.log(this.$parent.message)
//通过$root进行访问根组件
console.log(this.$root.message)
}
}
}
}
},

}
})
</script>
</body>
</html>

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!