前一段时间,有博友在我那篇封装Vue Element的table表格组件的博文下边留言说有没有那种“表格行内编辑”的封装组件,我当时说我没有封装过这样的组件,因为一直以来在实际开发中也没有遇到过这样的需求,但我当时给他提供了一个思路。

时间过去了这么久,公司的各种需求也不停地往外冒,什么地图图表、表格行内编辑、动态新增表单等等,只有你做不到,没有产品想不到,贼鸡儿累。再加上很快又要过年了,大家工作的心态基本呈直线下滑趋势而玩忽职守、尸位素餐以致饱食终日。只是话虽如此,但越是到年底,需求开发却越是紧急,平时可能一两周的开发任务,现在却要压缩到一周左右就要完成,苦不堪言。这不公司刚刚评完了需求,年前就让开发完成并提测,说是等年后来了,测试同学搞定后就上线。

话说这表格行内编辑,不光要在表格一行内实现文字的编辑,而且还要实现可新增一行或多行表格行内编辑的功能,同时还希望实现表格行内表单的正则验证。听着复杂,想着实现起来也复杂,其实不然,我们完全可以参照element动态增减表单项的模式来搞。原理大概其就是利用每一行的索引来设置每一个表单所需的prop和v-model,如果需要新增一行可编辑的表格行,只需往数据源数组中push一行相同的数据即可。

多说一句,年底了,这马上就要放假了,公司里很多人已经回老家了,我们这些留下来的人有一个算一个实在是没心思工作,但你以为这就可以放松了?可以摸摸鱼、划划水了?美得你。听没听说过一个女人:亚里士多德的妹妹,珍妮玛士多?

不过话又说回来,我们作为打工人,本职工作就是打工。你不工作,你还有脸称自己是打工人吗?你不是打工人,你连饭都吃不到嘴里,你还有脸说自己是“干饭人”?你还真想“十年一觉扬州梦”?东方不亮西方亮,二哈啥样你啥样。好好干活吧你!!!

这两天,趁着中午休息的时候,就把前一段时间加班加点完成的开发需求中的一个表格行内编辑的封装组件给发出来,兹当是给大家又提供了一个轮子亦或是多了一种选择吧。

照例先来张效果图:



1、封装的可编辑表格组件TableForm.vue

<template>
<el-form :model="form" ref="form" size="small">
<el-form-item v-if="!isDetail">
<el-button type="primary" @click="add">新增</el-button>
</el-form-item>
<el-table :data="form.list" border>
<el-table-column v-for="x in columns" :key="x.prop" :label="x.label" :prop="x.prop" v-bind="x.attr">
<template slot-scope="{row, $index}">
<t-text v-if="!x.edit" :row="{x, row}" />
<template v-else>
<t-text v-if="isDetail" :row="{x, row}" />
<t-input v-else v-model="row[`${x.prop}`]" v-bind="componentAttrs(x, $index)" class="width100" />
</template>
</template>
</el-table-column>
</el-table>
<el-form-item v-if="!isDetail" style="margin-top:18px;">
<el-button type="primary" @click="submit">提交</el-button>
<el-button @click="reset">重置</el-button>
</el-form-item>
</el-form>
</template> <script>
export default {
props: {config: Object},
computed: {
isDetail(){
const { isDetail = false } = this.config || {}
return isDetail
}
},
components: {
TInput: {
functional: true,
props: ['prop', 'rules', 'type', 'options'],
render: (h, {props: { prop, rules, type, options = [] }, data, listeners: {input = _.identity}}) => {
const children = h => {
if(type == 'select') return h('el-select', {class: 'width100', props: {...data.attrs}, on: {change(v){input(v)}}}, options.map(o => h('el-option', {props: {...o, key: o.value}})))
else if(type == 'checkbox') return h('el-checkbox-group', {props: {...data.attrs}, on: {input(v) {input(v)}}}, options.map(o => h('el-checkbox', {props: {...o, label: o.value, key: o.value}}, [o.label])))
else if(type == 'switch') return h('el-switch', {props: {activeColor: '#13ce66'}, ...data})
else if(type == 'date') return h('el-date-picker', {props: {type: 'date', valueFormat: 'yyyy-MM-dd',}, ...data})
return h('el-input', data)
} return h('el-form-item', {props: {prop, rules}}, [children(h)])
}
},
TText: {
functional: true,
props: ['row'],
render: (h, {props: { row: { x, row } }}) => {
if(!row[`${x.prop}`]) return h('span', '-')
else if(x.format && typeof x.format == 'function') return h('span', x.format(row))
else return h('span', row[`${x.prop}`])
}
},
},
data(){
const { columns = [], data = [] } = this.config || {}
return {
form: {
list: (data && data.length > 0) ? data.map(n => columns.reduce((r, c) => ({...r, [c.prop]: n[c.prop] == false ? n[c.prop] : (n[c.prop] || (c.type == 'checkbox' ? [] : ''))}), {})) : [columns.reduce((r, c) => ({...r, [c.prop]: c.type == 'checkbox' ? [] : (c.type == 'switch' ? false : '')}), {})]
},
columns,
rules: columns.reduce((r, c) => ({...r, [c.prop]: { required: c.required == false ? false : true, message: c.label + '必填'}}), {})
}
},
methods: {
componentAttrs(item, idx){
const {type, label} = item, attrs = Object.fromEntries(Object.entries(item).filter(n => !/^(prop|edit|label|attr|format)/.test(n[0]))),
placeholder = (/^(select|el-date-picker)/.test(type) ? '请选择' : '请输入') + label
Object.assign(attrs, {prop: `list.${idx}.${item.prop}`, rules: this.rules[item.prop]})
return {...attrs, placeholder}
},
add(){
const { columns = [] } = this.config || {}, obj = columns.reduce((r, c) => ({...r, [c.prop]: c.type == 'checkbox' ? [] : (c.type == 'switch' ? false : '')}), {})
this.form.list.push(obj)
},
submit(){
this.$refs.form.validate((valid) => {
if (valid) {
this.$emit('submit', this.form.list)
}
})
},
reset(){
this.$refs.form.resetFields();
},
}
}
</script>
<style scoped>
.width100{width: 100%;}
</style>

本次封装的可编辑的表格组件,基本把大家在表格中内嵌的一些常用表单如:input输入框、select下拉框/选择器、日期选择器、checkbox复选框、switch开关等都封装进去了,大家只需根据自己的实际需求去添加不同的type就可以了,如果你还有其他的表单组件需要加进去,你自己按照我这个套路给封装进去就完事了。

另外,本次封装有几个点,大家注意下:

1)本次封装的组件,不光可以实现表格行内的编辑,同样当你编辑完成下次需要回显这些数据的时候,你只需多传一个isDetail参数就可以了,该参数默认为false。你往这儿看:

computed: {
isDetail(){
const { isDetail = false } = this.config || {}
return isDetail
}
}

页面当中也加了这个isDetail计算属性的判断。

2)也许有同学已经注意到了,在本次封装所用到的data数据对象中,有一串很长的实现方法:

list: (data && data.length > 0) ? data.map(n => columns.reduce((r, c) => ({...r, [c.prop]: n[c.prop] == false ? n[c.prop] : (n[c.prop] || (c.type == 'checkbox' ? [] : ''))}), {})) : [columns.reduce((r, c) => ({...r, [c.prop]: c.type == 'checkbox' ? [] : (c.type == 'switch' ? false : '')}), {})]

这段代码是干嘛滴的呢?

它两种用途:

  • 没有数据需要回显时的可编辑表格的数据源

  • 有数据需要回显时的可编辑表格的数据源

n[c.prop] == false ? n[c.prop] : ...这段代码的判断或许有人会疑惑。大家要知道element的switch组件的值是非false既true的,不加这个判断,当数据回显时,switch为false的值就回显不出来。

2、使用方法:

<template>
<TableForm :config="config" @submit="submit" style="margin:20px;" />
</template> <script>
import TableForm from "./TableForm"; const repayTypeList = {
averageCapital: '等额本金',
averageInterest: '等额本息'
},
columns = [
{ prop: 'repaymentMethod', label: '还款方式', attr: {width: '180'}, format: ({ repaymentMethod }) => repayTypeList[repaymentMethod]},
{ prop: 'productPer', label: '期数', attr: {width: '180'}, format: ({ productPer }) => `${+ productPer + 1}期(${productPer}个月)` },
{ prop: 'costRate', label: '成本利率', attr: {minWidth: '110'}, edit: true, type: 'select', options: [{label: '5%', value: '5'}, {label: '10%', value: '10'}] },
{ prop: 'price', label: '单价', attr: {minWidth: '110'}, edit: true },
{ prop: 'company', label: '所属公司', attr: {minWidth: '110'}, edit: true },
{ prop: 'product', label: '产品', attr: {minWidth: '110'}, edit: true, type: 'checkbox', options: [{label: '橘子', value: 'orange'}, {label: '苹果', value: 'apple'}] },
{ prop: 'date', label: '日期', attr: {minWidth: '110'}, edit: true, type: 'date', required: false, },
{ prop: 'opt', label: '锁定', attr: {minWidth: '110'}, edit: true, type: 'switch' },
] export default {
components: {
TableForm,
},
data(){
return {
config: {
columns,
data: [],
},
}
},
created(){
this.config.data = [
{repaymentMethod: 'averageCapital', productPer: '1', price: '5', company: '谷歌上海', date: '2021-01-03', opt: false},
{repaymentMethod: 'averageInterest', productPer: '3', costRate: '10', price: '', company: '雅虎北京', opt: true},
{repaymentMethod: 'averageInterest', productPer: '5', costRate: '5', price: '100', company: '上海你真美', opt: false},
]
},
methods: {
submit(res){
console.log(res)
}
}
}
</script>

在使用的过程中,有一个需要注意的地方就是在columns数组中有一个required的属性,该属性默认为true,这个属性主要是用来控制当前的表单是否需要必填的校验的。还有需要说明的是,本次封装只是封装了每个表单是否需要必填的正则校验rules,没有对其他的正则验证如数字类型、小数位数等加以封装,如有需要你可以自行添加。

最后,通过子组件触发父组件的submit函数的方式来获取表格中表单的输入值。

封装Vue Element的可编辑table表格组件的更多相关文章

  1. 封装Vue Element的table表格组件

    上周分享了几篇关于React组件封装方面的博文,这周就来分享几篇关于Vue组件封装方面的博文,也好让大家能更好地了解React和Vue在组件封装方面的区别. 在封装Vue组件时,我依旧会交叉使用函数式 ...

  2. 封装Vue Element的form表单组件

    前两天封装了一个基于vue和Element的table表格组件,阅读的人还是很多的,看来大家都是很认同组件化.高复用这种开发模式的,毕竟开发效率高,代码优雅,逼格高嘛.虽然这两天我的心情很糟糕,就像& ...

  3. [js开源组件开发]table表格组件

    table表格组件 表格的渲染组件,demo请点击http://lovewebgames.com/jsmodule/table.html,git源码请点击https://github.com/tian ...

  4. 使用 iview Table 表格组件修改操作的显示隐藏

    使用 iview Table 表格组件修改操作的显示隐藏,如下图 1.如何设置 table 操作按后台传入的状态值去渲染 不同的按钮? 解决方法 我们在vue2中,动态渲染html 使用的是 retu ...

  5. Vue + Element-ui实现后台管理系统(5)---封装一个Form表单组件和Table表格组件

    封装一个Form表单组件和Table组件 有关后台管理系统之前写过四遍博客,看这篇之前最好先看下这四篇博客.另外这里只展示关键部分代码,项目代码放在github上: mall-manage-syste ...

  6. 封装Vue Element的dialog弹窗组件

    我本没有想着说要封装一个弹窗组件,但有同行的朋友在问我,而且弹窗组件也确实在项目开发中用的比较多.思前想后,又本着样式统一且修改起来方便的原则,还是再为大家分享一个我所封装的弹窗组件吧. 其实,并不是 ...

  7. Vue3学习(十一)之 table表格组件的使用

    一.前言 大约有两周没学习更文,不是懒,而是没心情,相亲路屡战屡败,着实很影响心情. 我想这世上对我而言,最难的事,莫过于恋爱结婚了,再一次经历了见光死的高光时刻. 二.又见Ant Design Vu ...

  8. VUE+Element UI实现简单的表格行内编辑效果

    原理是通过Css控制绑定的输入控件与显示值,在选中行样式下对控件进行隐藏或显示 <!DOCTYPE html> <html> <head> <meta cha ...

  9. 封装Vue Element的upload上传组件

    本来昨天就想分享封装的这个upload组件,结果刚写了两句话,就被边上的同事给偷窥上了,于是在我全神贯注地写分享的时候他就神不知鬼不觉地突然移动到我身边,腆着脸问我在干啥呢.卧槽你妈,当场就把我吓了一 ...

随机推荐

  1. livy提交spark应用

      spark-submit的使用shell时时灵活性较低,livy作为spark提交的一种工具,是使用接口或者java客户端的方式提交,可以集成到web应用中 1.客户端提交的方式 http://l ...

  2. <input type="image">表单提交2次 重复插入数据问题

    写一个表单提交用到图片:两种代码. <input type="image" src="xxx.gif"onclick="return dosub ...

  3. 商品类型的下拉框绑定一个事件,通过ajax获取属性

    html代码这么写 <!-- 商品属性 --> <table cellspacing="1" cellpadding="3" width=&q ...

  4. 基于nginx实现web服务器的双机热备

    1.适用场景 对于部署重要的服务,会使用两台服务器,互相备份,共同执行同一服务.当一台服务器出现故障时,可以由另一台服务器承担服务任务,从而在不需要人工干预的情况下,自动保证系统能持续提供服务.双机热 ...

  5. springboot集成轻量级权限认证框架sa-token

    sa-token是什么? sa-token是一个JavaWeb轻量级权限认证框架,主要解决项目中登录认证.权限认证.Session会话等一系列由此衍生的权限相关业务.相比于其他安全性框架较容易上手. ...

  6. 直播预告 | 开源的云原生开发环境 —— Nocalhost

    直播来啦!本次云原生学院邀请到腾讯云 CODING DevOps 后端工程师王炜为大家分享<开源的云原生开发环境 -- Nocalhost>. 直播信息 讲师:王炜 - 腾讯云 CODIN ...

  7. 【Web】CSS实现鼠标悬停实现显示与隐藏 特效

    鼠标悬停实现显示与隐藏特效 简单记录 - 慕课网 Web前端 步骤四:鼠标悬停实现显示与隐藏特效 初步掌握定位的基本使用,以及CSS选择器更高级的运用,完成一个网页中必会的鼠标经过隐藏显示特效. 实现 ...

  8. 【EXPDP】指定导出,只导出函数,导出的时候加上where条件过滤

    expdp导出的时候可以使用parfile这个参数,在parfile中添加想要的导出信息: 这里简单写了几句: vim test.par include=function     --导出函数 inc ...

  9. 【Linux】ssh互信脚本

    使用互信脚本的时候,需要敲回车,但是shell脚本无法满足,所以需要用到expect脚本 rpm -qa | grep expect 如果没有的话,直接用yum安装即可 yum install exp ...

  10. linux命名小技巧(持续更新)

    一   向某个文件批量加入内容 1.1 向/etc/wxm文件添加一大段内容可以使用这个命令 [root@registry easyrsa3]# cat <<EOF >varsset ...