此时页面应该已经可以渲染出表格了
既然要编辑数据,并且我的需求是整行整行的编辑,而编辑的同时就会同步更新数据,那么问题来了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函数会再次执行,详情参考https://cn.vuejs.org/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', 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; self.columnsList.forEach(function(item) { // 使用$set 可以触发视图更新 // 如果含有titleHtml属性 将其值填入表头 if (item.titleHtml) { self.$set(item, 'renderHeader', function(h, params) { return h('span', { domProps: { innerHTML: params.column.titleHtml } }); }); } // 如果含有操作属性 添加相应按钮 if (item.handle) { item.render = function(h, param) { 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)); } }); return h('div', children); }; } //如果含有editable属性并且为true if (item.editable) { item.render = function(h, params) { var currentRow = self.cloneDataList[params.index]; // 非编辑状态 if (!currentRow.editting) { // 日期类型单独 渲染(利用工具暴力的formatDate格式化日期) if (item.date) { return h('span', self.utils.formatDate(currentRow[item.key], item.date.split('_')[1])) } // 下拉类型中value与label不一致时单独渲染 if (item.option && self.utils.isArray(item.option)) { // 我这里为了简单的判断了第一个元素为object的情况,其实最好用every来判断所有元素 if (typeof item.option[0] === 'object') { return h('span', item.option.find(findObjectInOption(currentRow[item.key])).label); } } return h('span', currentRow[item.key]); } else { // 编辑状态 //如果含有option属性 if (item.option && self.utils.isArray(item.option)) { return h('Select', { props: { // ***重点***: 这里要写currentRow[params.column.key],绑定的是cloneDataList里的数据 value: currentRow[params.column.key] }, on: { 'on-change': function(value) { self.$set(currentRow, params.column.key, value) } } }, item.option.map(function(item) { return h('Option', { props: { value: item.value || item, label: item.label || item } }, item.label || item); })); } else if (item.date) { //如果含有date属性 return h('DatePicker', { props: { type: item.date.split('_')[0] || 'date', clearable: false, value: currentRow[params.column.key] }, on: { 'on-change': function(value) { self.$set(currentRow, params.column.key, value) } } }); } else { // 默认input return h('Input', { props: { // type类型也是自定的属性 type: item.input || 'text', // rows只有在input 为textarea时才会起作用 rows: 3, value: currentRow[params.column.key] }, on: { 'on-change'(event) { self.$set(currentRow, params.column.key, event.target.value) } } }); } } }; } }); }, // 还原数据,用来与原始数据作对比的 handleBackdata: function(object) { var clonedData = JSON.parse(JSON.stringify(object)); delete clonedData.editting; delete clonedData.saving; return clonedData; }
到这里完成已经差不多了,补上保存数据与删除数据的函数