基于uni-app的动态表单

news/2024/10/9 1:16:53/

一、应用场景和意义

可以通过配置字段和校验规则,快速完成页面开发、提升开发效率

二、应用前提

形成ui/业务规范,最好是应用在问卷调查之类的业务

三、动态表单的功能

字段报错、快速滚动定位报错信息、支持字段值和字段规则拆分,便于实现复杂的表单交互

四、动态表单支持的组件类型

1、input-text 文本输入框类型

<template v-if="item.type === 'input-text'">

<view class="formItemBox">

<view class="formItem">

<view class="left">

<view class="num" v-if="num">{{ index + 1 }}.</view>

<view v-if="item.redTip" class="colorRed">{{ item.redTip ? '*' : ''

}}

</view>

<view class="name">{{ item.label }}</view>

</view>

<view class="right">

<u-form-item>

<view v-if="item.readonly || disabledFields.includes(item.id)"

@click="showNoEdit" class="readonlytext">{{ form[item.id] }}

</view>

<u--input v-else style="width: 100%;" v-model="form[item.id]"

input-align="right" :placeholder="item.placeholder"

:placeholderStyle="placeholderStyle"

border="none"></u--input>

</u-form-item>

</view>

</view>

<u-form-item labelWidth="0" :prop="item.id" class="formItemNoBody">

</u-form-item>

<view class="line" v-show="formItem.list.length - 1 > index"></view>

</view>

</template>

支持正常的输入校验 和 不可编辑的样式和提示

2、single-select 单选

<template v-if="item.type === 'single-select'">

<view class="formItemBox">

<view class="formItem">

<view class="left">

<view class="num" v-if="num">{{ index + 1 }}.</view>

<view v-if="item.redTip" class="colorRed">{{ item.redTip ? '*' : ''

}}

</view>

<view class="name">{{ item.label }}</view>

</view>

<view class="right optItemBox">

<view class="optItem" @click.stop="showNoEditOrSelect(item)"></view>

<u-form-item>

<view v-if="item.readonly || disabledFields.includes(item.id)"

class="readonlytext">{{ form[item.id] }}</view>

<view v-else class="select_right">

<view v-if="!form[item.id]" class="placeholderStyle">

{{ item.placeholder }}</view>

<view v-else class="select_right_text">

{{ item.listMap[form[item.id]] &&

item.listMap[form[item.id]].name || '未匹配到' }}

</view>

</view>

<view v-show="false">

<u--input style="width: 100%;" v-model="form[item.id]"

input-align="right" :placeholder="item.placeholder"

:placeholderStyle="placeholderStyle"

border="none"></u--input>

</view>

<view class="arrow_right_icon">

<img src="./icon/arrow.png" alt="">

</view>

</u-form-item>

</view>

</view>

<u-form-item labelWidth="0" :prop="item.id" class="formItemNoBody">

</u-form-item>

<view class="line"></view>

</view>

<!-- <u-action-sheet cancelText="取消" :safeAreaInsetBottom="true" :actions="item.list"

:title="item.selectTitle" safeAreaInsetBottom :show="item.showSelect"

@select="selectConfirm($event, item)" @close="selectClose(item)"></u-action-sheet> --> <u-picker :show="item.showSelect" ref="uPicker" :defaultIndex="defaultIndex" :confirmColor="env.themeColor" :columns="[item.list]" @cancel="selectClose(item)" @close="selectClose(item)" keyName="name" @confirm="selectConfirm($event, item)"></u-picker>

</template>

支持正常的单选和不可编辑以及未匹配到的提示

3、dependent-computing 依赖别的字段计算

<template v-if="item.type === 'dependent-computing'">

<view class="formItemBox">

<view class="formItem">

<view class="left">

<view class="num" v-if="num">{{ index + 1 }}.</view>

<view v-if="item.redTip" class="colorRed">{{ item.redTip ? '*' : ''

}}

</view>

<view class="name">{{ item.label }}</view>

</view>

<view class="right optItemBox">

<view class="optItem" @click.stop="showNoEditOrSelect(item)"></view>

<u-form-item>

<view v-if="item.readonly || disabledFields.includes(item.id)"

class="readonlytext">{{ form[item.id] }}</view>

<view v-else class="select_right">

<u--input style="width: 100%;" v-model="form[item.id]"

input-align="right" :placeholder="item.placeholder"

:placeholderStyle="placeholderStyle"

border="none"></u--input>

</view>

</u-form-item>

</view>

</view>

<u-form-item labelWidth="0" :prop="item.id" class="formItemNoBody">

</u-form-item>

<view class="line"></view>

</view>

</template>

依赖计算不可编辑、做显示

4、switch 开关

<template v-if="item.type === 'switch'">

<view class="formItemBox">

<view class="formItem formSwitchItem">

<view class="left">

<view class="num" v-if="num">{{ index + 1 }}.</view>

<view v-if="item.redTip" class="colorRed">{{ item.redTip ? '*' : ''

}}

</view>

<view class="name">{{ item.label }}</view>

</view>

<view class="right optItemBox">

<view v-if="item.readonly || disabledFields.includes(item.id)"

class="optItem" @click.stop="showNoEditOrSelect(item)"></view>

<u-form-item>

<view class="switchBox">

<u-switch v-model="form[item.id]"

inactiveColor="rgba(229, 230, 235, 1)"

:activeColor="env.themeColor"

@change="changeSwitch($event, item)"></u-switch>

</view>

</u-form-item>

</view>

</view>

<u-form-item labelWidth="0" :prop="item.id" class="formItemNoBody">

</u-form-item>

<view class="line"></view>

</view>

</template>

5、单选日期 single-calendar

<template v-if="item.type === 'single-calendar'">

<view class="formItemBox">

<view class="formItem">

<view class="left">

<view class="num" v-if="num">{{ index + 1 }}.</view>

<view v-if="item.redTip" class="colorRed">{{ item.redTip ? '*' : ''

}}

</view>

<view class="name">{{ item.label }}</view>

</view>

<view class="right optItemBox">

<view class="optItem" @click.stop="showNoEditOrCalendar(item)">

</view>

<u-form-item>

<view v-if="item.readonly || disabledFields.includes(item.id)"

class="readonlytext">{{ form[item.id] }}</view>

<view v-else class="select_right">

<view v-if="!form[item.id]" class="placeholderStyle">

{{ item.placeholder }}</view>

<view v-else class="select_right_text">

{{ form[item.id] }}</view>

</view>

<view v-show="false">

<u--input style="width: 100%;" v-model="form[item.id]"

input-align="right" :placeholder="item.placeholder"

:placeholderStyle="placeholderStyle"

border="none"></u--input>

</view>

<view class="arrow_right_icon">

<img src="./icon/arrow.png" alt="">

</view>

</u-form-item>

</view>

</view>

<u-form-item labelWidth="0" :prop="item.id" class="formItemNoBody">

</u-form-item>

<view class="line"></view>

</view>

<!-- <u-calendar :show="item.showSingleCalendar" :color="env.themeColor"

:defaultDate="defaultDateSingle" mode="single"

></u-calendar> -->

<u-datetime-picker :show="item.showSingleCalendar" v-model="defaultDateSingle"

mode="date" @confirm="singleCalendarConfirm($event, item)"

@cancel="closeCalendar(item)"

@close="closeCalendar(item)"></u-datetime-picker>

</template>

支持正常的单选和不可编辑

6、upload-images 上传图片

<template v-if="item.type === 'upload-images'">

<view class="formItemBox">

<view class="formItem">

<view class="left">

<view class="num" v-if="num">{{ index + 1 }}.</view>

<view v-if="item.redTip" class="colorRed">{{ item.redTip ? '*' : ''

}}

</view>

<view class="name">{{ item.label }}</view>

</view>

</view>

<view class='img-wrap'>

<view v-show="false">

<u--input style="width: 100%;" v-model="form[${item.id}filePath]"

input-align="right" :placeholder="item.placeholder"

:placeholderStyle="placeholderStyle" border="none"></u--input>

</view>

<Upload :filesData="form[item.id] || []"

@onFilesChange="(items) => filesDataChange(items, ${item.id})"

:disableEdit="item.readonly || disabledFields.includes(item.id)"

:max='item.imgLen' uploadType='photo' />

</view>

<u-form-item labelWidth="0" :prop="${item.id}filePath"

class="formItemNoBody">

</u-form-item>

<view class="line"></view>

</view>

</template>

这个图片上传耦合了接口上传 和禁止编辑

五、入参

formData 表单校验规则

valueForm 表单字段值

六、使用示例

form: {

ownerName: '',

idNumbe: '',

phoneNumber: "",

proAddres: "",

projectDetailedAddress: "",

},

allFormData: [

{

title: '客户信息',

showTitle: true,

list: [{

id: "ownerName",

placeholder: "请输入",

label: "姓名",

type: "input-text",

redTip: false,

readonly: true,

rules: [

{

type: 'string',

required: true,

message: '请输入',

trigger: ['change', 'blur']

}

]

},

{

id: "idNumbe",

placeholder: "请输入",

label: "证件号码",

type: "input-text",

redTip: false,

readonly: true,

rules: [

{

type: 'string',

required: true,

message: '请输入',

trigger: ['change', 'blur']

}

]

},

{

id: "phoneNumber",

placeholder: "请输入",

label: "联系电话",

type: "input-text",

redTip: false,

readonly: true,

rules: [

{

type: 'string',

required: true,

message: '请输入',

trigger: ['change', 'blur']

}

]

},

]

},

{

title: '项目地址',

showTitle: true,

list: [{

id: "proAddres",

placeholder: "请输入",

label: "项目地址",

type: "input-text",

redTip: false,

readonly: true,

rules: [

{

type: 'string',

required: true,

message: '请输入',

trigger: ['change', 'blur']

}

]

}, {

id: "projectDetailedAddress",

placeholder: "请输入",

label: "详细地址",

type: "input-text",

redTip: false,

readonly: true,

rules: [

{

type: 'string',

required: true,

message: '请输入',

trigger: ['change', 'blur']

}

]

}]

},

{

title: '电站基本情况',

showTitle: true,

list: [{

id: "zuKuai",

placeholder: "请输入",

label: "板块数",

type: "input-text",

redTip: false,

readonly: false,

rules: [

{

type: 'string',

required: true,

message: '请输入',

trigger: ['change', 'blur']

}, {

validator: (rule, value, callback) => {

const pattern = /^[1-9]\d{0,3}$|^[1-9]\d{0,3}$|^\d{1,4}$/

if (!pattern.test(value)) {

callback(new Error('请输入大于0小于10000的正整数'));

} else {

callback();

}

},

trigger: ['change', 'blur'],

}

]

},

{

id: "zuPower",

placeholder: "请选择",

label: "功率",

type: "single-select",

redTip: false,

readonly: false,

showSelect: false,

selectTitle: "请选择",

list: [],

listMap: {},

rules: [

{

type: 'string',

required: true,

message: '请选择',

trigger: ['change', 'blur']

}

]

},

{

id: "totalZuPower",

placeholder: "计算带出,不得修改",

label: "系统容量",

type: "dependent-computing",

redTip: false,

readonly: false,

rules: [{

type: 'string',

required: true,

message: '请完善版块数和功率',

trigger: ['change', 'blur']

}, {

validator: (rule, value, callback) => {

if (Number(value) > 120000) {

callback(new Error('系统容量不能大于120000'));

} else {

callback();

}

},

trigger: ['change', 'blur'],

}]

},]

},

{

title: '付款信息',

showTitle: true,

list: [

{

id: "priceType",

placeholder: "请选择",

label: "价格类型",

type: "single-select",

redTip: false,

readonly: false,

showSelect: false,

selectTitle: "请选择",

list: [],

listMap: {},

rules: [

{

type: 'string',

required: true,

message: '请选择',

trigger: ['change', 'blur']

}

],

beferConfirmFun: (confirmFun) => {

uni.showModal({

title: '提示',

content: '修改价格类型后需重新填写付款信息',

success: async (res) => {

if (res.confirm) {

confirmFun()

}

},

});

}

},

{

id: "assemblyAttribute",

placeholder: "请选择",

label: "组件属性",

type: "single-select",

redTip: false,

readonly: false,

showSelect: false,

selectTitle: "请选择",

list: [],

listMap: {},

rules: [

{

type: 'string',

required: true,

message: '请选择',

trigger: ['change', 'blur']

}

]

},

{

id: "applySituation",

placeholder: "请选择",

label: "应用场景",

type: "single-select",

redTip: false,

readonly: false,

showSelect: false,

selectTitle: "请选择",

list: [],

listMap: {},

rules: [

{

type: 'string',

required: true,

message: '请选择',

trigger: ['change', 'blur']

}

]

},

{

id: "singleDoubleSide",

placeholder: "请选择",

label: "单双面",

type: "single-select",

redTip: false,

readonly: false,

showSelect: false,

selectTitle: "请选择",

list: [],

listMap: {},

rules: [

{

type: 'string',

required: true,

message: '请选择',

trigger: ['change', 'blur']

}

]

},

]

},

],

七、案例显示

可以进行复杂的交互和可视区域定位校验


http://www.ppmy.cn/news/1435133.html

相关文章

Web3与物联网:探索区块链如何驱动智能设备的未来

引言 在数字化快速发展的时代&#xff0c;Web3技术和物联网&#xff08;IoT&#xff09;都成为了前沿技术的代表。两者的结合正逐渐展现出无限的可能性&#xff0c;尤其是在智能设备和数据安全方面。本文将深入探讨Web3如何与物联网相结合&#xff0c;以及这种结合对未来智能设…

C++多态(个人笔记)

C多态 1.多态的定义以及实现1.1多态的构成条件1.2虚函数1.3虚函数的重写1.4override和final1.5函数重载&#xff0c;覆盖&#xff08;重写&#xff09;&#xff0c;隐藏&#xff08;重定义&#xff09;区别 2.抽象类2.1接口继承和实现继承的区别 3.多态原理3.1虚函数表3.2多态的…

L1-099 帮助色盲 - java

L1-099 帮助色盲 代码长度限制 16 KB 时间限制 400 ms 内存限制 64 MB 栈限制 8192 KB 题目描述&#xff1a; 在古老的红绿灯面前&#xff0c;红绿色盲患者无法分辨当前亮起的灯是红色还是绿色&#xff0c;有些聪明人通过路口的策略是这样的&#xff1a;当红灯或绿灯亮起时&am…

《深入浅出.NET框架设计与实现》笔记6.2——ASP.NET Core应用程序多种运行模式之二——IIS 服务承载

ASP.NET Core应用程序可以在多种运行模式下运行&#xff0c;包括自宿主&#xff08;Self-Hosting&#xff09;、IIS服务承载、桌面应用程序、服务承载。 因此选择和时的模式很重要。 IIS 服务承载 将 ASP.NET Core 应用程序托管在 Internet Information Services (IIS) 中。 …

Day1--什么是网络安全?网络安全常用术语

目录 1. 什么是网络安全&#xff1f; 信息系统&#xff08;Information System&#xff09; 信息系统安全三要素&#xff08;CIA&#xff09; 网络空间安全管理流程 网络安全管理 2. 网络安全的常用术语 3. 网络安全形势 4. 中国网络安全产业现状 1. 什么是网络安全&am…

(ChatGPT、Al柯基、Al Web、ChatGPT4.0中文网、VIVI-Al)分享好用的ChatGPT

目录 1、ChatGPT 2、AI柯基 - 智能写作助手 - 沈阳满信电子商务有限公司 3、AI Web

Linux红帽(RHCE)认证学习笔记

Linux 文件管理 1. Linux下的目录结构 / 是Linux里的根目录 Linux的一级目录 /boot :存放的是系统的启动配置⽂件和内核⽂件/dev :存放的是Linux的设备⽂件/etc:存放的是Linux下的配置文件/home:存放普通用户的家目录/media:挂载点⽬录/mnt:挂载点⽬录/run:挂载点⽬…

Linux第七章

&#x1f436;博主主页&#xff1a;ᰔᩚ. 一怀明月ꦿ ❤️‍&#x1f525;专栏系列&#xff1a;线性代数&#xff0c;C初学者入门训练&#xff0c;题解C&#xff0c;C的使用文章&#xff0c;「初学」C&#xff0c;linux &#x1f525;座右铭&#xff1a;“不要等到什么都没有了…