vue/iview的table单元格可编辑,可上下键切换,小键盘enter可选中下一个

本文主要是介绍vue/iview的table单元格可编辑,可上下键切换,小键盘enter可选中下一个,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在开发过程中,前后至今遇到好几次的编辑输入框编辑情况,4.24之前的版本,虽然改进好几次操作,但是都是用render函数实现,发现有时并不是很好操作,而且隐藏好几个bug,今天(2019-7-19)发布一个新版,目前无发现bug,而且监听键盘更灵活。废话不多说,上代码

 

2019-04-24版本

因为需要多列可编辑表格,直接用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,方便待会进行操作domlet 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 = truesetTimeout(() => {this.cando = falselet 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 = truesetTimeout(() => {this.cando = falselet name = values + (params.row._index + 1) + 'n'document.getElementsByClassName(`${name}`)[0].children[1].focus()}, 50)}},input: (e) => {// 项目要求只允许输入三位小数点,直接操作dom赋值let val = e.target.valueif (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})
},

2019-7-19效果如图

 1.HTML主要用slot进行操作,需要添加一个class,方便后续dom操作

// 主要利用iview 的slot进行操作
// keyup.native 监听按钮事件
// inputName 监听输入事件,主要限制数字等输入
<Table :columns='tableColumns' :data='tableData'><template slot-scope='{ row, index }' slot='danjia'><Input @input="inputName($event, row, index, 'danjia')" class="danjia" @keyup.native="handleKeyup($event, index, 'danjia')" :value='row.danjia'></Input></template><template slot-scope='{ row, index }' slot='shuliang'><Input @input="inputName($event, row, index, 'shuliang')" class="shuliang" @keyup.native="handleKeyup($event, index, 'shuliang')" :value='row.shuliang'></Input><span>{{row.danwei}}</span></template><template slot-scope='{ row, index }' slot='zengsong'><Input @input="inputName($event, row, index, 'zengsong')" class="zengsong" @keyup.native="handleKeyup($event, index, 'zengsong')" :value='row.zengsong'></Input></template><template slot-scope='{ row, index }' slot='jishu'><Input @input="inputName($event, row, index, 'jishu')" class="jishu" :value='row.jishu' @keyup.native="handleKeyup($event, index, 'jishu')"></Input><span>{{row.danwei}}</span></template><template slot-scope='{ row, index }' slot='jizhong'><Input @input="inputName($event, row, index, 'jizhong')" class="jizhong" :value='row.jizhong' @keyup.native="handleKeyup($event, index, 'jizhong')"></Input><span>kg</span></template><template slot-scope='{ row, index }' slot='jianshu'><Input @input="inputName($event, row, index, 'jianshu')" class="jianshu" @keyup.native="handleKeyup($event, index, 'jianshu')" :value='row.jianshu'></Input><span>{{row.danwei}}</span></template><template slot-scope='{ row, index }' slot='yuanchandi'><Input @input="inputName($event, row, index, 'yuanchandi')" class="yuanchandi"  @keyup.native="handleKeyup($event, index, 'yuanchandi')" :value='row.yuanchandi'></Input></template><template slot-scope='{ row, index }' slot='shengcanriqi'><DatePicker type="date" placeholder="Select date" @keyup.native="handleKeyup($event, index, 'shengcanriqi')" class="shengcanriqi"></DatePicker><!-- <Input @input="inputName($event, row, index, 'shengcanriqi')" class="shengcanriqi" @keyup.native="handleKeyup($event, index, 'shengcanriqi')" :value='row.shengcanriqi'></Input> --></template><template slot-scope='{ row, index }' slot='baozhiqi'><Input @input="inputName($event, row, index, 'baozhiqi')" class="baozhiqi" @keyup.native="handleKeyup($event, index, 'baozhiqi')" :value='row.baozhiqi'></Input></template></Table>

2.表头和表格数据

// 表头数据格式定义,咳咳,忽略拼音的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}
],

3. methods方法的定义,直接操作dom,小键盘enter键向右既下一个,注意需要按顺序写一个对象

// 表头方法定义,由于个别列需要进行输入合计
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 = 0if (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
}

4.computed计算属性监听头部数字变化

computed: {addNum () {let nums = {jine: 0,jishu: 0,jizhong: 0,jianshu: 0}this.copyTableData.map(v => {nums.jine += +v.jinenums.jishu += +v.jishunums.jizhong += +v.jizhongnums.jianshu += +v.jianshu})return nums}
},

 

这篇关于vue/iview的table单元格可编辑,可上下键切换,小键盘enter可选中下一个的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/702096

相关文章

Vue3组件中getCurrentInstance()获取App实例,但是返回null的解决方案

《Vue3组件中getCurrentInstance()获取App实例,但是返回null的解决方案》:本文主要介绍Vue3组件中getCurrentInstance()获取App实例,但是返回nu... 目录vue3组件中getCurrentInstajavascriptnce()获取App实例,但是返回n

JS+HTML实现在线图片水印添加工具

《JS+HTML实现在线图片水印添加工具》在社交媒体和内容创作日益频繁的今天,如何保护原创内容、展示品牌身份成了一个不得不面对的问题,本文将实现一个完全基于HTML+CSS构建的现代化图片水印在线工具... 目录概述功能亮点使用方法技术解析延伸思考运行效果项目源码下载总结概述在社交媒体和内容创作日益频繁的

前端CSS Grid 布局示例详解

《前端CSSGrid布局示例详解》CSSGrid是一种二维布局系统,可以同时控制行和列,相比Flex(一维布局),更适合用在整体页面布局或复杂模块结构中,:本文主要介绍前端CSSGri... 目录css Grid 布局详解(通俗易懂版)一、概述二、基础概念三、创建 Grid 容器四、定义网格行和列五、设置行

前端下载文件时如何后端返回的文件流一些常见方法

《前端下载文件时如何后端返回的文件流一些常见方法》:本文主要介绍前端下载文件时如何后端返回的文件流一些常见方法,包括使用Blob和URL.createObjectURL创建下载链接,以及处理带有C... 目录1. 使用 Blob 和 URL.createObjectURL 创建下载链接例子:使用 Blob

Vuex Actions多参数传递的解决方案

《VuexActions多参数传递的解决方案》在Vuex中,actions的设计默认只支持单个参数传递,这有时会限制我们的使用场景,下面我将详细介绍几种处理多参数传递的解决方案,从基础到高级,... 目录一、对象封装法(推荐)二、参数解构法三、柯里化函数法四、Payload 工厂函数五、TypeScript

Pytest多环境切换的常见方法介绍

《Pytest多环境切换的常见方法介绍》Pytest作为自动化测试的主力框架,如何实现本地、测试、预发、生产环境的灵活切换,本文总结了通过pytest框架实现自由环境切换的几种方法,大家可以根据需要进... 目录1.pytest-base-url2.hooks函数3.yml和fixture结论你是否也遇到过

Spring Boot项目中结合MyBatis实现MySQL的自动主从切换功能

《SpringBoot项目中结合MyBatis实现MySQL的自动主从切换功能》:本文主要介绍SpringBoot项目中结合MyBatis实现MySQL的自动主从切换功能,本文分步骤给大家介绍的... 目录原理解析1. mysql主从复制(Master-Slave Replication)2. 读写分离3.

Vue3使用router,params传参为空问题

《Vue3使用router,params传参为空问题》:本文主要介绍Vue3使用router,params传参为空问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录vue3使用China编程router,params传参为空1.使用query方式传参2.使用 Histo

CSS Padding 和 Margin 区别全解析

《CSSPadding和Margin区别全解析》CSS中的padding和margin是两个非常基础且重要的属性,它们用于控制元素周围的空白区域,本文将详细介绍padding和... 目录css Padding 和 Margin 全解析1. Padding: 内边距2. Margin: 外边距3. Padd

CSS will-change 属性示例详解

《CSSwill-change属性示例详解》will-change是一个CSS属性,用于告诉浏览器某个元素在未来可能会发生哪些变化,本文给大家介绍CSSwill-change属性详解,感... will-change 是一个 css 属性,用于告诉浏览器某个元素在未来可能会发生哪些变化。这可以帮助浏览器优化