封装Vue Element的form表单组件
前两天封装了一个基于vue和Element的table表格组件,阅读的人还是很多的,看来大家都是很认同组件化、高复用这种开发模式的,毕竟开发效率高,代码优雅,逼格高嘛。虽然这两天我的心情很糟糕,就像“懂王”怼记者:“你是一个糟糕的记者;CNN,Fake news”一样的心情,但我还是忍着难受的心情来工作和分享,毕竟工作是饭碗,分享也能化解我糟糕透顶的心情。
今天,就来分享一下基于vue和Element所封装的form表单组件,其中所用到的技术,在上一篇文章封装Vue Element的table表格组件中已介绍的差不多了,今天再来多讲一个vue的动态组件component,关于动态组件component的介绍,vue官方倒是很吝啬,就只是给了一个例子来告诉我们如何使用而已。我们可以把它理解成一个占位符,其具体展示什么,是有is
attribute来实现,比如官网给的例子:
<component v-bind:is="currentTabComponent"></component>
在上述示例中,currentTabComponent可以包括:
已注册组件的名字
或一个组件的选项对象
就酱,对它的介绍完了。
如果你还想了解更多,可以去vue官网查看。
接下来就是封装的具体实现,照例先来张效果图:
1、封装的form表单组件Form.vue:
<template>
<el-form ref="form" :model="form" :rules="rules" size="small" :label-position="'top'">
<el-row :gutter="20">
<el-col :lg="8" :md="12" :sm="24" v-for="(x, i) in formItems" :key="i">
<el-form-item :label="x.label" :prop="x.prop">
<component v-model="form[x.prop]" v-bind="componentAttrs(x)" class="width-full" />
</el-form-item>
</el-col>
</el-row>
<div class="searchBtn">
<el-button class="filter-item" @click="reset">重置</el-button>
<el-button class="filter-item" type="primary" @click="submit">查询</el-button>
</div>
</el-form>
</template>
<script>
import { fromEntries } from '@/utils'
export default {
props: {
config: Object,
},
components: {
selectBar: {
functional: true,
props: {value: String, list: Array, callback: Function},
render(h, {props: {value = '', list = [], callback}, data: {attrs = {}}, listeners: {input}}){
return h('el-select', {class: 'width-full', props: {value, ...attrs}, on: {change(v) {input(v); callback(v)}}}, list.map(o => h('el-option', {props: {...o, key: o.value}})))
}
},
checkbox: {
functional: true,
props: {value: Boolean, desc: String },
render(h, {props: {value = '', desc = ''}, data: {attrs = {}}, listeners: {input}}){
return h('el-checkbox', {props: {value, ...attrs}, on: {change(v) {input(v)}}}, desc)
}
},
checkboxGroup: {
functional: true,
props: {value: Array, list: Array},
render(h, {props: {value = [], list = []}, data: {attrs = {}}, listeners: {input}}){
return h('el-checkbox-group', {props: {value, ...attrs}, on: {input(v) {input(v)}}}, list.map(o => h('el-checkbox', {props: {...o, label: o.value, key: o.value}}, [o.label])))
}
},
radioGroup: {
functional: true,
props: {value: String, list: Array },
render(h, {props: {value = '', list = []}, data: {attrs = {}}, listeners: {input}}){
return h('el-radio-group', {props: {value, ...attrs}, on: {input(v) {input(v)}}}, list.map(o => h('el-radio', {props: {...o, key: o.label}}, [o.value])))
}
},
},
data(){
let { columns, data } = this.config;
return {
TYPE: {
select: {
is: 'selectBar',
clearable: true, //是否可清空,默认为false不可清空
},
text: {
is: 'el-input',
clearable: true,
},
switch: {
is: 'el-switch',
},
checkbox: {
is: 'checkbox',
clearable: true,
},
checkboxGroup: {
is: 'checkboxGroup',
clearable: true,
},
radioGroup: {
is: 'radioGroup',
clearable: true,
},
daterange: {
is: 'el-date-picker',
type: 'daterange',
valueFormat: 'yyyy-MM-dd',
rangeSeparator: '至',
startPlaceholder: '开始日期',
endPlaceholder: '结束日期',
editable: false,
},
date: {
is: 'el-date-picker',
type: "date",
valueFormat: 'yyyy-MM-dd',
editable: false,
},
auto: {
is: 'el-autocomplete'
}
},
form: columns.reduce((r, c) => Object.assign(r, {[c.prop]: data[c.prop] ? data[c.prop] : (c.is == 'checkboxGroup' ? [] : null)}), {}),
rules: columns.reduce((r, c) => ({...r, [c.prop]: c.rules ? c.rules : []}), {}),
}
},
computed: {
formItems() {
return this.config.columns;
},
},
methods: {
componentAttrs(item) {
let {is = 'text', label} = item, map = fromEntries(Object.entries(item).filter(n => !/^(label|prop|is|rules)/.test(n[0]))),
placeholder = (/^(select|el-date-picker)/.test(is) ? '请选择' : '请输入') + label;
return {...map, ...this.TYPE[is], placeholder}
},
reset() {
this.$refs.form.resetFields();
},
submit() {
this.$refs.form.validate(valid => valid && this.$emit('submit', this.form));
},
geRules(){
let rules = {};
this.config.columns.forEach(c => {
let {prop, rules: ruleList = [], required = false} = c;
rules[prop] = ruleList;
required && ruleList.unshift({required, message: `${c.label}不能为空`});
})
return { rules };
},
}
};
</script>
<style scoped>
.width-full{width: 100%;}
</style>
在封装时有一个Object.fromEntries的方法不兼容ie,而我们公司又要求项目可以兼容ie(我们公司的ie基本都是ie11),所以只能自己封装了一个fromEntries方法。
export const fromEntries = arr => {
if (Object.prototype.toString.call(arr) === '[object Map]') {
console.log(1)
let result = {};
for (const key of arr.keys()) {
result[key] = arr.get(key);
}
return result;
}
if(Array.isArray(arr)){
let result = {}
arr.map(([key,value]) => {
result[key] = value
})
return result
}
throw 'Uncaught TypeError: argument is not iterable';
}
2、使用已封装的表单组件:
<template>
<Form :config="config" @submit="getList" ref="form" />
</template>
<script>
import Form from "./Form";
const statusLlist = [
{label: '未提交', value: "0"},
{label: '待审批', value: "1"},
{label: '已通过', value: "2", disabled: true}
]
export default {
components: {
Form,
},
data() {
const confimPass = (rule, value, callback) => {
if (value === '') {
callback(new Error('请再次输入密码'));
} else if (value !== this.$refs.form.form.password) {
callback(new Error('两次输入密码不一致!'));
} else {
callback();
}
};
return {
config: {
columns: [
{ prop: "name", label: "借款人名称", is: "auto", fetchSuggestions: this.querySearch },
{ prop: "certificateId", label: "统一信用代码", rules: [{required: true, message: '请输入统一信用代码'}] },
{ prop: 'date', label: "日期", is: 'date', },
{ prop: 'status', label: "状态", is: 'select', list: statusLlist, callback: r => this.statusChange(r) },
{ prop: "password", label: "密码", type: 'password' },
{ prop: "confimPass", label: "确认密码", type: 'password', rules: [{validator: confimPass}] },
{ prop: 'remark', label: "备注", type: 'textarea' },
{ prop: "email", label: "邮箱", rules: [{ required: true, message: '请输入邮箱地址' }, { type: 'email', message: '请输入正确的邮箱地址' }] },
{ prop: 'love', label: '爱好', is: 'checkboxGroup', list: [{label: '篮球', value: "0"}, {label: '排球', value: "1"}, {label: '足球', value: "2", disabled: true}] },
],
data: {
name: '小坏',
certificateId: '222',
status: '0',
love: ['0']
}
},
}
},
methods: {
querySearch(q, cb){
if (!q) {cb([]);return}
},
getList(res){
console.log(res)
},
statusChange(r){
console.log(r)
},
},
}
</script>
本次封装的form表单组件,基本考虑到了在日常开发中会经常使用到的表单组件,如果还有其他的需求,可自行添加。另外,本次封装也对表单的回显(返显)做了实现,比如我们在编辑数据时,需要将被修改的数据显示在表单中,本次封装就充分考虑到了这一点,只要你在传给封装的form组件的参数中加一个data参数,并将需要回显的数据名称一一对应并赋值就可以了。
封装Vue Element的form表单组件的更多相关文章
- 封装react antd的form表单组件
form表单在我们日常的开发过程中被使用到的概率还是很大的,比如包含了登录.注册.修改个人信息.新增修改业务数据等的公司内部管理系统.而在使用时这些表单的样式如高度.上下边距.边框.圆角.阴影.高亮等 ...
- Vue + Element-ui实现后台管理系统(5)---封装一个Form表单组件和Table表格组件
封装一个Form表单组件和Table组件 有关后台管理系统之前写过四遍博客,看这篇之前最好先看下这四篇博客.另外这里只展示关键部分代码,项目代码放在github上: mall-manage-syste ...
- Vue+Element的动态表单,动态表格(后端发送配置,前端动态生成)
Vue+Element的动态表单,动态表格(后端发送配置,前端动态生成) 动态表单生成 ElementUI官网引导 Element表单生成 Element动态增减表单,在线代码 关键配置 templa ...
- Form( 表单) 组件
本节课重点了解 EasyUI 中 Form(表单)组件的使用方法, 这个组件不依赖于任何组件.一. 加载方式表单组件只能在 JS 区域设置,首先定义一张表单.<form id="box ...
- 第二百二十一节,jQuery EasyUI,Form(表单)组件
jQuery EasyUI,Form(表单)组件 学习要点: 1.加载方式 2.属性列表 3.事件列表 4.方法列表 本节课重点了解 EasyUI 中 Form(表单)组件的使用方法,这个组件不依赖于 ...
- Django form表单 组件
目录 Django form表单 组件 Form 组件介绍 普通方式手写注册功能 使用form组件实现注册功能 Form 常用字段与插件 常用字段(必备) 字段参数(必备) 内置验证(必备) 自定义效 ...
- Vue 2.x折腾记 - (17) 基于Ant Design Vue 封装一个配置式的表单组件
前言 写了个类似上篇搜索的封装,但是要考虑的东西更多. 具体业务比展示的代码要复杂,篇幅太长就不引入了. 效果图 2019-04-25 添加了下拉多选的渲染,并搜索默认过滤文本而非值 简化了渲染的子组 ...
- 从后端到前端之Vue(六)表单组件
表单组件 做项目的时候会遇到一个比较头疼的问题,一个大表单里面有好多控件,一个一个做设置太麻烦,更头疼的是,需求还总在变化,一会多选.一会单选.一会下拉的,变来变去的烦死宝宝了. 那么怎么解决这个问题 ...
- vue3 element-plus 配置json快速生成form表单组件,提升生产力近600%(已在公司使用,持续优化中)
️本文为博客园社区首发文章,未获授权禁止转载 大家好,我是aehyok,一个住在深圳城市的佛系码农♀️,如果你喜欢我的文章,可以通过点赞帮我聚集灵力️. 个人github仓库地址: https:gi ...
随机推荐
- 利用updatexml()报错注入mysql
基本介绍一下updatexml() updatexml(XML_document, XPath_string, new_value) XML_document是文档对象的名称 XPath_string ...
- scrapy分布式浅谈+京东示例
scrapy分布式浅谈+京东示例: 学习目标: 分布式概念与使用场景 浅谈去重 浅谈断点续爬 分布式爬虫编写流程 基于scrapy_redis的分布式爬虫(阳关院务与京东图书案例) 环境准备: 下载r ...
- 本地建立mysql服务器
这里可以学到 : 搭建一个mysql的后台服务器,构建自己的本地数据库表,可以满足一些自己学习增删改查的简单需求 1.打开mysql官网 https://www.mysql.com/downloa ...
- Rsync服务详解
Rsync简介 什么是rsync? Rsync是一款开源的.快速的.多功能的.可实现全量及增量的本地或远程数据同步备份的优秀工具.Rstync软件适用于unix/linux/windows等多种操作系 ...
- ABC 162 F Select Half dp 贪心
LINK:Select Half 考试的时候调了一个小时给调自闭了 原来是dp的姿势不太对. 首先 容易发现 奇数最多空2个位置 偶数最多空1一个位置 然后 设f[i][j][k]表示第i个数选了没有 ...
- dfs树
dfs树是解决图中带环的利器. 前天CF的F题就是dfs树,但是当时我没有认真思考 觉着找到一个环过于困难 当时没有想到 也没理解dfs树的意义. 对于一张无向图求出一个dfs树 这个树有两种边 树边 ...
- ThreadLocal面试六连问
转自:码农沉思录 中高级阶段开发者出去面试,应该躲不开ThreadLocal相关问题,本文就常见问题做出一些解答,欢迎留言探讨. ThreadLocal为Java并发提供了一个新的思路, 它用来存储T ...
- 7月15日考试 题解(链表+状压DP+思维题)
前言:蒟蒻太弱了,全打的暴力QAQ. --------------------- T1 小Z的求和 题目大意:求$\sum\limits_{i=1}^n \sum\limits_{j=i}^n kth ...
- 读源码从简单的集合类之ArrayList源码分析。正确认识ArrayList
一.查看源码的方法 1.看继承结构 看这个类的层次结构,处于一个什么位置,可以在自己心里有个大概的了解. 我是有idea查看的, eg:第一步: 第二步: 第三步:查看子类或者继承关系:F4 2.看构 ...
- Tutte 定理与 Tutte–Berge 公式
Tutte theorem 图 \(G=(V,E)\) 有完美匹配当且仅当满足 \(\forall U\subseteq V,o(G-U)\le|U|,o(X)\) 表示 X 子图的奇连通块数. Tu ...