Vue组件开发

父子组件之间的交互

  1. 子组件要求父组件传递的变量写在props
  2. 子组件自己维护的,不需要父组件传递的变量写在data
  3. 在子组件内调用父组件方法:子组件用$emit发起一个事件(可以带事件参数),父组件用v-on@监听这个事件并做处理(监听方法的形参就是子组件传的参数)
  4. 父组件调用子组件方法:父组件在子组件上定义ref属性, 父组件用this.$refs.refName.method去调用子组件方法。

示例:分页表格组件

TablePage功能:

  1. 翻页时、改变页大小时,自动调用后台查找
  2. 固定一列操作列,数据列和操作列分开从父组件传
  3. 当操作列中的按钮大于1时,这些按钮应折叠在“更多”下拉按钮中,如“编辑”、“删除”。如果不需要这些操作,操作列应该隐藏

框架是iView。设置好跨域访问和axios全局后,使用<Table /><Page />以及slot-scope实现以上功能。

TablePage组件:

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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
<template>
<div>
<!-- 表格 -->
<Table
:columns="insideColumns"
:data="data"
border>
<template slot-scope="{ row, index }" slot="action">

<template v-if="actionNumber < 2">
<a @click="firstAction.onClick(row)">{{firstAction.name}}</a>
</template>

<!-- 按钮数超过一个时,显示更多操作的下拉菜单 -->
<template v-else>
<Dropdown transfer trigger="click">
<a href="javascript:void(0)">More<Icon type="ios-arrow-down"></Icon></a>
<DropdownMenu slot="list">
<DropdownItem v-for="(item, index) in insideActions" :key="index" >
<a @click="item.onClick(row)">{{item.name}}</a>
</DropdownItem>
</DropdownMenu>
</Dropdown>
</template>

</template>
</Table>
<!-- 分页组件 -->
<div style="margin-top: 10px">
<Page transfer :current="currentPage" :total="count" :page-size="pageSize" show-elevator show-total show-sizer @on-change="changePage" @on-page-size-change="changePageSize" />
</div>
</div>
</template>

<script>
export default {
name: 'TablePage',
// 子组件要求父组件传递的变量
props: {
data: {
type: Array,
default () {
return [];
}
},
columns: { // 数据列
type: Array,
default () {
return [];
}
},
actions: { // 操作列
type: Array,
default () {
return [];
}
},
count: {
type: Number,
default: 0
},
currentPage: {
type: Number,
default: 1
},
pageSize: {
type: Number,
default: 10
}
},
// 子组件自己维护的变量
data () {
return {
insideColumns: [],
actionNumber: 0,
firstAction: {},
insideActions: [],
};
},
methods: {
changePage (newPage) {
this.currentPage = newPage;
this.getData();
},
changePageSize (newPageSize) {
this.pageSize = newPageSize;
this.getData();
},
// 在子组件内调用父组件方法:子组件用`$emit`发起一个事件
getData () {
this.$emit('get-data', this.currentPage, this.pageSize);
},
// 当actions有元素时,新增一列操作列
handleColumns (columns) {
let actionColumn = {
title: 'Action',
slot: 'action',
width: 130,
fixed: 'right',
resizable: true
};
if (this.actions && this.actions.length > 0) {
this.insideColumns = columns.concat(actionColumn);
}
},
// 处理外部传入的 actions
handleActions (actions) {
this.actionNumber = actions.length; // 按钮数
if (this.actionNumber > 0) {
this.firstAction = actions[0]; // 设置唯一的按钮
if(this.actionNumber > 1) { // 按钮多于1个,设置下拉按钮项
let more = [...actions];
this.insideActions = more;
}
}
}
},
mounted () {
this.handleColumns(this.columns);
this.handleActions(this.actions);
}
};
</script>

上面代码中的getData()方法很关键,它是TablePage与父组件通信的桥梁,通过this.$emit()触发名为”get-data”的事件,并传递参数currentPagepageSize。在父组件中,需要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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
<template>
<div>
<!-- 点击按钮触发查询,加载表格数据 -->
<div style="margin-bottom: 10px">
<Button @click="search()">查询</Button>
</div>

<!--分页表格区域-->
<TablePage :columns="columns" :data="data" :count="count"
:currentPage="currentPage"
:pageSize="pageSize"
@get-data="loadData" <!--子组件内$emit的事件-->
:actions="actions"
>
</TablePage>

</div>
</template>

<script>
import TablePage from './table-page'

export default {
name: 'PersonManage',
components: {
TablePage // 引入组件
},
data () {
return {
currentPage: 1,
pageSize: 10,
// 总条数
count: 0,
// 表格数据列
columns: [
{
title: 'ID',
key: 'id'
},
{
title: 'Lastname',
key: 'lastname'
},
{
title: 'Firstname',
key: 'firstname'
},
{
title: 'City',
key: 'city'
},
{
title: 'Address',
key: 'address'
}
],
// 表格源数据
data: [],
// 操作列
actions: [
{ name: 'Edit', onClick: (row) => this.handleEdit(row) },
{ name: 'Delete', onClick: (row) => this.handleDelete(row.id)}
],
}
},
methods: {
search(){
this.currentPage = 1
this.loadData(this.currentPage, this.pageSize)
},
// 调用后台接口获取表格数据
loadData(currentPage, pageSize){
this.currentPage = currentPage
this.pageSize = pageSize

this.$axios({
url: '/man/person/getListByPage',
method: 'post',
data: {
currentPage: this.currentPage,
pageSize: this.pageSize
}
}).then(res => {
let resData = res.data
let pageData = resData.data
this.data = pageData.dataList
this.count = pageData.count
});
},
// 按钮事件
handleEdit(row){
console.log('edit=====>'+JSON.stringify(row))
},
handleDelete(rowId){
console.log('delete=====>'+JSON.stringify(rowId))
},
}
}
</script>

currentPagepageSize由父组件传入子组件,而不是由子组件维护,原因是:父组件在改变currentPagepageSize的值后应该同步到子组件,这样子组件的<Page />组件才能与实际页码和页大小匹配。

父组件改变currentPagepageSize的场景:点击查询按钮时,需要把当前页码currentPage改为1。

因此,这两个参数也应该由父组件传入子组件,子组件改变它的值后通知到父组件。

父组件调用子组件方法例子

抄自:https://www.cnblogs.com/renzm0318/p/8762129.html

子组件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<template>
<div>
childComponent
</div>
</template>

<script>
export default {
name: "child",
methods: {
childClick(e) { // 子组件方法
console.log(e)
}
}
}
</script>

父组件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<template>
<div>
<button @click="parentClick">点击</button>

<Child ref="mychild" /><!--子组件-->
</div>
</template>

<script>
import Child from './child'; //引入子组件Child
export default {
name: "parent",
components: {
Child
},
methods: {
parentClick() {
this.$refs.mychild.childClick("子组件方法");// 调用子组件的方法childClick
}
}
}
</script>