项目基于vue和element-ui,所以必须在您使用的项目总入口优先导入element-ui才能使用。
别问我为什么写这个项目,我不想码代码,最多写一个对象传递进去,能达到我的目的就可以了,不能再多了,我要节省时间玩游戏享受人生...
我在这个项目里面码那么多字是因为我很多次自己都已经忘记了我对象的结构是怎样的,所以写详细点自己能在以后使用的时候更快回想起来这个祖传代码是怎么用的而不至于总是骂自己。
- 表单中的select、cascader和cascaderpanel宽度为 element-ui 的默认宽度,必须导入css样式文件才能使宽度为100%或者在参数部分指定各个表单组件的样式或者style宽度为100%才行。
a. 导入css文件方式,在总的main.js入口文件加入
import 'vic-form/dist/VicForm.css'
b. 参数配置方式
组件传入的 vdata 对象,其中的 vdata.form.data 中的各个组件的style可以直接配置宽度尺寸,也可以使用class来配置宽度,但是必须注意你编写的组件style中是否使用了scoped,如果使用了则需要在编写样式的时候使用样式穿透
- 识别是否为手机移动端,如果不单独设置 vdata.mobileWidth 参数,则默认手机移动端的模态框宽度为100%。
yarn add vic-form
所有的表单项都是 Element 的表单组件,设置 vdata.form.data 中的各个组件的 formtype 属性。
- hide类型,隐藏此字段不显示,但是可以底层控制其提交此字段数据或者修改其值;
- input类型,Input 输入框,其type可设置成其他的输入框类型;
- number类型,InputNumber 计数器;
- inputsearch类型,输入搜索框;
- date类型,日期选择框,如果想使用日期和时间选择框,type设置为datetime即可;
- time类型,时间选择框;
- textarea类型,多行文本框;
- checkbox类型,多选框;
- checkboxGroup类型,一组多选框;
- radio类型,单选框;
- radioGroup类型,一组单选框;
- select类型,下拉选择框;
- cascader类型,级联选择框;
- cascaderpanel类型,级联选择面板;
- switch类型,switch开关;
- slider类型,slider滑块;
- rate类型,rate评分打星;
- color类型,颜色选择组件;
- file类型,文件上传
- button类型,按钮
- divider类型,分割线,也可使用hr
- checkboxButton类型,按钮样式多选框
- checkboxButtonGroup类型,一组按钮样式多选框
- html类型,自定义html代码
- ue类型,vue-ueditor-wrap组件,UE编辑器
- selectGroup类型,分组下拉选择框;
- slot类型,插槽,直接编写指定部分;
- image类型,图片,仅用于展示;
- images类型,图片组,仅用于展示;
- vdata对象顶级参数,除开以下列出的参数,Element的Dialog组件的属性值都可以配置在此处,具体参考Element的Dialog组件
参数名 | 必填 | 类型 | 默认值 | 备注 |
---|---|---|---|---|
id | true | String | 空 | 组件的ID |
title | true | String | 空 | 模态框的标题文字 |
show | true | Boolean | 空 | 用于控制是否显示模态框 |
form | true | Object | 空 | 表单 |
type | false | String | 空 | 设置为'div'之后就只是html页面中添加显示表单了,其他字符串或者不设置就是Element的Dialog显示表单 |
titleHtml | false | String | 空 | div模式表单的标题,使用html字符串即可 |
width | false | String | 空 | Dialog或者Div的宽度,默认是50%,移动端是100% |
style | false | Object | 空 | Div的Style设置,用对象形式编写即可 |
redraw | false | Boolean | 空 | textarea区域文字需要手动控制刷新 |
mobileWidth | false | String | '100%' | 模态框的移动端宽度,不设置此字段的时候默认为100% |
content | false | String | 空 | 文字显示 |
btn | false | Array | 空 | 模态框底部按钮组,如果只是展示表单可以不配置此字段 |
... | false | 未知 | 空 | 参考Element的Dialog组件的属性值 |
- vdata.form属性,表单相关的
参数名 | 必填 | 类型 | 默认值 | 备注 |
---|---|---|---|---|
data | true | Array | 空 | 表单项目,不配置此参数则表单不会有任何元素出现 |
rules | false | Object | 空 | 表单验证规则 |
... | false | 未知 | 空 | 参考Element的Form组件的属性值 |
- 表单子项Form-Item属性
参数名 | 必填 | 类型 | 默认值 | 备注 |
---|---|---|---|---|
label | true | String | 空 | 表单子项目的文字描述 |
formtype | true | String | 空 | 表单子项目的类型 |
noLabel | false | Boolean | false | 表单label是否显示 |
labelWidth | false | String | 空 | 表单label的宽度 |
name | true | String | 空 | 表单子项目绑定的name,依靠此值锁定该表单子项目的 |
value | true | 依靠类型来定 | 空 | 表单子项目绑定的值,数据类型靠子项目的类型来定 |
type | false | String | 空 | 表单子项目的类型为input类型的时候,type就可以再次定义该input框是什么类型 |
col | false | String/Number | 24 | 此项设置占据的宽度,默认占据一行的宽度 |
offset | false | String/Number | 0 | 左侧的间隔格数,默认0 |
push | false | String/Number | 0 | 向右移动格数,默认0 |
pull | false | String/Number | 0 | 向左移动格数,默认0 |
xs | false | String/Number | 24 | xs视图下的宽度 |
sm | false | String/Number | 24 | sm视图下的宽度 |
md | false | String/Number | 24 | md视图下的宽度 |
lg | false | String/Number | 24 | lg视图下的宽度 |
xl | false | String/Number | 24 | xl视图下的宽度 |
... | false | 未知 | 空 | 参考Element的Form-Item的属性值 |
- vdata.btn属性,每个按钮的参数
参数名 | 必填 | 类型 | 默认值 | 备注 |
---|---|---|---|---|
text | true | String | 空 | 按钮的显示文本 |
click | true | String | 空 | 点击按钮执行的动作 |
valid | false | Boolean | 空 | 点击此按钮是否执行表单验证再执行点击事件 |
... | false | 未知 | 空 | 参考Element的按钮组件的属性值 |
- 绑定的事件都有一个返回对象,就是表单的值,格式就是json格式,所有的key取表单子项目中设置的name;
- 模态框形式的范例
// Vue template直接调用组件,绑定参数和方法
<template>
<div id="app">
<!-- 使用按钮控制VicForm的显示 -->
<el-button @click="initFormData"> Test </el-button>
<!-- 调用VicForm模态框 -->
<VicForm :vdata="vdata" @submit="submit" @cancel="cancel">
<span slot="slotTest">
<el-alert
title="成功提示的文案1"
type="success">
</el-alert>
</span>
<span slot="slotTest2">
<el-carousel height="150px">
<el-carousel-item v-for="item in 4" :key="item">
<h3 class="small">{{ item }}</h3>
</el-carousel-item>
</el-carousel>
</span>
</VicForm>
</div>
</template>
<script>
import VicForm from 'vic-form' // 导入组件
export default {
name: 'app',
components: {
VicForm // 注册组件
},
data() {
return {
vdata: {
id: 'vicformId', // 组件的ID
title: 'VicForm', // 模态框的标题文字
mobileWidth: '95%', // 移动端模态框宽度
form: { // 表单
labelWidth: '100px', // 左侧文本宽度,如果不设置,则子项的label和子项会两行显示
data: [ // 各个表单的子项目
{
label: 'ID', // 左侧的文本
formtype: 'hide', // 子项目类型,设置为隐藏则此子项目不会显示出来,但是dom渲染还是会有
name: 'id', // 表单的name属性绑定值
state: null, // 表单状态
value: '', // 绑定的值
placeholder: 'id', // 文本框的placeholder属性
disabled: true // 锁定该组件不能编辑
},
{
label: 'name',
formtype: 'input', // 正常文本输入框
type: 'text', // 如果只是文本录入框,则可以省略此参数
name: 'name',
state: null,
value: '',
placeholder: 'please input your name'
},
{
label: 'Number',
formtype: 'number', // 计数器
name: 'number',
state: null,
value: '',
min: 0,
max: 100,
placeholder: 'please input number'
},
{
label: 'Switch',
formtype: 'switch', // 开关组件
col: 12,
xs: 24,
name: 'switch',
state: null,
value: false,
activeColor: '#13ce66',
inactiveColor: '#ff4949',
activeText: 'active',
inactiveText: 'inactive'
},
{
label: 'Color',
formtype: 'color', // 颜色选择器
col: 12,
xs: 24,
name: 'color',
value: null
},
{
label: 'Slider',
formtype: 'slider',
col: 12,
xs: 24,
name: 'slider', // 滑块
state: null,
value: 60,
min: 0,
max: 100
},
{
label: 'Rate',
formtype: 'rate', // 评分打星
col: 12,
xs: 24,
name: 'rate',
value: null,
colors: ['#99A9BF', '#F7BA2A', '#FF9900']
},
{
label: 'Radio',
formtype: 'radio', // 一个单选
col: 12,
xs: 24,
name: 'radio',
value: false,
text: 'Readed',
colors: ['#99A9BF', '#F7BA2A', '#FF9900']
},
{
label: 'RadioGroup',
formtype: 'radioGroup', // 一组单选
col: 12,
xs: 24,
name: 'radioGroup',
value: [],
datas: [
{ label: '1', text: 'Man'},
{ label: '0', text: 'Woman'}
]
},
{
label: 'Checkbox',
formtype: 'checkbox', // 一个多选
col: 12,
xs: 24,
name: 'checkbox',
value: false,
text: 'Readed',
colors: ['#99A9BF', '#F7BA2A', '#FF9900']
},
{
label: 'CheckboxGroup',
formtype: 'checkboxGroup', // 一组多选
name: 'checkboxGroup',
value: [],
datas: [
{ label: '1', text: 'Orange', bchecked: false },
{ label: '2', text: 'Apple', bchecked: false },
{ label: '3', text: 'Pear', bchecked: false }
]
},
{
label: 'Hr',
formtype: 'hr',
name: 'hr',
position: 'center',
content: 'Divider'
},
{
label: 'Date',
formtype: 'date', // 日期选择
name: 'date',
state: null,
value: '',
placeholder: 'please select date'
},
{
label: 'Time',
formtype: 'time', // 时间选择
name: 'time',
state: null,
value: '',
placeholder: 'please select time'
},
{
label: 'Datetime',
formtype: 'date', // 日期+时间选择
type: 'datetime',
name: 'datetime',
state: null,
value: '',
format: 'yyyy-MM-dd HH:mm:ss',
valueFormat: 'yyyy-MM-dd HH:mm:ss',
placeholder: 'please select datetime'
},
{
label: 'TextArea1',
formtype: 'textarea', // 多行文本框
name: 'textarea1',
state: null,
value: '',
rows: 4,
showWordLimit: true,
clearable: true,
maxlength: 120,
resize: 'none',
placeholder: 'please input something'
},
{
label: 'TextArea2',
formtype: 'input', // 文本输入框
type: 'textarea', // 多行文本框
name: 'textarea2',
state: null,
value: '',
placeholder: 'please input something'
},
{
label: 'Select',
formtype: 'select', // 下拉选择框
name: 'pid',
state: null,
value: '',
placeholder: 'please select your selected',
options: [
{ label: 'Orange', value: '1' },
{ label: 'Apple', value: '2' },
{ label: 'Pear', value: '3' }
]
},
{
label: 'SelectGroup',
formtype: 'selectGroup',
name: 'sid',
state: null,
value: '',
placeholder: 'please select your selected',
options: [
{ label: 'Red', options: [
{ label: 'Big Red', value: 1 },
{ label: 'Middle Red', value: 2 },
{ label: 'Red', value: 3 }
] },
{ label: 'Green', options: [
{ label: 'Big Green', value: 4 },
{ label: 'Middle Green', value: 5 },
{ label: 'Green', value: 6 }
] },
{ label: 'Blue', options: [
{ label: 'Big Blue', value: 7 },
{ label: 'Middle Blue', value: 8 },
{ label: 'Blue', value: 9 }
] }
]
},
{
label: 'Cascader',
formtype: 'cascader', // 级联选择
name: 'cid',
state: null,
value: '',
placeholder: 'please select your city',
mustfill: true,
options: [
{
value: 'china',
label: '中国',
children: [
{
value: 'beijing',
label: '北京',
children: [
{
value: 'dongcheng',
label: '东城区'
},
{
value: 'xicheng',
label: '西城区'
},
{
value: 'chaoyang',
label: '朝阳区'
},
{
value: 'fengtai',
label: '丰台区'
},
{
value: 'haidian',
label: '海淀区'
}
]
},
{
value: 'shanghai',
label: '上海',
children: [
{
value: 'huangpu',
label: '黄浦区'
},
{
value: 'xujiahui',
label: '徐家汇'
},
{
value: 'jingan',
label: '静安区'
}
]
}
]
}
],
props: { checkStrictly: true }
},
{
label: 'File Upload',
formtype: 'file', // 上传组件
name: 'file', // 表单子项目的name字段,上传会以此字段为name,注意此处应该和后台读取参数一致
url: 'api/upload/image', // 上传的服务器接口地址
state: null,
file: [], // 文件地址数组
accept: '.png,.jpg,.jpeg,.bmp', //允许文件类型
btnText: 'Upload', // 按钮文本
// listType: 'picture', // 图片列表形式
listType: 'picture-card', // 图片卡片展示形式
beforeUpload: (file) => { // 文件上传钱的执行函数,可用于判断文件大小或其他
const isLt2M = file.size / 1024 / 1024 < 2
if (!isLt2M) {
this.$message({
message: 'file size must less 2MB!',
type: 'warning'
})
}
return isLt2M
},
onSuccess: (response, file, fileList, item) => { this.uploadedImage(response, file, fileList, item) }, // 文件上传成功之后的执行函数,如果设置了此函数则由调用VicForm的组件自己编写接收上传之后返回的文件地址,如果没有设置此函数,则在提交表单的时候由提交动作进行处理
multiple: false, // 是否允许多文件上传
limit: 1 // 上传文件数限制
},
{
label: 'UE Editor',
formtype: 'ue',
name: 'ue',
value: '',
config: {
// 如果需要上传功能,找后端小伙伴要服务器接口地址
// serverUrl: this.$config.baseUrl + 'ueditor/ueditorConfig',
// serverUrl: 'http://localhost:8090/ueditor/ueditorConfig',
// 你的UEditor资源存放的路径,相对于打包后的index.html
UEDITOR_HOME_URL: '/ueditor/',
// 编辑器不自动被内容撑高
autoHeightEnabled: false,
// 工具栏是否可以浮动
autoFloatEnabled: false,
// 初始容器高度
initialFrameHeight: 340,
// 初始容器宽度
initialFrameWidth: '100%',
// 关闭自动保存
enableAutoSave: true,
// 最大字数限制
maximumWords: 40000
}
},
{
label: 'slot', // 左侧的文本
formtype: 'slot', // 子项目类型
name: 'slotTest', // 表单的name属性绑定值
state: null, // 表单状态
value: '', // 绑定的值
placeholder: 'id', // 文本框的placeholder属性
disabled: true // 锁定该组件不能编辑
},
{
formtype: 'html',
content: '<div style="color: green;">any code.</div>'
},
{
label: 'Image',
formtype: 'image',
name: 'image',
state: null,
value: 'https://gw.alicdn.com/imgextra/i3/O1CN01uRz3de23mzWofmPYX_!!6000000007299-2-tps-143-59.png'
},
{
label: 'Images',
formtype: 'images',
name: 'images',
state: null,
value: [
' https://gw.alicdn.com/imgextra/i3/O1CN01uRz3de23mzWofmPYX_!!6000000007299-2-tps-143-59.png',
' https://gw.alicdn.com/imgextra/i3/O1CN01uRz3de23mzWofmPYX_!!6000000007299-2-tps-143-59.png',
' https://gw.alicdn.com/imgextra/i3/O1CN01uRz3de23mzWofmPYX_!!6000000007299-2-tps-143-59.png'
]
},
{
label: 'slotTest2',
formtype: 'slot',
col: 24,
xs: 24,
name: 'slotTest2',
state: null,
value: '',
clearable: true,
placeholder: 'please input your name'
}
],
rules: { // 表单验证
name: [ // 验证的key为form.data中的子项的name字段
{
required: true, // 必须录入
message: '必须录入文本', // 表单验证失败之后的提示信息
trigger: 'change' // 表单验证的方式
},
{
validator: (rule, value, callback) => { // 验证器
if (value.trim().length > 0) {
callback()
} else {
callback(new Error('必须录入ID'))
}
},
trigger: 'change' // 表单验证的方式
}
],
number: [ // 验证的key为form.data中的子项的name字段
{ required: true, message: '必须录入数字', trigger: 'change' },
{ validator: (rule, value, callback) => { if (parseInt(value) > 0) { callback() } else { callback(new Error('必须录入数字')) } }, trigger: 'change' }
]
}
},
btn: [ // 底部按钮组
{
text: 'Submit', // 按钮1的显示文本
type: 'success', // 按钮的样式类型
icon: '', // 按钮文本左侧的图标
class: 'btn-success', // 按钮的 class 样式
click: 'submit', // 按钮点击后执行的动作,此动作必须在 Vue template 调用组件的时候绑定上动作方法
valid: true // 如果需要表单前端验证,则使用 valid 参数来配置,验证通过会执行 click 参数指定的 submit 方法,不通过则会按 form.rules 中的规则提示信息进行提示,你也可以不配置rules验证自己在submit方法内手写验证(你闲得发慌的时候可以考虑下)
},
{
text: 'cancel', // 按钮2的显示文本
type: '', // ...
icon: '', // ...
class: 'btn-secondary', // ...
click: 'cancel' // ...
}
],
content: '<div style="color:red;">content 1233211234567</div>', // 表单底部至模态框按钮组中间区域显示的html,可不配置
show: false // 是否显示模态框
},
fileList: { // 用于接收上传之后返回的文件地址
file: []
}
}
},
methods: {
initFormData: function() {
// clear the form data
for (let i = 0; i < this.vdata.form.data.length; i++) {
this.$set(this.vdata.form.data[i], 'value', '')
}
this.$set(this.vdata, 'show', !this.vdata.show)
},
uploadedImage: function(response, file, fileList, item) {
console.log(`uploadedImage => `)
console.log(response) // 服务器返回的上传结果
console.log(file) // 上传的文件信息
console.log(fileList) // 上传的文件列表
console.log(item) // 表单中该子项目的参数
// 此处设置的是只上传1个文件,所以需要将之前的文件结果进行清空
this.fileList.file.splice(0, this.fileList.file.length)
// 添加上传结果地址到记录中进行保存,最后表单提交结果的时候需要调用的
this.fileList.file.push(response.data)
},
submit: function(formValues) {
this.$message.success('Submit')
console.log(formValues) // 表单的值
// 将表单的值赋值到vdata对象中,方便下一次打开的时候再次编辑
for(let i = 0; i < this.vdata.form.data.length; i++) {
this.$set(this.vdata.form.data[i], 'value', formValues[this.vdata.form.data[i].name])
}
// 打印表单值和上传文件的值,
let datas = Object.assign({}, formValues, this.fileList)
console.log(datas)
// 此处可按照自由意愿将表单最终结果进行上传处理
this.cancel()
},
cancel: function() {
setTimeout(() => {
this.$message.warning('Hide Dialog')
}, 500)
this.$set(this.vdata, 'show', !this.vdata.show)
}
}
}
</script>
-
Div形式的范例
<template> <div id="app"> <!-- 使用按钮控制VicForm的显示 --> <el-button @click="initFormData"> Test </el-button> <!-- 调用VicForm --> <VicForm :vdata="vdata" @submit="submit" @cancel="cancel" /> </div> </template> <script> import VicForm from 'vic-form' // 导入组件 export default { name: 'app', components: { VicForm // 注册组件 }, data() { return { vdata: { id: 'vicformId', type: 'div', title: 'VicForm', titleHtml: '<div style="color: blue; font-weight: bold;font-size: 32px; padding-bottom: 10px;">VicForm-InputForm</div>', width: '60%', style: { 'padding-top': '40px', 'padding-bottom': '40px' }, form: { labelWidth: '130px', data: [ { label: 'ID', formtype: 'hide', name: 'id', value: '', placeholder: 'id', disabled: true }, { label: 'text input', formtype: 'input', name: 'inputText', value: '', placeholder: 'please input something' }, { label: 'Number input', formtype: 'input', type: 'number', // 指定input类型 name: 'inputNumber', value: '', min: 1, max: 100, placeholder: 'please input Number' }, { label: 'Password input', formtype: 'input', type: 'password', // 指定input类型 name: 'inputPassword', value: '', showPassword: true, placeholder: 'please input Password' }, { label: 'Hr', formtype: 'hr', name: 'hr', position: 'left', content: 'hr' }, { label: 'URL input', formtype: 'input', type: 'url', // 指定input类型 name: 'inputUrl', value: '', placeholder: 'please input URL' }, { label: 'Tel input', formtype: 'input', type: 'tel', // 指定input类型 name: 'inputTel', value: '', placeholder: 'please input Tel' }, { label: 'Email input', formtype: 'input', type: 'email', // 指定input类型 name: 'inputEmail', value: '', placeholder: 'please input Email' }, { formtype: 'html', content: '<div style="color: green;">any code.</div>' } ], rules: { inputText: [ { required: true, message: '必须录入文本', trigger: 'change' }, { validator: (rule, value, callback) => { if (value.trim().length > 0) { callback() } else { callback(new Error('必须录入点什么')) } }, trigger: 'change' } ], inputNumber: [ { required: true, message: '必须录入数字', trigger: 'change' }, { validator: (rule, value, callback) => { if (parseInt(value) > 0) { callback() } else { callback(new Error('必须录入数字')) } }, trigger: 'change' } ], } }, btn: [ { text: 'Submit', type: 'success', icon: '', class: 'btn-success', click: 'submit', valid: true }, { text: 'cancel', type: '', icon: '', class: 'btn-secondary', click: 'cancel' } ], show: false } } }, methods: { initFormData: function() { // clear the form data for (let i = 0; i < this.vdata.form.data.length; i++) { this.$set(this.vdata.form.data[i], 'value', '') } this.$set(this.vdata, 'show', !this.vdata.show) }, submit: function(formValues) { this.$message.success('Submit') console.log(formValues) // 表单的值 // 将表单的值赋值到vdata对象中,方便下一次打开的时候再次编辑 for(let i = 0; i < this.vdata.form.data.length; i++) { this.$set(this.vdata.form.data[i], 'value', formValues[this.vdata.form.data[i].name]) } this.cancel() }, cancel: function() { setTimeout(() => { this.$message.warning('Hide Dialog') }, 500) this.$set(this.vdata, 'show', !this.vdata.show) } } } </script>
- 新增表单按钮的点击事件中传递表单的值到外部,再由外部函数进行处理;
- 增加slot插槽;
- 修改文件上传的文件列表的判断用limit,不使用多选,使其可以多次单传文件;
- 新增UE编辑器;
- 增加noLabel参数,可以关闭表单行的标题显示,增加labelWidth参数,单独设置本表单行的label宽度;
- 增加vic-form的hr类型和html类型