当前位置:   article > 正文

Vue+Element-ui实例_可编辑表格和分页_element ui 表格页例子

element ui 表格页例子

下面是一个可以实现编辑的表格,并且该表格嵌入在form表单内,可以对已修改的内容进行保存提交;而且实现了对表格数据进行关键字搜索和分类筛选的功能,实现了前端分页的效果。

主要难点:

(1)当el-table列数据过多时,我们可以通过设置 type="expand" 和 Scoped slot 可以开启展开行功能,然后在每一行设置一个可编辑按钮,对展开的数据中的某条数据进行再编辑。

(2)当你设置可编辑按钮时,还要对此行展开状态进行判断,判断该行是否为展开,若已展开,则编辑,若未展开,则展开进行编辑。

(3)当对某一行进行编辑时,如该行未确认完成编辑,则不能对其他行再进行编辑,需要对该行确认完成编辑,才可对其他行进行编辑操作。

(4)对数据进行分页展示。

(5)对数据进行关键字搜索和根据分类对每页数据进行筛选。

(6)保存和提交数据的检验。

效果图如下:

效果图(1)
概览

效果图(2)

效果图(3)

效果图(4)

效果视频如下:

可编辑el-table表格演示视频

下面是代码部分:

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <title>可编辑表格</title>
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
  7. <script src="../vue/vue.min.js" type="text/javascript" charset="utf-8"></script>
  8. <script src="../elementUI/index.js" type="text/javascript" charset="utf-8"></script>
  9. <script src="../vue/axios.min.js" type="text/javascript" charset="utf-8"></script>
  10. <link rel="stylesheet" type="text/css" href="../elementUI/index.css" />
  11. <style type="text/css">
  12. .menu {
  13. width: 100%;
  14. height: 100%;
  15. }
  16. .container_table {
  17. width: 100%;
  18. }
  19. .el-table .cell {
  20. text-align: center;
  21. }
  22. .postForm {
  23. width: 340px;
  24. height: 40px;
  25. float: right;
  26. margin-top: -40px;
  27. }
  28. /* 展开的form样式 */
  29. .demo-table-expand label {
  30. width: 90px;
  31. color: #99a9bf;
  32. }
  33. .el-form--label-left .el-form-item__label {
  34. text-align: right;
  35. }
  36. .demo-table-expand .el-form-item {
  37. margin-right: 0;
  38. margin-bottom: 0;
  39. width: 30%;
  40. }
  41. .container_table .fy {
  42. margin-top: 20px;
  43. }
  44. </style>
  45. </head>
  46. <body>
  47. <div id="menu" class="menu">
  48. <el-container>
  49. <div class="container_table">
  50. <el-form :model="tableData" @submit.native.prevent>
  51. <el-table ref="refTable" height="500" :data="tableData.slice((currentPage-1)*pagesize,currentPage*pagesize)"
  52. style="width: 100%" @expand-change="expandChange">
  53. <el-table-column type="expand">
  54. <template slot-scope="props">
  55. <el-form label-position="left" inline class="demo-table-expand">
  56. <el-form-item label="日期">
  57. <span>{{ props.row.date }}</span>
  58. </el-form-item>
  59. <el-form-item label="姓名">
  60. <span>{{ props.row.name }}</span>
  61. </el-form-item>
  62. <el-form-item label="手机号">
  63. <span v-if="props.row.isSet">{{props.row.phone}}</span>
  64. <span v-else>
  65. <el-input clearable v-model="props.row.phone"></el-input>
  66. </span>
  67. </el-form-item>
  68. <el-form-item label="地址">
  69. <span v-if="props.row.isSet">{{props.row.address}}</span>
  70. <span v-else>
  71. <el-input type="textarea" clearable autosize v-model="props.row.address"></el-input>
  72. </span>
  73. </el-form-item>
  74. <el-form-item label="部门">
  75. <span>{{ props.row.tag }}</span>
  76. </el-form-item>
  77. </el-form>
  78. </template>
  79. </el-table-column>
  80. <el-table-column prop="date" label="日期" sortable width="120" column-key="date">
  81. </el-table-column>
  82. <el-table-column prop="name" label="姓名">
  83. </el-table-column>
  84. <el-table-column prop="phone" label="手机号">
  85. </el-table-column>
  86. <el-table-column prop="address" label="地址">
  87. </el-table-column>
  88. <el-table-column prop="tag" label="部门" width="140" :filters="sectorData" :filter-method="filterTag">
  89. <template slot-scope="scope">
  90. <el-tag size="medium" disable-transitions>{{scope.row.tag}}</el-tag>
  91. </template>
  92. </el-table-column>
  93. <el-table-column prop="searchInfo" width="200">
  94. <template slot="header" slot-scope="scope">
  95. <el-input clearable v-model="search" prefix-icon="el-icon-search" size="mini" placeholder="输入姓名关键字搜索" @input="searchName" />
  96. </template>
  97. <template slot-scope="scope">
  98. <el-button :disabled="btnDisabled" plain icon="el-icon-edit" v-if="scope.row.isSet" @click="handleEdit(scope.$index, scope.row)"
  99. size="mini">编辑</el-button>
  100. <el-button plain v-else @click="saveEdit(scope.$index, scope.row)" size="mini">确定</el-button>
  101. </template>
  102. </el-table-column>
  103. </el-table>
  104. </el-form>
  105. <el-pagination class="fy" :current-page="currentPage" :page-sizes="[5, 10, 20]" :page-size="pagesize" layout="total, sizes, prev, pager, next, jumper"
  106. @size-change="handleSizeChange" @current-change="handleCurrentChange" :total="tableData.length" background>
  107. </el-pagination>
  108. <div class="postForm">
  109. <el-button icon="el-icon-finished" type="primary" @click="postForm">提交</el-button>
  110. <el-button icon="el-icon-check" type="success" @click="saveForm">保存</el-button>
  111. <el-button icon="el-icon-back" type="info" @click="backtrack">撤回</el-button>
  112. </div>
  113. </div>
  114. </el-container>
  115. </div>
  116. </body>
  117. <script type="text/javascript">
  118. var vm = new Vue({
  119. el: '#menu',
  120. data() {
  121. return {
  122. /* 表格数据 */
  123. tableData: [],
  124. /* 原始表格数据 */
  125. oldtableData: [],
  126. /* 部门数据 */
  127. sectorData: [],
  128. pagesize: 5, //每页的数据条数
  129. currentPage: 1, //默认开始页面
  130. search: '', //搜索关键字
  131. btnDisabled: false,
  132. };
  133. },
  134. methods: {
  135. /* 部门筛选 */
  136. filterTag(value, row, column) {
  137. console.log(value);
  138. // console.log(row);
  139. return row.tag === value;
  140. },
  141. /* 分页方法 */
  142. handleSizeChange(val) {
  143. // console.log(`每页 ${val} 条`);
  144. this.pagesize = val;
  145. },
  146. handleCurrentChange: function(val) {
  147. // console.log(`当前页: ${val}`);
  148. this.currentPage = val;
  149. },
  150. /* 姓名关键字搜索 */
  151. searchName(search) {
  152. var newList = [];
  153. // console.log(search);
  154. if (search != '') {
  155. vm.oldtableData.forEach(item => {
  156. if (item.name.indexOf(search) != -1) {
  157. //空字符串包含在所有字符串中,因此控制会返回所有列表
  158. newList.push(item);
  159. }
  160. });
  161. return this.tableData = newList;
  162. } else {
  163. return this.tableData = this.oldtableData;
  164. }
  165. },
  166. /* 更改每一行的张开/关闭状态 */
  167. expandChange(row, expandedRows) {
  168. row.isExpand = !row.isExpand;
  169. },
  170. /* 开启编辑单元格 */
  171. handleEdit(index, row, e) {
  172. for (const i of this.tableData) {
  173. if (!i.isSet) {
  174. return this.$message.warning('请先保存当前编辑项');
  175. }
  176. }
  177. if (!row.isExpand) {
  178. //调用,table的方法,展开/折叠 行
  179. this.$refs.refTable.toggleRowExpansion(row);
  180. }
  181. row.isSet = false;
  182. },
  183. /* 保存单元格,进行编辑验证 */
  184. saveEdit(index, row, column) {
  185. // console.log(row);
  186. if ((row.address.replace(/\s+/g, '') == '' || (row.phone.replace(/\s+/g, '') == ''))) {
  187. row.isSet = false;
  188. return this.$message.error('数据不能为空');
  189. } else {
  190. row.isSet = true;
  191. }
  192. //调用,table的方法,展开/折叠 行
  193. this.$refs.refTable.toggleRowExpansion(row);
  194. },
  195. /* 提交表单 */
  196. postForm() {
  197. if (!this.btnDisabled) {
  198. return this.$message.error('请先保存');
  199. } else {
  200. this.$confirm('是否提交?', '提示', {
  201. confirmButtonText: '确定',
  202. cancelButtonText: '取消',
  203. type: 'warning'
  204. }).then((action) => {
  205. this.$message({
  206. type: 'success',
  207. message: '提交成功!',
  208. });
  209. if (action === 'confirm') {
  210. //提交表单
  211. console.log(this.tableData);
  212. }
  213. }).catch(() => {
  214. this.$message({
  215. type: 'info',
  216. message: '已取消提交!'
  217. });
  218. });
  219. }
  220. },
  221. /* 保存表单 */
  222. saveForm() {
  223. for (var i = 0; i < this.tableData.length; i++) {
  224. if (!this.tableData[i].isSet) {
  225. this.$message.warning('请先保存当前编辑项');
  226. return this.btnDisabled = false;
  227. } else {
  228. this.btnDisabled = true;
  229. }
  230. }
  231. },
  232. /* 撤回保存 */
  233. backtrack() {
  234. this.btnDisabled = false;
  235. },
  236. /* 获取内容数据 */
  237. getTableData() {
  238. axios.get('../data/tableData.json', {})
  239. .then(function(res) {
  240. for (var i = 0; i < res.data[0].tableData.length; i++) {
  241. // 添加单元格是否可以编辑的属性值
  242. res.data[0].tableData[i].isSet = true;
  243. // 添加行是否展开的属性值
  244. res.data[0].tableData[i].isExpand = false;
  245. }
  246. console.log(res.data);
  247. // 赋值
  248. vm.tableData = res.data[0].tableData;
  249. vm.oldtableData = res.data[0].tableData;
  250. vm.sectorData = res.data[1].sectorData;
  251. }).catch(function(error) {
  252. console.log(error);
  253. });
  254. }
  255. },
  256. mounted() {
  257. // 获取内容数据
  258. this.getTableData();
  259. }
  260. });
  261. </script>
  262. </html>

data数据如下:

  1. [{
  2. "tableData": [{
  3. "date": "2016-05-01",
  4. "name": "张晓明",
  5. "phone": "18852067999",
  6. "address": "上海市普陀区金沙江路 11 弄",
  7. "tag": "设计三所"
  8. }, {
  9. "date": "2016-05-02",
  10. "name": "李米中",
  11. "phone": "18852067999",
  12. "address": "上海市普陀区金沙江路 12 弄",
  13. "tag": "设计二所"
  14. }, {
  15. "date": "2016-05-03",
  16. "name": "张晓明",
  17. "phone": "18852067999",
  18. "address": "上海市普陀区金沙江路 13 弄",
  19. "tag": "南京小组"
  20. }, {
  21. "date": "2016-05-04",
  22. "name": "李米中",
  23. "phone": "18852067999",
  24. "address": "上海市普陀区金沙江路 14 弄",
  25. "tag": "设计一所"
  26. }, {
  27. "date": "2016-05-05",
  28. "name": "向飒飒",
  29. "phone": "18852067999",
  30. "address": "上海市普陀区金沙江路 15 弄",
  31. "tag": "南京小组"
  32. }, {
  33. "date": "2016-05-06",
  34. "name": "王小虎",
  35. "phone": "18852067999",
  36. "address": "上海市普陀区金沙江路 16 弄",
  37. "tag": "设计三所"
  38. },
  39. {
  40. "date": "2016-05-07",
  41. "name": "张晓明",
  42. "phone": "18852067999",
  43. "address": "上海市普陀区金沙江路 17 弄",
  44. "tag": "设计二所"
  45. }, {
  46. "date": "2016-05-08",
  47. "name": "李米中",
  48. "phone": "18852067999",
  49. "address": "上海市普陀区金沙江路 18 弄",
  50. "tag": "南京小组"
  51. }, {
  52. "date": "2016-05-09",
  53. "name": "向飒飒",
  54. "phone": "18852067999",
  55. "address": "上海市普陀区金沙江路 19 弄",
  56. "tag": "设计一所"
  57. }, {
  58. "date": "2016-05-10",
  59. "name": "王小虎",
  60. "phone": "18852067999",
  61. "address": "上海市普陀区金沙江路 20 弄",
  62. "tag": "设计三所"
  63. },
  64. {
  65. "date": "2016-05-11",
  66. "name": "张晓明",
  67. "phone": "18852067999",
  68. "address": "上海市普陀区金沙江路 21 弄",
  69. "tag": "设计三所"
  70. }, {
  71. "date": "2016-05-12",
  72. "name": "李米中",
  73. "phone": "18852067999",
  74. "address": "上海市普陀区金沙江路 22 弄",
  75. "tag": "设计二所"
  76. }, {
  77. "date": "2016-05-13",
  78. "name": "向飒飒",
  79. "phone": "18852067999",
  80. "address": "上海市普陀区金沙江路 23 弄",
  81. "tag": "南京小组"
  82. }, {
  83. "date": "2016-05-14",
  84. "name": "王小虎",
  85. "phone": "18852067999",
  86. "address": "上海市普陀区金沙江路 24 弄",
  87. "tag": "设计一所"
  88. }, {
  89. "date": "2016-05-15",
  90. "name": "王小虎",
  91. "phone": "18852067999",
  92. "address": "上海市普陀区金沙江路 25 弄",
  93. "tag": "设计二所"
  94. }
  95. ]
  96. },
  97. {
  98. "sectorData": [{
  99. "itemid": 10001,
  100. "text": "设计一所",
  101. "value": "设计一所"
  102. }, {
  103. "itemid": 10002,
  104. "text": "设计二所",
  105. "value": "设计二所"
  106. },
  107. {
  108. "itemid": 10003,
  109. "text": "设计三所",
  110. "value": "设计三所"
  111. },
  112. {
  113. "itemid": 10004,
  114. "text": "南京小组",
  115. "value": "南京小组"
  116. }
  117. ]
  118. }
  119. ]

代码中使用的框架有:

vue链接:vue

elementUI链接:elementUI

axios.js链接:axios.min.js

主要的难点的简单讲解:

(1)在el-table中通过设置 type="expand" 和 Scoped slot 可以开启展开行功能,el-table-column 的模板会被渲染成为展开行的内容,展开行可访问的属性与使用自定义列模板时的 Scoped slot 相同。然后在表格的最后一列设置两个按钮,但是两个按钮要根据 v-if="scope.row.isSet"来进行“编辑和确定”的切换。

(2)在每条数据中设置一个isExpand="false"的属性,默认该行为未展开状态,当展开或关闭该行时,记录下该状态,如下:

/* 更改每一行的张开/关闭状态 */
            expandChange(row, expandedRows) {
                    row.isExpand = !row.isExpand;
            },

(3)在点击编辑按钮时,对其他行进行验证,如其他行存在编辑状态,则先保存对其他行的编辑,然后才能对该行进行编辑;点击改变某条数据变为可编辑状态,确认时,对数据进行非空校验。如下:

/* 开启编辑单元格 */
                handleEdit(index, row, e) {
                    for (const i of this.tableData) {
                        if (!i.isSet) {
                            return this.$message.warning('请先保存当前编辑项');
                        }
                    }
                    if (!row.isExpand) {
                        //调用,table的方法,展开/折叠 行
                        this.$refs.refTable.toggleRowExpansion(row);
                    }
                    row.isSet = false;

         },
        /* 保存单元格,进行编辑验证 */
                saveEdit(index, row, column) {
                    // console.log(row);
                    if ((row.address.replace(/\s+/g, '') == '' || (row.phone.replace(/\s+/g, '') == ''))) {
                        row.isSet = false;
                        return this.$message.error('数据不能为空');
                    } else {
                        row.isSet = true;
                    }
                    //调用,table的方法,展开/折叠 行
                    this.$refs.refTable.toggleRowExpansion(row);
                },

 (4)分页展示的核心代码是在获取的数据后,写入到el-table中,如下红色部分:

<el-table ref="refTable" height="500" :data="tableData.slice((currentPage-1)*pagesize,currentPage*pagesize)"
                         style="width: 100%" @expand-change="expandChange">

/* 分页方法 */
                handleSizeChange(val) {
                    // console.log(`每页 ${val} 条`);
                    this.pagesize = val;
                },
                handleCurrentChange: function(val) {
                    // console.log(`当前页: ${val}`);
                    this.currentPage = val;
                },

(5) 此案例中是对姓名中的关键字进行搜索,对字符串使用indexOf属性,对搜索到的数据添加到一个新的数组中,并返回给el-table;在筛选中,是element中的,可去案例中参考。如下:

<el-table-column prop="tag" label="部门" width="140" :filters="sectorData" :filter-method="filterTag">
                       <template slot-scope="scope">
                                    <el-tag size="medium" disable-transitions>{{scope.row.tag}}</el-tag>
                        </template>
        </el-table-column>

<template slot="header" slot-scope="scope">
               <el-input clearable v-model="search" prefix-icon="el-icon-search" size="mini" placeholder="输入姓名关键字搜索" @input="searchName" />
         </template>

/* 部门筛选 */
                filterTag(value, row, column) {
                    console.log(value);
                    // console.log(row);
                    return row.tag === value;
                },

/* 姓名关键字搜索 */
                searchName(search) {
                    var newList = [];
                    // console.log(search);
                    if (search != '') {
                        vm.oldtableData.forEach(item => {
                            if (item.name.indexOf(search) != -1) {
                                //空字符串包含在所有字符串中,因此控制会返回所有列表
                                newList.push(item);
                            }
                        });
                        return this.tableData = newList;
                    } else {
                        return this.tableData = this.oldtableData;
                    }
                },

(6)下面就是对保存和提交的简单校验,在提交时要确认数据已经保存,保存的数据不可再编辑

/* 提交表单 */
                postForm() {
                    if (!this.btnDisabled) {
                        return this.$message.error('请先保存');
                    } else {
                        this.$confirm('是否提交?', '提示', {
                            confirmButtonText: '确定',
                            cancelButtonText: '取消',
                            type: 'warning'
                        }).then((action) => {
                            this.$message({
                                type: 'success',
                                message: '提交成功!',

                            });
                            if (action === 'confirm') {
                                //提交表单
                                console.log(this.tableData);
                            }
                        }).catch(() => {
                            this.$message({
                                type: 'info',
                                message: '已取消提交!'
                            });
                        });
                    }
                },
                /* 保存表单 */
                saveForm() {
                    for (var i = 0; i < this.tableData.length; i++) {
                        if (!this.tableData[i].isSet) {
                            this.$message.warning('请先保存当前编辑项');
                            return this.btnDisabled = false;
                        } else {
                            this.btnDisabled = true;
                        }
                    }
                },
                /* 撤回保存 */
                backtrack() {
                    this.btnDisabled = false;
                },

 这次vue小实例就写到这,如果内容、代码有不妥的地方,望斧正,谢谢。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/103159
推荐阅读
相关标签
  

闽ICP备14008679号