我们在项目中经常会用到对于表格的增删查改操作,以下使用vue2+elementui来实现表格的增删查改
表格的基本属性
基础表格如下:(其中需要注意的是当el-table元素中注入data对象数组后,在el-table-column中用prop属性来对应对象中的键名即可填入数据,用label属性来定义表格的列名。可以使用width属性来定义列宽。)
<template><el-table:data="tableData"style="width: 100%"><el-table-columnprop="date"label="日期"width="180"></el-table-column><el-table-columnprop="name"label="姓名"width="180"></el-table-column><el-table-columnprop="address"label="地址"></el-table-column></el-table></template><script>export default {data() {return {tableData: [{date: '2016-05-02',name: '王小虎',address: '上海市普陀区金沙江路 1518 弄'}, {date: '2016-05-04',name: '王小虎',address: '上海市普陀区金沙江路 1517 弄'}, {date: '2016-05-01',name: '王小虎',address: '上海市普陀区金沙江路 1519 弄'}, {date: '2016-05-03',name: '王小虎',address: '上海市普陀区金沙江路 1516 弄'}]}}}</script>
使用带斑马纹的表格,可以更容易区分出不同行的数据。
stripe属性可以创建带斑马纹的表格。它接受一个Boolean,默认为false,设置为true即为启用。
带边框表格:
默认情况下,Table 组件是不具有竖直方向的边框的,如果需要,可以使用border属性,它接受一个Boolean,设置为true即可启用。
带状态表格
可以通过指定 Table 组件的 row-class-name 属性来为 Table 中的某一行添加 class,表明该行处于某种状态。
<template><el-table:data="tableData"style="width: 100%":row-class-name="tableRowClassName"><el-table-columnprop="date"label="日期"width="180"></el-table-column><el-table-columnprop="name"label="姓名"width="180"></el-table-column><el-table-columnprop="address"label="地址"></el-table-column></el-table>
</template><style>.el-table .warning-row {background: oldlace;}.el-table .success-row {background: #f0f9eb;}
</style><script>export default {methods: {tableRowClassName({row, rowIndex}) {if (rowIndex === 1) {return 'warning-row';} else if (rowIndex === 3) {return 'success-row';}return '';}},data() {return {tableData: [{date: '2016-05-02',name: '王小虎',address: '上海市普陀区金沙江路 1518 弄',}, {date: '2016-05-04',name: '王小虎',address: '上海市普陀区金沙江路 1518 弄'}, {date: '2016-05-01',name: '王小虎',address: '上海市普陀区金沙江路 1518 弄',}, {date: '2016-05-03',name: '王小虎',address: '上海市普陀区金沙江路 1518 弄'}]}}}
</script>
以上代码的效果是
具体的逻辑如下:(通过指定 Table 组件的 row-class-name 属性来为 Table 中的某一行添加 class,表明该行处于某种状态。下面这个函数传入的是一个对象,row表示的是每一行的数据信息,rowIndex表示的是索引下标。一下表示行标为1 的显示warning-row的style效果,行标为3的显示成功的效果)
tableRowClassName({row, rowIndex}) {if (rowIndex === 1) {return 'warning-row';} else if (rowIndex === 3) {return 'success-row';}return '';}
我们可以在这里改需求,比如说如果想要奇数偶数页不同,我们可以改变函数
tableRowClassName ({ row, rowIndex }) {if (rowIndex%2=== 0) {return 'warning-row';} else {return 'success-row';}return '';}
再比如修改日期为具体某一天的颜色
// 日期是五月一号的改颜色tableRowClassName ({ row, rowIndex }) {if (row.date=== '2016-05-01') {return 'warning-row';} else {return 'success-row';}return '';}
固定表头
只要在el-table元素中定义了height属性,即可实现固定表头的表格,而不需要额外的代码。
固定列
固定列需要使用fixed属性,它接受 Boolean 值或者leftright,表示左边固定还是右边固定。
固定列和表头可以同时使用,只需要将上述两个属性分别设置好即可。
排序
在列中设置sortable属性即可实现以该列为基准的排序,接受一个Boolean,默认为false。
筛选
在列中设置filters,filter-method属性即可开启该列的筛选,filters 是一个数组,filter-method是一个方法,它用于决定某些数据是否显示,会传入三个参数:value, row 和 column。
<template><el-table:data="tableData"border:row-class-name="tableRowClassName"style="width: 100%"><!-- 其中这个prop一定要和下面tableData中的键保持一致 --><el-table-columnprop="date"label="日期"sortablewidth="180":filters="[{ text: '2016-05-01', value: '2016-05-01' }, { text: '2016-05-02', value: '2016-05-02' }, { text: '2016-05-03', value: '2016-05-03' }, { text: '2016-05-04', value: '2016-05-04' }]":filter-method="filterHandler"></el-table-column><el-table-columnprop="name"label="姓名"width="180"></el-table-column><el-table-columnprop="address"label="地址"></el-table-column><el-table-columnprop="tag"label="标签":filters="tagFilter":filter-method="filterHandler"filter-placement="bottom-end"><template slot-scope="scope">//对表格里面的数据进行处理的话需要用到template,对于这个数据我们是不方便自定义的,如果要对数据进行更多的自定义,我们就可以使用template;scope相当于是一整个数据对象//下面的意思是拿到的数据等于家,就显示primary这种样式,否则后面一种样式<el-tag:type="scope.row.tag === '家' ? 'primary' : 'success'"disable-transitions>{{ scope.row.tag }}</el-tag></template></el-table-column></el-table></template><script>
export default {name: 'Navbar',data() {return {tableData: [{date: '2016-05-02',name: '王小虎',address: '上海市普陀区金沙江路 1518 弄',tag: '家'}, {date: '2016-05-04',name: '王小虎',address: '上海市普陀区金沙江路 1517 弄',tag: '公司'}, {date: '2016-05-01',name: '王小虎',address: '上海市普陀区金沙江路 1519 弄',tag: '家'}, {date: '2016-05-03',name: '王小虎',address: '上海市普陀区金沙江路 1516 弄',tag: '公司'}]};},computed: {// filter中的数据是静态的,但是大多数项目中都是动态的,所以上面的filter需要进行变化tagFilter () {// 此时数据重复,需要进行降重处理// return this.tableData.map(v=>({ text: v.tag, value: v.tag }))let map = new Map();for (let item of this.tableData) {if (!map.has(item.tag)) {map.set(item.tag,item)}};// 但是当前map是一个二维数组,需要进行转换let data = [...map.values()]return data.map(v=>({ text: v.tag, value: v.tag }))}},methods: {// value代表的是当前的数据,row代表的是整个对象,column表示的是表格的特性(可以拿到某个属性的名字)filterHandler (value, row, column) {const property = column['property'];// 这个的意思就是从表格里面筛选出来和value相同的值return row[property] === value; // row[property]:就比如说我拿到tableData中的date ,即tableData[date]}
},
};
</script>
动态数据的增删查改
我们使用json-server模拟请求以及请求回来的过程。详情请看json-server的入门
- 拿到数据展示到页面
<template> <el-table:data="tableData"borderstyle="width: 100%"><!-- 其中这个prop一定要和下面tableData中的键保持一致 --><el-table-columnprop="title"label="文章标题"width="180"></el-table-column><el-table-columnprop="user"label="姓名"width="180"></el-table-column><el-table-columnprop="date"label="日期"sortablewidth="180"></el-table-column><el-table-columnprop="id"label="ID"></el-table-column><el-table-columnprop="check"label="状态"></el-table-column></el-table></template><script>
import axios from 'axios';
export default {name: 'Navbar',data() {return {//动态数据需要对应传过来的键名tableData: []};},methods: {},created () {axios.get('http://localhost:3009/userList').then(res => {// this.tableData = res;console.log(res.data);this.tableData = res.data;})}
};
</script><style>
</style>
我们会发现没有状态的值,就算展示也不能直接展示布尔值,在这里我们可以用到标签
<el-table-columnprop="check"label="状态"><template slot-scope="scope"><el-tag:type="scope.row.check === 'false' ? 'primary' : 'success'"disable-transitions>{{ scope.row.check }}</el-tag></template></el-table-column>
接着要进行文本格式化,转化为用户能够识别的文字。这个文本格式化要借助过滤器,然后通过管道的思想把它加添加进去
filters: {checkFilter (v) {switch (v) {case true:return '已发表'case false:return '未发表'default:return '未发表'}}},
<el-tag:type="scope.row.check ? 'success':'primary' "disable-transitions>{{ scope.row.check| checkFilter }}</el-tag>
最后的效果:
增加操作项(编辑和删除)
<el-table-column label="操作"><template slot-scope="scope"><el-buttonsize="mini"@click="handleEdit(scope.$index, scope.row)">编辑</el-button><el-buttonsize="mini"type="danger"@click="handleDelete(scope.$index, scope.row)">删除</el-button></template></el-table-column>
我们将添加项放到最顶上
<el-buttontype="success"roundsize="mini"@click="handleSet('add',null)">增加</el-button>
但是这个时候出现了一个问题,vscode代码行会有很多红色的波浪行(原因是代码和vetur插件的格式不对应所以导致出现红色波浪线)解决办法有:1.在template下用一个div标签包裹住我们所写的代码,或者用el-card包裹住也可以。 2.设置vetur,将以下三个选项的勾选全部取消掉
但是,事实证明虽然没有红色波浪线了,但是运行的时候仍然会报错。所以最好还是采用第一种方法解决。
添加和编辑
首先可以先捋顺一下添加和编辑的思路,添加的话,弹出的对话框中的数据都是空的,而编辑的话里面则是都有之前的数据的
所以我们在添加点击事件的时候
<!-- 添加 --><el-buttontype="success"roundsize="mini"@click="handleSet('add',null)">增加</el-button><!-- 编辑 --><el-buttonsize="mini"@click="handleSet('update',row)">编辑</el-button>
添加弹框(思路是:如果先通过三元运算符来判断是添加还是编辑,如果是添加的话就需要弹出来的框里面没有内容,如果是编辑的话就显示之前的内容;visible.sync这个是用来判断这个对话框是否弹出,默认不弹出false,触发了点击事件以后就将其变为true。其中还form表示的是整个弹框对象,当然里面有哪些内容还是要取决于tableData,比如table里面有标题title,姓名name,日期date,id,check状态等这些变量,那么我们的form里面就要在这个变量范围内,本次用的是form.user,form.title,form.date,form.check)
<el-dialog:title="state=='add'?'添加':'编辑'":visible.sync="dialogTableVisible"><!-- 其中下面这个form代表的是整个弹框对象 --><el-form :model="form"><el-form-item label="发布作者"><el-input v-model="form.user"></el-input></el-form-item><el-form-item label="文章标题"><el-input v-model="form.title"></el-input></el-form-item><el-form-item label="日期"><el-date-pickerv-model="form.date"type="date"placeholder="选择日期"></el-date-picker></el-form-item><el-form-item label="状态"><el-switchv-model="form.check"active-color="#13ce66"inactive-color="#ff4949"></el-switch></el-form-item></el-form><divslot="footer"class="dialog-footer"><el-button @click="dialogTableVisible = false">取 消</el-button><el-buttontype="primary"@click="dialogTableVisible = false">确 定</el-button></div></el-dialog>
其中点击事件中,我们先要看是哪种状态,我们要把是add还是update传入到我们的state中,来判断到底是要添加还是编辑,接着将弹窗状态变为true
methods: {handleSet (type, row) { //设置数据this.state = type;this.dialogTableVisible = true; //弹框的状态}},
结果为:点击添加,添加的弹窗如下;点击编辑,编辑的弹窗也如下(我们可以看到编辑的弹窗应该要有之前原本的内容,但是现在还没有加进来)
所以我们要在点击事件中,要判断类型,如果是添加则form的值为空,如果是编辑则form的值为row,见下面代码的最后一行
handleSet (type, row) { //设置数据this.state = type;this.dialogTableVisible = true; //弹框的状态type == 'add' ? this.form = {} : this.form = row;}
此时我们再试一次:
另外我们还可以看一下状态,此时未发表的状态是红色按钮,已发表的是绿色按钮。
但是此时还有一个bug(当我们修改了编辑中的日期,我们会发现表格中的日期会变成undefined,为什么会这样呢?原因在于这一块涉及到了深浅拷贝,简单来讲就是B复制了A,修改A时,如果B发生了变化就是浅拷贝,如果没有变化就是深拷贝)
解决办法:加扩展运算符扩展运算符是深拷贝还是浅拷贝?
handleSet (type, row) { //设置数据this.state = type;this.dialogTableVisible = true; //弹框的状态type == 'add' ? this.form = {} : this.form = { ...row };}
然后我们可以进行添加或者编辑操作了,但是现在我们的添加和编辑是同一个,那么到底是放到添加还是编辑里面呢?接下来就聊一聊弹框中数据的处理,这就是弹框中“确定”的处理。针对编辑和添加共用一个弹框的处理。
为“确定”按钮添加点击事件
<el-buttontype="primary"@click="updateData()">确 定</el-button>
我们可以通过接口文档,数据的添加是post请求,数据的编辑是put请求,
async updateData () { //提交(可能是编辑的,也有可能是添加的)let method = this.state == 'add' ? 'post' : 'put'; //判断状态,如果是添加就是post,否则就是putlet res = await axios({ //在里面要发送请求,拿到具体的数据,里面包含以下几种method: method, //请求的类型,如果是添加就是post,编辑就是puturl: 'data/${this.state}', //后面的值不确定是add还是update,所以可以通过${this.state}来获取data: this.form //具体的数据对象})}this.userList(); //写完以后再次调用数据的查询
我们会发现上面新增的时间出现问题,所以我们需要进行时间的转换,在过滤器filters中写
dateFilter (v) {let d = new Date(v);let timer = d.getFullYear() + '-' + (d.getMonth() + 1) + '-' + (d.getDate());return timer;}
然后在日期上面添加一个template
<el-table-columnprop="date"label="日期"sortablewidth="180"><template slot-scope={row}>{{ row.date |dateFilter}}</template></el-table-column>
结果如下: