vue-封装Form&Table组件
前言
- 项目中可以直接使用 elementUI 直接进行开发。
- 当页面变多之后,每个页面写一套会发现有很多相似的地方,于是采用提取组件的方式使用,减少开发成本。
- 页面的内容常见的是Table 数据的展示,对数据的增删改查
- 头部为form表单,进行条件的筛选
- 中间为内容数据的展示
- 底部为分页菜单
Form表单
简单使用
我们看下官网一个示例 Form 表单
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<template>
<el-form ref="form" :model="form" label-width="80px">
<el-form-item label="姓名">
<el-input v-model="form.name" style="width: 195px"></el-input>
</el-form-item>
<el-form-item label="国籍">
<el-select v-model="form.region" placeholder="请选择国籍">
<el-option label="中国" value="china"></el-option>
<el-option label="美国" value="America"></el-option>
</el-select>
</el-form-item>
<el-form-item label="爱好">
<el-checkbox-group v-model="form.type">
<el-checkbox label="画画" name="type"></el-checkbox>
<el-checkbox label="吹泡泡" name="type"></el-checkbox>
<el-checkbox label="放风筝" name="type"></el-checkbox>
<el-checkbox label="看佩琦" name="type"></el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit" size="small"
>立即创建</el-button
>
</el-form-item>
</el-form>
</template>
<script>
export default {
data() {
return {
form: {
name: "",
region: "",
type: [],
},
};
},
methods: {
onSubmit() {
console.log(
"提交 -> " +
this.form.name +
" " +
this.form.region +
" " +
this.form.type,
);
},
},
};
</script>运行结果
封装Form组件
从上面的例子中可以看到至少父组件需要2份数据传入到表单组件中的:
v-mode
对应的数据, 这份数据是用户选择好后给父组件的,所以是双向绑定的。- label 对应的数据(选项),这里是写死的,既然要封装成一个控件那么这份数据也需要父组件传过来。
新建一个
CommonForm.vue
,作为封装Form的组件。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19<template>
<!--是否行内表单-->
<el-form :inline="inline" :model="form" ref="form" label-width="100px">
</el-form>
</template>
<script>
export default {
//inline 属性可以让表单域变为行内的表单域
//form 表单数据 formLabel 是标签数据
props: {
inline: Boolean,
form: Object,
formLabel: Array,
},
};
</script>
<style></style>表单的子项,类型可以有 input 输入框,Switch 开关, select选择器,单选,多选,时间日期… 等情况
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<!--标签显示名称-->
<el-form-item v-for="item in formLabel" :key="item.model" :label="item.label">
<!--根据type来显示是什么标签-->
<!-- switch开关 -->
<el-switch
v-model="form[item.model]"
v-if="item.type === 'switch'"
active-color="#13ce66"
inactive-color="#ff4949"
active-text="开"
></el-switch>
<!-- 输入框 -->
<el-input
v-model="form[item.model]"
:placeholder="'请输入' + item.label"
v-if="item.type === 'input'"
></el-input>
<!-- 数值输入 -->
<el-input-number
v-model="form[item.model]"
v-if="item.type === 'number'"
controls-position="right"
:placeholder="'请输入' + item.label"
></el-input-number>
<!-- 下拉选择 -->
<el-select
v-model="form[item.model]"
placeholder="请选择"
v-if="item.type === 'select'"
>
<!--如果是select或者checkbox 、Radio就还需要选项信息-->
<el-option
v-for="item in item.opts"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
<el-date-picker
v-model="form[item.model]"
type="date"
placeholder="选择日期"
v-if="item.type === 'date'"
value-format="yyyy-MM-dd"
>
</el-date-picker>
</el-form-item>
<!--还可以留一个插槽,放置搜索的按钮-->
<el-form-item>
<slot></slot>
</el-form-item>使用: 父组件传入props中的属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21<!-- 创建一个行内表单, 带有一个输入框,属性值为keyword,标签名为空。 slot为搜索按钮 -->
<common-form inline :formLabel="formLabel" :form="searchFrom">
<el-button type="primary" @click="getList(searchFrom.keyword)">搜索</el-button>
</common-form>
<script>
data() {
return {
searchFrom: {
keyword: ''
},
formLabel: [
{
model: 'keyword',
label: '',
type: 'input'
}
]
};
}
</script>
Table组件
简单使用
看下element有关表格最简单的示例。Table 表格
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<template>
<el-table :data="tableData" style="width: 100%">
<el-table-column prop="date" label="日期" width="180"> </el-table-column>
<el-table-column prop="name" label="姓名" width="180"> </el-table-column>
<el-table-column prop="address" label="地址"> </el-table-column>
</el-table>
</template>
<script>
export default {
data() {
return {
tableData: [
{
date: "2017-05-04",
name: "小小",
address: "浙江省杭州市千岛湖镇 阳光路",
},
{
date: "1956-05-04",
name: "爷爷",
address: "浙江省杭州市千岛湖镇 清波花园",
},
{
date: "1958-05-04",
name: "奶奶",
address: "浙江省杭州市千岛湖镇 冬瓜乌",
},
],
};
},
};
</script>
Pagination 分页
当数据量过多时,使用分页分解数据。下面是一个完整
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 class="block">
<span class="demonstration">完整功能</span>
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage4"
:page-sizes="[100, 200, 300, 400]"
:page-size="100"
layout="total, sizes, prev, pager, next, jumper"
:total="400">
</el-pagination>
</div>
</template>
<script>
export default {
methods: {
handleSizeChange(val) {
console.log(`每页 ${val} 条`);
},
handleCurrentChange(val) {
console.log(`当前页: ${val}`);
}
},
data() {
return {
currentPage4: 4
};
}
}
</script>
封装Table组件
通过上面的示例,至少也是两份数据是需要父组件传入到表格组件中的:
- v-model对应的数据,这份数据是用户选择好后给父组件的。
- label 对应的数据,这里是写死的,既然要封装成一个控件那么这份数据也需要外面传过来。
注意: 这里除了上面这两份数据外,还有一份数据在实际开发中也是需要的,那就是分页信息,因为一般table数据都会比较多所以分页还是非常需要的。
新建一个CommonTable.vue,作为封装Table的组件
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<template>
<div class="common-table">
<!--stripe 是否为斑马纹 v-loading在请求数据未返回的时间有个加载的图案,提高用户体验-->
<el-table
:data="tableData"
height="90%"
stripe
v-loading="config.loading"
>
<!--第一行为序号 默认写死-->
<el-table-column label="序号" width="85">
<!--slot-scope="scope" 这里取到当前单元格,scope.$index就是索引 默认从0开始这里从1开始-->
<template slot-scope="scope">
<span style="margin-left: 10px">{{
(config.page - 1) * 20 + scope.$index + 1
}}</span>
</template>
</el-table-column>
<!--show-overflow-tooltip 当内容过长被隐藏时显示 tooltip-->
<el-table-column
show-overflow-tooltip
v-for="item in tableLabel"
:key="item.prop"
:label="item.label"
:width="item.width ? item.width : 125"
>
<!--其实可以在上面:prop="item.prop"就可以显示表单数据 这里设置插槽的方式话更加灵活 我们可以写样式-->
<template slot-scope="scope">
<span style="margin-left: 10px">{{ scope.row[item.prop] }}</span>
</template>
</el-table-column>
<!--操作-->
<el-table-column label="操作" min-width="180">
<template slot-scope="scope">
<el-button size="min" @click="handleEdit(scope.row)"
>编辑</el-button
>
<el-button size="min" type="danger" @click="handleDelete(scope.row)"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
<!--分页-->
<el-pagination
class="pager"
layout="prev, pager, next,total"
:total="config.total"
:current-page.sync="config.page"
@current-change="changePage"
:page-size="20"
></el-pagination>
</div>
</template>
<script>
// config分页数据,这里面至少包括当前页码 总数量
export default {
props: {
tableData: Array,
tableLabel: Array,
config: Object,
},
methods: {
//更新 调用父组件的 edit 方法
handleEdit(row) {
this.$emit("edit", row);
},
//删除 调用父组件的 del 方法
handleDelete(row) {
this.$emit("del", row);
},
//分页 调用父组件的 changePage 方法
changePage(page) {
this.$emit("changePage", page);
},
},
};
</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
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<!--依次是: 表格数据 表格标签数据 分页数据 列表方法 更新方法 删除方法-->
<common-table
:tableData="tableData"
:tableLabel="tableLabel"
:config="config"
@changePage="getList()"
@edit="editUser"
@del="delUser"
>
</common-table>
<script>
import CommonTable from "components/CommonTable";
export default {
data() {
return {
tableData: [
{
id: "e2de22E3-DbF4-E40C-abeF-e2ebcb74D8Df",
name: "侯娜",
addr: "四川省 阿坝藏族羌族自治州 金川县",
age: 48,
birth: "1997-09-03",
sex: 0,
sexLabel: "女",
},
{
id: "dCfaae68-bEc3-Bc3D-aC91-cc738e31e6DE",
name: "范洋",
addr: "黑龙江省 齐齐哈尔市 昂昂溪区",
age: 52,
birth: "1999-05-13",
sex: 1,
sexLabel: "男",
},
{
id: "eB9BAabF-516D-A8cb-Ff7b-E581a4C15CA3",
name: "郝磊",
addr: "甘肃省 定西市 临洮县",
age: 26,
birth: "1986-08-21",
sex: 0,
sexLabel: "女",
},
{
id: "62f9b82e-698b-ea65-e3dC-a3f6CBC24faB",
name: "顾秀英",
addr: "台湾 新北市 瑞芳区",
age: 53,
birth: "2020-09-20",
sex: 0,
sexLabel: "女",
},
{
id: "33b6b7fD-FEc4-d3c6-b1D2-5dB99F88E5b3",
name: "张军",
addr: "西藏自治区 拉萨市 尼木县",
age: 31,
birth: "2016-01-06",
sex: 1,
sexLabel: "男",
},
{
id: "5188076A-C1fa-1e7E-f9cb-daBA0cccB868",
name: "谭磊",
addr: "青海省 海南藏族自治州 贵南县",
age: 53,
birth: "1996-08-11",
sex: 1,
sexLabel: "男",
},
{
id: "DA914cCf-0CfE-25a1-e7BF-4A4A231Feb7F",
name: "高洋",
addr: "澳门特别行政区 离岛 -",
age: 25,
birth: "1995-06-21",
sex: 0,
sexLabel: "女",
},
{
id: "9A46669B-962b-EedC-c8Db-Fb49C41E5f9E",
name: "董杰",
addr: "澳门特别行政区 澳门半岛 -",
age: 46,
birth: "2004-05-10",
sex: 0,
sexLabel: "女",
},
],
tableLabel: [
{ prop: "name", label: "姓名" },
{ prop: "age", label: "年龄" },
{ prop: "sexLabel", label: "性别" },
{ prop: "birth", label: "出生日期", width: 200 },
{ prop: "addr", label: "地址", width: 320 },
],
config: {
total: 8,
loading: false,
page: 1,
pagesize: 20,
},
};
},
methods: {
getList(name = "") {
console.log("getList");
},
editUser(row = "") {
console.log("editUser");
},
delUser(page = "") {
console.log("delUser");
},
},
};
</script>
<style lang="scss" scoped></style>
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 凉月の博客!
评论