vue+iview实现可编辑表格的⽰例代码先简单说明⼀下,这个Demo引⼊的vue,iview的⽅式是标签引⼊的,没有⽤到webpack之类的构建⼯具...毕竟公司还在⽤angularjs+jq.
这也是我第⼀次写⽂章,⼤家看看思路就⾏了,要是有⼤佬指点指点就更好了
话不多说,先来个效果图
我们再看下极为简单的⽬录结构
IViewEditTable ## vue+iview 实现的可编辑表格
└── index.html ## ⾸页
└── js
└── editTable.js ## ⾸页JS
└── ivew ## iview相关
└── vue
├── axios.min.js ## axios (ajax)
├── util.js ## 与业务⽆关的纯⼯具函数包
└── vue.min.js ## vue (2.x)
⾸页html:
<!DOCTYPE html>
<html xmlns="/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>可编辑表格</title>
<link href="iview/iview.css" rel="external nofollow" rel="stylesheet" />
</head>
<body >
<div id="editTableCtrl">
<i-table :loading="loading" border :data="dataList" :columns="columnsList" stripe size="small"></i-table>
</div>
<script src="vue/axios.min.js"></script>
<script src="vue/vue.min.js"></script>
<script src="iview/iview.min.js"></script>
<script src="vue/util.js"></script>
<script src="js/editTable.js"></script>
</body>
</html>
⾸页没什么说的,都是基本的架⼦. 这是需要渲染的数据及其说明:
{
"Status": 1,
"Total": 233,
"Items": [{
"ID": 1,
"PID": 3,
"PRJCODE": "2018-001", //项⽬编号不可编辑
"PRJNAME": "淡化海⽔配套泵站", //项⽬名称⽂本输⼊框
"PRJTYPE": "基础设施", //项⽬类型下拉选项
"JSUNIT": "投资公司", //建设单位⽂本输⼊框
"FLOW_TYPE_CODE":"A02", //流程分类下拉选项,与数据库以code形式交互
"DATE_START": "2018-12-1", //开⼯时间⽇期选择
"DATE_END": "2019-12-1", //竣⼯时间⽇期选择
"CONTENT": "建设淡化海⽔配套泵站⼀座,占地⾯积约8500平⽅⽶", //建设内容多⾏输⼊框
"INVEST_ALL": "1000" //总投资数字输⼊框
}]
}
还有editTable.js的基本架⼦,$http是我为了⽅便在utils最后⼀⾏加⼊的 (angularjs⽤多了,习惯⽤\$http) Vue.prototype.utils = utils
window.$http = axios
editTable.js :
var vm = new Vue({
el: '#editTableCtrl',
data: function() {
return {
loading: true,
//表格的数据源
dataList: [],
// 列
columnsList: [],
// 增加编辑状态, 保存状态, ⽤于操作数据避免⼲扰原数据渲染
cloneDataList: []
}
},
methods: {
getData: function() {
var self = this;
self.loading = true;
$('').then(function(res) {
self.dataList = res.data.Items;
self.loading = false;
});
},
},
created: function() {
}
});
我们再来按照iview的规则编写渲染的列:
//...
/**
* @name columnsList (浏览器渲染的列)
* @author catkin
* @see www.iviewui/components/table
* @param
* {
* titleHtml : 渲染带有html的表头列: '资⾦<em class="blue" >来源</em>'
* editable : true,可编辑的列必须有字段
* option : 渲染的下拉框列表,如果需要与数据库交互的值与显⽰的值不同,须使⽤[{value:'value',label:'label'}]的形式,下⾯有例⼦
* date : 渲染成data类型 ,可选参数:
* date | daterange: yyyy-MM-dd (默认)
* datetime | datetimerange: yyyy-MM-dd HH:mm:ss
* year: yyyy
* month: yyyy-MM
* input : 渲染input类型 ,可选参数为html5所有类型 (额外增加 textarea 属性), 默认text
* handle : 数组类型, 渲染操作⽅式,⽬前只⽀持 'edit', 'delete'
* }
* @version 0.0.1
*/
columnsList: [{
width: 80,
type: 'index',
title: '序号',
align: 'center'
}, {
align: 'center',
title: '项⽬编号',
key: 'PRJCODE'
}, {
align: 'center',
title: '项⽬名称',
titleHtml: '项⽬名称 <i class="ivu-icon ivu-icon-edit"></i>',
key: 'PRJNAME',
editable: true
}, {
align: 'center',
title: '项⽬分类',
titleHtml: '项⽬分类 <i class="ivu-icon ivu-icon-edit"></i>',
key: 'PRJTYPE',
option: ['产业项⽬', '基础设施', '民⽣项⽬', '住宅项⽬'],
editable: true
}, {
align: 'center',
title: '建设单位',
titleHtml: '建设单位 <i class="ivu-icon ivu-icon-edit"></i>',
key: 'JSUNIT',
editable: true
}, {
align: 'center',
title: '流程分类',
titleHtml: '流程分类 <i class="ivu-icon ivu-icon-edit"></i>',
key: 'FLOW_TYPE_CODE',
option: [{
value: 'A01',
label: '建筑-出让'
}, {
value: 'A02',
label: '建筑-划拨'
}, {
value: 'B01',
label: '市政-绿化'
}, {
value: 'B02',
label: '市政-管线'
}],
editable: true
}, {
align: 'center',
title: '开⼯时间',
titleHtml: '开⼯时间 <i class="ivu-icon ivu-icon-edit"></i>',
key: 'DATE_START',
//这⾥在后⾯处理的时候会分割成['month','yyyy-MM']的数组,分别代表iview的DatePicker组件选择⽇期的格式与数据库传过来时页⾯显⽰的格式 date: 'month_yyyy-MM',
editable: true
}, {
align: 'center',
title: '竣⼯时间',
titleHtml: '竣⼯时间 <i class="ivu-icon ivu-icon-edit"></i>',
key: 'DATE_END',
date: 'month_yyyy-MM',
editable: true
}, {
align: 'center',
title: '建设内容',
titleHtml: '建设内容 <i class="ivu-icon ivu-icon-edit"></i>',
key: 'CONTENT',
input: 'textarea',
editable: true
}, {
align: 'center',
title: '总投资(万元)',
titleHtml: '总投资<br />(万元) <i class="ivu-icon ivu-icon-edit"></i>',
key: 'INVEST_ALL',
input: 'number',
editable: true
}, {
title: '操作',
align: 'center',
width: 150,
key: 'handle',
handle: ['edit', 'delete']
}]
//...
此时页⾯应该已经可以渲染出表格了
既然要编辑数据,并且我的需求是整⾏整⾏的编辑,⽽编辑的同时就会同步更新数据,那么问题来了
vue中, 数据更新,视图会随之更新. 想象⼀下,我在输⼊框中属于⼀个值,触发了数据更新,接着⼜触发了视图更新,那么我每次输⼊时,这个input都会失焦,毫⽆⽤户体验. 所以我们把可编辑的动态内容⽤cloneDataList渲染,静态显⽰的⽤dataList渲染
//...
self.dataList = res.data.Items;
// 简单的深拷贝,虽然map会返回新数组,但是数组元素也是引⽤类型,不能直接改,所以先深拷贝⼀份
self.cloneDataList = JSON.parse(JSON.stringify(self.dataList)).map(function(item) {
// 给每⾏添加⼀个编辑状态与保存状态, 默认都是false
item.editting = false;
item.saving = false;
return item;
});
//...
接下来,我们要根据columnsList做⼀次循环判断,根据相应的key写出不同的render函数
//全局添加
//根据value值出数组中的对象元素
function findObjectInOption(value) {
return function(item) {
return item.value === value;
}
}
/
/动态添加编辑按钮
var editButton = function(vm, h, currentRow, index) {
return h('Button', {
props: {
size: 'small',
type: currentRow.editting ? 'success' : 'primary',
loading: currentRow.saving
},
style: {
margin: '0 5px'
},
on: {
click: function() {
// 点击按钮时改变当前⾏的编辑状态, 当数据被更新时,render函数会再次执⾏,详情参考/v2/api/#render
// handleBackdata是⽤来删除当前⾏的editting属性与saving属性
var tempData = vm.handleBackdata(currentRow)
if (!currentRow.editting) {
currentRow.editting = true;
} else {
// 这⾥也是简单的点击编辑后的数据与原始数据做对⽐,⼀致则不做操作,其实更好的应该遍历所有属性并判断
if (JSON.stringify(tempData) == JSON.stringify(vm.dataList[index])) {
console.log('未更改');
return currentRow.editting = false;
}
vm.saveData(currentRow, index)
currentRow.saving = true;
}
}
}
}, currentRow.editting ? '保存' : '编辑');
};
//动态添加删除按钮
var deleteButton = function(vm, h, currentRow, index) {
return h('Poptip', {
props: {
confirm: true,
title: currentRow.WRAPDATASTATUS != '删除' ? '您确定要删除这条数据吗?' : '您确定要对条数据撤销删除吗?', transfer: true,
placement: 'left'
},
on: {
'on-ok': function() {
vm.deleteData(currentRow, index)
}
}
},
[
h('Button', {
style: {
color: '#ed3f14',
fontSize: '18px',
padding: '2px 7px 0',
border: 'none',
outline: 'none',
htmlbutton属性focus: {
'-webkit-box-shadow': 'none',
'box-shadow': 'none'
}
},
domProps: {
title: '删除'
},
props: {
size: 'small',
type: 'ghost',
icon: 'android-delete',
placement: 'left'
}
})
]);
};
//methods中添加
init: function() {
console.log('init');
var self = this;
// 使⽤$set 可以触发视图更新
/
/ 如果含有titleHtml属性将其值填⼊表头
if (item.titleHtml) {
self.$set(item, 'renderHeader', function(h, params) {
return h('span', {
domProps: {
innerHTML: lumn.titleHtml
}
});
});
}
// 如果含有操作属性添加相应按钮
if (item.handle) {
var currentRow = self.cloneDataList[param.index];
var children = [];
item.handle.forEach(function(item) {
if (item === 'edit') {
children.push(editButton(self, h, currentRow, param.index));
} else if (item === 'delete') {
children.push(deleteButton(self, h, currentRow, param.index));
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论