背景
项目遇到大量的各类表单,以及搜索表格的页面。设计师出的页面以及交互几乎都差不多,也算是遵循设计的统一性吧。当我们开发的时候,总感觉每天在重复手动搬砖,那我们是不是可以推个小车来搬砖呢?本着想偷偷懒的想法,就有了以下发生的事情...
you-want
至于为啥叫you-want,其灵感来源于《中国好声音》的 “I Want You”。另外的意思就是想表明:你想要啥,都可以来告诉我,我尽量满足你!(有点夸张,不过也算是一个努力💪的方向...)
「表单/表格」开箱即用的解决方案。该组件库是在 Vue2 + Ant Design Vue 的基础进行二次开发的,所以项目必须是vue2+ antd架构(其他版本敬请期待...)。至于为什么非要造这个轮子?我也看了大量市场上提供的相似解决方案,感觉场景以及使用都比较复杂,有一定的学习成本,我只想让事情简单化,不想让使用者有学习负担,怎么简单怎么来,也就是说只要大家会Vue2 + Ant Design Vue就可以了。 主要收录了常用的几个组件。如果大家有其它组件需求,都可以给我提,我努力完成...
快速上手
首先,安装组件库
npm install you-want
#或
yarn add you-want
#或
pnpm install you-want
接着,在项目入口文件 main.js 注册组件
import YouWant from 'you-want'
Vue.use(YouWant.YFormList)
Vue.use(YouWant.YSearchTable)
Vue.use(YouWant.YSearchForm)
最后,就可以在页面或组件里边直接使用
<template>
<div class="">
<!-- 带检索功能的表格 -->
<y-search-table
:FormProps="FormProps"
:FormListColumns="FormListColumns"
:TableColumns="columns"
:TableData="data"
:TableProps="TableProps"
></y-search-table>
<!-- 表单列表组件 -->
<y-form-list
ref="formListRef"
:FormListColumns="FormListColumns"
>
</y-form-list>
</div>
</template>
使用说明
-
YFormList --- 让表单简单化,配置一下就可以
-
YSearchTable --- 让表格固定化,做自己业务就好
-
YSearchForm --- 让检索适配化,大小屏通吃
下边可看到具体文档:
FormList 组件使用文档说明
让表单简易化,配置一下就可以!不用再堆积大量的HTML标签了,代码层次逻辑清晰明了!JSON配置简单易上手!
Attributes
FormListColumns
FormListColumns 参数为对象object,必传。
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
key | key值,对应接口字段 | string | — | — |
tag | 标签,首字母大写 | string | 见tag | — |
options | form组件配置 | object | — | {} |
formItemProps | formItem 配置项 | object | {label: "名称"} | {} |
nodeProps | 内置标签节点对应的属性 | object | — | {} |
hidden | 配置节点的显示/隐藏(可通过配置表达式智能联动) | boolean/表达式 | true/false/"{{formData.key === value}}" | false |
afterProps | 节点后边可能出现单位、按钮、或说明... | object | — | {} |
colSpan | 栅格布局占位 | number | 1~24 | 24 |
otherNode | 其他特殊节点 | object[array] | — | — |
tag
tag 参数为字符串string,标签介绍,首字母大写。现在支持一下标签:
tag | 说明 | 配置文档 |
---|---|---|
Input | Input输入框 | 文档 |
Badge | Badge徽标数 | 文档 |
RadioGroup | RadioGroup单选框 | 文档 |
DatePicker | DatePicker日期选择框 | 文档 |
Textarea | Textarea输入框 | 文档 |
Select | Select选择器 | 文档 |
InputNumber | InputNumber数字输入框 | 文档 |
Switch | Switch开关 | 文档 |
Slider | Slider滑动输入条 | 文档 |
Rate | Rate评分组件 | 文档 |
Upload | Upload上传 | 文档 |
RangePicker | RangePicker日期区间 | 文档 |
TimePicker | TimePicker时间选择框 | 文档 |
AutoComplete | AutoComplete自动完成 | 文档 |
Cascader | Cascader级联选择 | 文档 |
Span | Span展示 | 值为:options.initialValue 或 DetailData[key] |
InputNumberSelect | InputNumberSelect数字带单位 | 参考InputNumber 和 Select 配置 |
RangeTimePicker | RangeTimePicker时间区间 | 见RangeTimePicker |
InputSelect | InputSelect文本带选择框 | 参考Input 和 Select 配置 |
Slot | 插槽渲染,可自定义复杂的表单 | 额外单独配置 |
RangeTimePicker
其它配置不变,和其它节点一样,仅 nodeProps 的配置如下:
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
format | 展示的时间格式 | string | — | "HH:mm:ss" |
disabled | 禁用全部操作 | boolean | — | false |
hourStep | 小时选项间隔 | number | — | 1 |
minuteStep | 分钟选项间隔 | number | — | 1 |
secondStep | 秒选项间隔 | number | — | 1 |
disabledStartTime | 禁用的开始时间 | string | 例:"09:10" | — |
disabledEndTime | 禁用的结束时间 | string | 例:"21:30" | — |
FormProps
FormProps 参数为对象object,非必传,Form 表单属性,配置参考
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
labelCol | label 标签布局 | object | — | {span: 6} |
wrapperCol | 节点标签布局 | object | — | {span: 18} |
... | ... | ... | ... | ... |
DetailData
DetailData 参数为对象object,非必传,只有在需要回显数据的时候(详情/编辑)传递该参数。
使用案例
文字表述感觉不明朗,不直观,直接上案例代码吧,简单粗暴明朗,朗朗上手!
:::整体代码配置示例。
<template>
<y-form-list
ref="formListRef"
:FormProps="FormProps"
:FormListColumns="FormListColumns"
>
</y-form-list>
<a-button type="primary" @click="getData">获取表单数据</a-button>
</template>
<script>
// 可忽略不用配置,内置默认值
const FormProps = {
labelCol: { span: 5 },
wrapperCol: { span: 13 },
};
// 生成表单配置,必传
const FormListColumns = {
key0: {
tag: "Input",
formItemProps: { label: "Input" },
options: {
rules: [{ required: true, message: "必选!" }],
},
nodeProps: {
disabled: false,
},
afterProps: {
tag: "Button",
label: "选择",
click: () => { },
},
hidden: false,
},
key1: {
tag: 'Badge',
formItemProps: {
label: "Badge",
},
nodeProps: {
text: '已解决'
}
},
key2: {
tag: "Select",
formItemProps: {
label: "Select",
},
options: {
initialValue: '',
},
nodeProps: {
options: [
{ label: "全部", value: '' },
{ label: "是", value: 1 },
{ label: "否", value: 2 },
],
},
},
key3: {
type: "RadioGroup",
formItemProps: { label: "RadioGroup" },
options: {
initialValue: 1,
},
nodeProps: {
options: [
{ label: "时间区间", value: 1 },
{ label: "间隔区间", value: 2 },
],
},
},
key4: {
type: "DatePicker",
formItemProps: { label: "DatePicker" },
options: {
rules: [{ required: true, message: "必选!" }],
},
nodeProps: {
},
},
key5: {
tag: "Textarea",
formItemProps: { label: "Textarea" },
options: {
rules: [{ required: true, message: "必填!" }],
},
nodeProps: {},
},
key6: {
tag: "InputNumber",
formItemProps: { label: "InputNumber" },
options: {
rules: [
{ required: true, message: "必选!" },
{ pattern: /^[1-9]\d*$/, message: "请输入正整数!" },
],
},
nodeProps: {
placeholder: "请输入正整数",
min: 1
},
},
key7: {
tag: "RangePicker",
formItemProps: { label: "RangePicker" },
options: {
rules: [{ required: true, message: "必选!" }],
},
nodeProps: {
format: "YYYY-MM-DD HH:mm:ss",
disabledDate(current) {
return current && current < moment().add(-1, "days");
},
},
},
key8: {
type: "TimePicker",
formItemProps: { label: "TimePicker" },
options: {
rules: [
{ required: true, message: "必选!" },
],
},
nodeProps: {
},
},
key9: {
tag: "Span",
formItemProps: {
label: "Span",
},
options: {
initialValue: '我是Span',
},
nodeProps: {
},
},
key10: {
type: "InputNumberSelect",
formItemProps: { label: "InputNumberSelect" },
options: {
initialValue: { number: 0, unit: '分' },
rules: [
{ required: true, message: "必填!" },
],
},
nodeProps: {
options: [
{ label: "秒", value: "s" },
{ label: "分", value: "m" },
],
},
},
key11: {
tag: "RangeTimePicker",
formItemProps: {
label: "RangeTimePicker",
},
options: {
initialValue: [moment("10:20", "HH:mm:ss"), moment("20:30", "HH:mm:ss")],
rules: [{ required: true, message: "必选!" }],
},
nodeProps: {
format: "HH:mm:ss",
disabled: false,
disabledStartTime: '09:10',
disabledEndTime: '21:30',
hourStep: 1,
minuteStep: 1,
secondStep: 1,
},
},
}
export default {
name: "Demo",
data() {
return {
FormProps,
FormListColumns
};
},
computed: {
},
methods: {
getData() {
this.$refs.formListRef?.getFromValue((values) => {
// values 是表单的值
console.log(values);
});
},
},
};
</script>
:::
效果图
SearchTable 组件使用文档说明
该组件的设计只为UI组件封装,统一方法处理,统一页面适配,不造成多余学习成本,主要还是学习UI组件库的使用。
特点
-
SearchForm 头部的筛选框部分支持屏幕适配,根据窗口大小一排展示不同数量
-
Table 底部的 table 表格固定UI的设计样式,支持分页器,各种常见模式都支持配置
Attributes
FormListColumns
FormListColumns 参数为对象 object,必传。
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
key | key值,对应接口字段 | string | — | — |
tag | 标签,首字母大写 | string | 见tag | — |
options | form组件配置 | object | — | {} |
formItemProps | formItem 配置项 | object | {label: "名称"} | {} |
nodeProps | 内置标签节点对应的属性 | object | — | {} |
tag
tag 参数为字符串 string,标签介绍,首字母大写。现在支持一下标签:
tag | 说明 | 配置文档 |
---|---|---|
Input | Input输入框 | 文档 |
RadioGroup | RadioGroup单选框 | 文档 |
DatePicker | DatePicker日期选择框 | 文档 |
Textarea | Textarea输入框 | 文档 |
Select | Select选择器 | 文档 |
InputNumber | InputNumber数字输入框 | 文档 |
Switch | Switch开关 | 文档 |
Slider | Slider滑动输入条 | 文档 |
Rate | Rate评分组件 | 文档 |
Upload | Upload上传 | 文档 |
RangePicker | RangePicker日期区间 | 文档 |
TimePicker | TimePicker时间选择框 | 文档 |
AutoComplete | AutoComplete自动完成 | 文档 |
InputNumberSelect | InputNumberSelect数字带单位 | 参考InputNumber 和 Select 配置 |
RangeTimePicker | RangeTimePicker时间区间 | 见RangeTimePicker |
RangeTimePicker
其它配置不变,和其它节点一样,仅 nodeProps 的配置如下:
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
format | 展示的时间格式 | string | — | "HH:mm:ss" |
disabled | 禁用全部操作 | boolean | — | false |
hourStep | 小时选项间隔 | number | — | 1 |
minuteStep | 分钟选项间隔 | number | — | 1 |
secondStep | 秒选项间隔 | number | — | 1 |
disabledStartTime | 禁用的开始时间 | string | 例:"09:10" | — |
disabledEndTime | 禁用的结束时间 | string | 例:"21:30" | — |
FormProps
FormProps 参数为对象 object,非必传,Form 表单属性,配置参考
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
labelCol | label 标签布局 | object | — | {span: 6} |
wrapperCol | 节点标签布局 | object | — | {span: 18} |
... | ... | ... | ... | ... |
TableColumns
该参数为数组 object[array],是配置表格的API。文档见Table#Column
TableData
该参数为数组 array,下边表格的数据data,一般是接口请求回来的数据。
TableProps
该参数为对象 object,是关于表格属性的配置。文档见Table
使用案例
文字表述感觉不明朗,不直观,直接上案例代码吧,简单粗暴明朗,朗朗上手!
:::整体代码配置示例。
<template>
<div>
<y-search-table
ref="searchTableRef"
:FormProps="FormProps"
:FormListColumns="FormListColumns"
:TableColumns="columns"
:TableData="tableData"
:TableProps="TableProps"
@onValuesChange="onValuesChange"
@change="searchTableChange"
>
<template slot="extra">
<a-button type="primary" @click="createClick">新建</a-button>
</template>
<span slot="source" slot-scope="{ record }">
{{ record.tbSource === "1" ? "hive" : "其他" }}
</span>
<span slot="tbSource" slot-scope="{ record }">
{{ record.tbSource === "1" ? "hive" : "其他" }}
</span>
<span slot="monitorSwitch" slot-scope="{ record }">
{{ record.monitorSwitch === "1" ? "是" : "否" }}
</span>
<span slot="tbDegree" slot-scope="{ record }">
{{ `P${record.tbDegree}` }}
</span>
<div slot="action" slot-scope="{ record }">
<a
v-if="record.monitorSwitch === '1'"
style="margin-right: 8px"
@click="tableItemsClick(record)"
>
表的监控项
</a>
<a v-else style="margin-right: 8px" @click="createClick(record)">
新建监控
</a>
</div>
</y-search-table>
</div>
</template>
<script>
// 这个是默认值,可以不传,如果需要定制,可选传
const FormPropsIndex = {
labelCol: { span: 6 },
wrapperCol: { span: 18 },
};
// 不传就是空
const FormListColumnsIndex = {
monitor: {
tag: "Select",
formItemProps: {
label: "是否监控",
},
options: {
initialValue: '',
},
nodeProps: {
options: [
{ label: "全部", value: '' },
{ label: "是", value: 1 },
{ label: "否", value: 2 },
],
},
},
tableType: {
tag: "Select",
formItemProps: { label: "表类型" },
options: {
initialValue: 1,
},
nodeProps: {
options: [
{ label: "离线表", value: 1 },
{ label: "实时表", value: 2 },
],
},
},
tableImportance: {
tag: "Select",
formItemProps: { label: "表重要程度" },
options: {
initialValue: "",
},
nodeProps: {
options: [
{ label: "全部", value: "" },
{ label: "P0", value: 0 },
{ label: "P1", value: 1 },
{ label: "P2", value: 2 },
{ label: "P3", value: 3 },
],
},
},
source: {
tag: "Select",
formItemProps: { label: "数据源" },
options: {
initialValue: "hive",
},
nodeProps: {
options: [
{ label: "全部", value: "" },
{ label: "hive", value: "hive" },
],
},
},
database: {
tag: "Select",
formItemProps: { label: "数据库" },
options: {},
nodeProps: {
options: [],
},
},
tableName: {
tag: "Select",
formItemProps: { label: "数据表" },
options: {},
nodeProps: {
options: [],
placeholder: "可模糊搜索",
showSearch: true,
search: () => {}
},
},
userName: {
tag: "Select",
formItemProps: { label: "负责人" },
options: {
},
nodeProps: {
options: [],
placeholder: "请先选择数据库",
},
},
};
const columnsIndex = [
{
title: "数据源",
dataIndex: "source",
width: 100,
scopedSlots: { customRender: "source" },
},
{ title: "库", dataIndex: "db" },
{ title: "数据表名", dataIndex: "tb" },
{ title: "数据表备注", dataIndex: "tbComment" },
{
title: "是否监控",
dataIndex: "monitorSwitch",
width: 100,
scopedSlots: { customRender: "monitorSwitch" },
},
{
title: "表类型",
dataIndex: "tbSource",
width: 100,
scopedSlots: { customRender: "tbSource" },
},
{
title: "表的重要程度",
dataIndex: "tbDegree",
width: 150,
scopedSlots: { customRender: "tbDegree" },
},
{ title: "已配置规则数", dataIndex: "ruleCnt", width: 150 },
{ title: "负责人", dataIndex: "tbOwner", width: 150 },
{
title: "操作",
dataIndex: "action",
fixed: "right",
width: 150,
scopedSlots: { customRender: "action" },
},
];
export default {
name: "PageName",
data(){
return {
FormProps: FormPropsIndex, // 该参数可以不传,有默认值
FormListColumns: FormListColumnsIndex,
columns: columnsIndex,
tableData: [],
TableProps: {
title: "",
loading: false,
rowKey: (record) => `${record.db}${record.tb}`,
pagination: {
current: 1,
pageSize: 10,
total: 0
},
},
feildValue: {},
formData: {}
}
},
mounted() {
},
methods: {
// 监听刷选项发生改变事件
onValuesChange(props, values) {
this.formData = Object.assign(this.formData, values); // 缓存数据,做对比
// Todo
},
// 表格事件,也是查询的回调事件,values 查询参数,pagination 页码变化参数
searchTableChange(values = {}, pagination) {
this.TableProps.pagination = Object.assign(this.TableProps.pagination, pagination)
this.getFromData(Object.assign(this.feildValue, values));
},
// 请求表格列表数据
getFromData(values){
console.log(values)
this.feildValue = values // 保存查询参数,切换页码时需要
// Todo
},
}
}
</script>
:::