在开发过程中,前后至今遇到好几次的编辑输入框编辑情况,4.24之前的版本,虽然改进好几次操作,但是都是用render函数实现,发现有时并不是很好操作,而且隐藏好几个bug,今天(2019-7-19)发布一个新版,目前无发现bug,而且监听键盘更灵活。废话不多说,上代码
因为需要多列可编辑表格,直接用render函数,isNum代表这个数是否需要只允许输入小数点
有一点要特别注意,表格展示的数据用tableData,然后深拷贝一组数据,copyTableData,不然实际过程中发现赋值的时候,容易失去焦点
columns的代码如下:
storeColumns: [
{title: '序号', type: 'index', align: 'center', fixed: 'left', width: 60},
{title: '供应商', key: 'VenderName', align: 'center', fixed: 'left', width: 180},
{title: '商品名称', key: 'GoodsName', align: 'center', fixed: 'left', width: 180},
{title: '商品条码', key: 'BarCode', align: 'center', width: 180},
{title: '品类', key: 'CategoryName', align: 'center', width: 180},
{title: '单位/规格', key: 'SpecUnit', align: 'center', width: 180},
{title: '保质期', key: 'ShelfLife', align: 'center', width: 180},
{title: '销售量', key: 'Qty', align: 'center', width: 180},
{title: '同期总销售额', key: 'SaleValue', align: 'center', width: 180},
{title: '同期毛利额', key: 'GrossProfit', align: 'center', width: 180},
{title: '同期毛利率(%)', key: 'RateOfMargin', align: 'center', width: 180},
{title: '昨日库存总量', key: 'CloseQty', align: 'center', width: 180},
{title: '建议补货量', key: 'SRQ', align: 'center', width: 180},
{title: '订货周期', key: 'OrderCycle', align: 'center', width: 180},
{title: '门店订货量', key: 'OrderQtyShop', align: 'center', width: 180, render: (h, params) => {return this.renderInput(h, params, 'OrderQtyShop', 1)}},
{title: '预计售完时间', key: 'SellOutDate', align: 'center', width: 180, render: (h, params) => {return this.renderInput(h, params, 'SellOutDate')}},
{title: '陈列位置', key: 'POD', align: 'center', width: 180, render: (h, params) => {return this.renderInput(h, params, 'POD')}},
{title: '进价', key: 'CostPrice', align: 'center', width: 180},
{title: '平均售价', key: 'AvgPrice', align: 'center', width: 180},
{title: '计划促销价', key: 'PlanPromPrice', align: 'center', width: 180, render: (h, params) => {return this.renderInput(h, params, 'PlanPromPrice', 1)}},
{title: '备注', key: 'Notes', align: 'center', width: 280, render: (h, params) => {return this.renderInput(h, params, 'Notes')}}
],
renderInput的代码如下,如果有一些功能不需要刻意自己删除,代码有一点乱,可以取自己需求的
renderInput (h, params, values, isNum) {
// 设置一个class,方便待会进行操作dom
let ref = values + params.row._index + 'n'
return h('Input', {
class: [
`${ref}`
],
props: {
// 给予初始值
value: params.row[values],
},
on: {
'on-blur': (e) => {
// 失去焦点时赋值
this.$set(this.copyTableData[params.row._index], values, this.changeValue)
},
'on-focus': () =>{
// 获取焦点时,给changeValue中间变量赋值,且选中当前值
this.changeValue = this.copyTableData[params.row._index][values]
setTimeout(()=> {
document.getElementsByClassName(`${ref}`)[0].children[1].select()
})
}
},
nativeOn: {
keydown: (event) => {
// 监听键盘变化,input上下框可以通过上下键切换
if (event.keyCode === 38) {
if (this.cando) {
return
}
this.cando = true
setTimeout(() => {
this.cando = false
let name = values + (params.row._index - 1) + 'n'
document.getElementsByClassName(`${name}`)[0].children[1].focus()
}, 50)
}
if (event.keyCode === 40) {
if (this.cando) {
return
}
this.cando = true
setTimeout(() => {
this.cando = false
let name = values + (params.row._index + 1) + 'n'
document.getElementsByClassName(`${name}`)[0].children[1].focus()
}, 50)
}
},
input: (e) => {
// 项目要求只允许输入三位小数点,直接操作dom赋值
let val = e.target.value
if (isNum) {
val = val.replace(/[^\d.]/g, ""); //清除“数字”和“.”以外的字符
val = val.replace(/\.{2,}/g, "."); //只保留第一个. 清除多余的
val = val.replace(".", "$#$").replace(/\./g, "").replace("$#$", ".");
val = val.replace(/^(\-)*(\d+)\.(\d\d\d).*$/, '$1$2.$3');
console.log(val)
setTimeout(() =>{
document.getElementsByClassName(`${ref}`)[0].children[1].value = val
}, 2)
this.changeValue = val
} else {
this.changeValue = val
}
}
},
key: ref
})
},
// 主要利用iview 的slot进行操作
// keyup.native 监听按钮事件
// inputName 监听输入事件,主要限制数字等输入
{{row.danwei}}
{{row.danwei}}
kg
{{row.danwei}}
// 表头数据格式定义,咳咳,忽略拼音的key
tableColumns: [
{ type: 'selection', align: 'center', width: 50, fixed: 'left' },
{ title: '序号', type: 'index', width: 80, align: 'center', fixed: 'left' },
{ title: '编码', key: 'num', align: 'center', fixed: 'left', width: 100 },
{ title: '品名', key: 'pinming', align: 'center', fixed: 'left', width: 100 },
{ title: '单位', key: 'danwei', align: 'center', width: 80 },
{ title: '单价', key: 'danjia', width: 100, slot: 'danjia', renderHeader: (h, params) => this.renderHeader(h, params, '单价(元)', 'danjia') },
{ title: '数量', key: 'shuliang', slot: 'shuliang', width: 100, align: 'center' },
{ title: '金额(元)', key: 'jine', align: 'center', width: 100, renderHeader: (h, params) => this.renderHeader(h, params, '金额(元)', 'jine') },
{ title: '赠送数量', key: 'zengsong', slot: 'zengsong', width: 100, align: 'center' },
{ title: '计数', key: 'jishu', align: 'center', width: 100, slot: 'jishu', renderHeader: (h, params) => this.renderHeader(h, params, '计数', 'jishu') },
{ title: '计重', key: 'jizhong', align: 'center', width: 100, slot: 'jizhong', renderHeader: (h, params) => this.renderHeader(h, params, '计重', 'jizhong') },
{ title: '件数', key: 'jianshu', align: 'center', width: 100, slot: 'jianshu', renderHeader: (h, params) => this.renderHeader(h, params, '件数', 'jianshu') },
{ title: '原产地', key: 'yuanchandi', align: 'center', width: 150, slot: 'yuanchandi' },
{ title: '生产日期', key: 'shengcanriqi', align: 'center', width: 180, slot: 'shengcanriqi' },
{ title: '保质期', key: 'baozhiqi', align: 'center', width: 300, slot: 'baozhiqi' }
],
// 当然是假数据,哈哈哈,后端数据没来,key全部用拼音代替
tableData: [
{danwei: '头', num: 1, pinming: '品名1', danjia: 2, shuliang: 2, jine: 2, jishu: 2, jizhong: 3, jianshu: 5},
{danwei: '个', num: 1, pinming: '品名2', danjia: 2, shuliang: 2, jine: 2, jishu: 2, jizhong: 3, jianshu: 5},
{danwei: '个', num: 1, pinming: '品名2', danjia: 2, shuliang: 2, jine: 2, jishu: 2, jizhong: 3, jianshu: 5},
{danwei: '个', num: 1, pinming: '品名2', danjia: 2, shuliang: 2, jine: 2, jishu: 2, jizhong: 3, jianshu: 5},
{danwei: 'kg', num: 1, pinming: '品名3', danjia: 2, shuliang: 2, jine: 2, jishu: 2, jizhong: 3, jianshu: 5}
],
// 表头方法定义,由于个别列需要进行输入合计
renderHeader (h, params, name, key) {
return h('div', [
h('div', name),
h('div', {
style: {
'text-align': 'right'
}
}, this.addNum[key])
])
},
// 按键切换
handleKeyup (event, index, key) {
// 向上键
if (event.keyCode === 38) {
// 获取到所有class为[key]的dom列表
let doms = document.getElementsByClassName(key)
if (!index) {
index = this.copyTableData.length
}
// 选中类表中第index个,向上故而减1,dom里头包含的input,获取焦点以及选中input里的内容
let dom = doms[index - 1].getElementsByTagName('input')[0]
dom.focus()
dom.select()
}
// 向下键
if (event.keyCode === 40) {
let doms = document.getElementsByClassName(key)
if (+index === this.copyTableData.length - 1) {
index = -1
}
let dom = doms[index + 1].getElementsByTagName('input')[0]
dom.focus()
dom.select()
}
// 小键盘回车键
if (event.keyCode === 13) {
// 小键盘回车因为需要根据class判断下一个,故而有input输入框的全部需要在这按顺序声明
let keyName = ['danjia', 'shuliang', 'zengsong', 'jishu', 'jizhong', 'jianshu', 'yuanchandi', 'shengcanriqi', 'baozhiqi']
let num = 0
if (key === keyName[keyName.length - 1]) {
if (index === this.copyTableData.length - 1) {
index = 0
} else {
++index
}
} else {
keyName.map((v, i) => {
if (v === key) {
num = i + 1
}
})
}
let doms = document.getElementsByClassName(keyName[num])
let dom = doms[index].getElementsByTagName('input')[0]
dom.focus()
dom.select()
}
},
// 输入赋值,记得不直接给tableData赋值,而是深度拷贝一个,不然从新渲染时会失去焦点
inputName (value, row, index, key) {
let ret = this.regular(value)
let dom = document.getElementsByClassName(key)
setTimeout(() => {
dom[index].children[1].value = ret
})
this.copyTableData[index][key] = value
},
// 正则验证,限定输入数字,到时可根据参数选择要不要验证,这里自己看是否需要
regular (value) {
value = value.replace(/[^\d.]/g, '') // 清除"数字"和"."以外的字符
value = value.replace(/[^\d.]/g, '') // 清除"数字"和"."以外的字符
value = value.replace(/^\./g, '') // 验证第一个字符是数字而不是
value = value.replace(/\.{2,}/g, '.') // 只保留第一个. 清除多余的
value = value.replace('.', '$#$').replace(/\./g, '').replace('$#$', '.')
console.log('value2:' + value)
value = value.replace(/^(-)*(\d+)\.(\d{3}).*$/, '$1$2.$3') // 只能输入两个小数
return value
}
computed: {
addNum () {
let nums = {
jine: 0,
jishu: 0,
jizhong: 0,
jianshu: 0
}
this.copyTableData.map(v => {
nums.jine += +v.jine
nums.jishu += +v.jishu
nums.jizhong += +v.jizhong
nums.jianshu += +v.jianshu
})
return nums
}
},