我是靠谱客的博主 谦让项链,最近开发中收集的这篇文章主要介绍vue3+element-plus 的form多表单组件及多Descriptions详情组件封装(可实现单页面有多个表单/详情按模块的方式展示并且可以收缩;Vue3项目),觉得挺不错的,现在分享给大家,希望可以做个参考。
概述
一、最终效果
二、组件集成了以下功能
1、可以多模块配置form表单——配置formOpts对象
2、每个模块可以收起或展开——模块不设置title值取消此功能(或者设置disabled:true)
3、每个模块可以自定义插槽设置
4、头部标题可以显示隐藏——有title则显示没有则隐藏
5、可以自定义设置footer操作按钮(默认:表单显示取消和保存按钮;详情显示取消按钮)——设置 :footer="null"
6、多表单校验不通过可以指定哪个模块
7、可以设置tabs(默认展示第一个tab;可以指定展示某一个根据setSelectedTab方法)
8、头部返回操作默认返回上一页,若需要自定义可以设置isGoBackEvent
9、多模块详情页面value值可以自定义插槽
10、多模块详情页面value值可以自定义tip(提示)
11、多模块表单或详情页面如果不使用手风琴收缩功能可以设置“disabled:true”
三、实际组件是以下组件结合,并继承其Attributes
1、多模块表单是基于我之前封装的 t-form组件
2、多模块详情是基于我之前封装的 t-detail组件
四、参数配置
1、代码示例
<!-- 第一种 表单形式 -->
<t-module-form
title="模块表单组件运用"
subTitle="模块表单"
ref="sourceForm"
:formOpts="formOpts"
:submit="submit"
:tabs="tabs"
@handleEvent="handleEvent"
/>
<!-- 第二种详情展示 根据handleType-->
<t-module-form
title="详情模块组件运用"
subTitle="模块详情"
ref="sourceDetail"
handleType="desc"
:descData="descData"
:tabs="tabs"
/>
2、配置参数(Attributes)继承 t-form/t-detail Attributes
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
title | 头部返回按钮标题 | string | 无 |
titleSlot | 是否使用插槽显示 title | Boolean | false |
subTitle | 头部副标题 | string | 无 |
extra | 操作区,位于 title 行的行尾(右侧) | slot | 无 |
footer | 底部操作区(默认展示“取消/保存”按钮;使用插槽则隐藏)footer="null"时隐藏底部操作 | String slot | 无 |
tabs | 页面展示是否需要页签(并且 tabs 的 key 是插槽) | Array | 无 |
isGoBackEvent | 点击头部返回(默认返回上一页,设置此值可以自定义 back 事件) | Boolean | false |
handleType | 显示方式(‘edit’:form 表单操作,‘desc’:表详情页面) | string | edit |
----edit | handleType=edit 表 form 表单操作的属性 | - | - |
------formOpts | 表单配置描述,支持多分组表单 | Object | 无 |
------submit | 点击保存时返回所有表单数据(数据格式 promise 且可显示 loading 状态) | function | 所有表单数据 |
-----desc | handleType=desc 表详情页面的属性 | - | - |
------descColumn | 详情页面展示每行显示几列(handleType= desc 生效) | Number | 4 |
------descData | 详情页面配置描述,支持多分组表 (handleType= desc 生效) | Object | 无 |
2-1、formOpts 配置参数
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
title | 表单标题(是否显示控制折叠面板功能) | String | 无 |
slotName | 插槽(自定义表单数据)有插槽就无需配置 opts | slot | 无 |
name | 每组表单定义的名字(作用:是否默认展开) | String | 无 |
widthSize | 每行显示几个输入项(默认两项) 最大值 4 | Number | 3 |
disabled | 禁用时取消收缩功能及隐藏 icon) | Boolean | false |
opts | 表单配置项 | Object | 无 |
2-1-1、opts 配置参数
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
rules | 规则(可依据 element-plus el-form 配置————对应 formData 的值) | Object/Array | - |
operatorList | 操作按钮 list | Array | - |
listTypeInfo | 下拉选择数据源(type:'select’有效) | Object | - |
labelPosition | 改变表单项 label 与输入框的布局方式(默认:right) /top | String | right |
labelWidth | label 宽度(默认值 120px) | String | 120px |
formData | 表单提交数据(对应 fieldList 每一项的 value 值) | Object | - |
fieldList | form 表单每项 list | Array | - |
----slotName | 自定义表单某一项输入框 | slot | - |
----comp | form 表单每一项组件是输入框还是下拉选择等(可使用第三方 UI 如 el-select/el-input 也可以使用自定义组件) | String | - |
----bind | 表单每一项属性(继承第三方 UI 的 Attributes,如 el-input 中的 clearable 清空功能)默认清空及下拉过滤 | Object | - |
----type | form 表单每一项类型 | String | - |
----widthSize | form 表单某一项所占比例(如果一行展示可以设值:1) | Number | 2 |
----width | form 表单某一项所占实际宽度 | String | - |
----arrLabel | type=select-arr 时,每个下拉显示的中文 | String | label |
----arrKey | type=select-arr 时,每个下拉显示的中文传后台的数字 | String | key |
----label | form 表单每一项 title | String | - |
----labelRender | 自定义某一项 title | function | - |
----value | form 表单每一项传给后台的参数 | String | - |
----rules | 每一项输入框的表单校验规则 | Object/Array | - |
----list | 下拉选择数据源(仅仅对 type:'select’有效) | String | - |
----event | 表单每一项事件标志(handleEvent 事件) | String | - |
2-2、descData 配置参数
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
title | 详情标题(是否显示控制折叠面板功能) | String | - |
slotName | 插槽(自定义详情数据)有插槽就无需配置 data | slot | - |
name | 每组详情定义的名字(作用:是否默认展开) | String | - |
disabled | 禁用时取消收缩功能及隐藏 icon) | Boolean | false |
data | 详情配置项 | Object | - |
----label | 详情字段说明标题 | String | - |
----value | 详情字段返回值 | String | - |
----slotName | 插槽(自定义 value) | slot | - |
----span | 占用的列宽,默认占用 1 列,最多 4 列 | Number | 1 |
----tooltip | value 值的提示语 | String/function | - |
3、events
事件名 | 说明 | 返回值 |
---|---|---|
handleEvent | 单个查询条件触发事件 | fieldList 中的 event 值和对应输入的 value 值 |
tabsChange | 点击 tab 切换触发 | 被选中的标签 tab 实例 |
validateError | 校验失败抛出事件 | obj——每个收缩块的对象 |
back | 头部标题点击返回事件 | - |
4、Methods
事件名 | 说明 | 参数 |
---|---|---|
resetFormFields | 重置表单 | - |
clearValidate | 清空校验 | - |
setSelectedTab | 默认选中 tab | 默认选中 tab 插槽名 |
五、具体代码
<template>
<div class="t_module_form" :style="{marginBottom:footer!==null?'60px':''}">
<div class="scroll_wrap">
<!-- 头部 -->
<el-page-header
v-if="title||titleSlot"
:title="title"
@back="back"
:class="{noContent:!isShow('extra')&&!subTitle,'isShowBack':isShowBack}"
>
<template #title v-if="titleSlot">
<slot name="title"></slot>
</template>
<template #content>
<div class="sub_title">{{subTitle}}</div>
<div class="extra">
<slot name="extra"></slot>
</div>
</template>
</el-page-header>
<!-- 表单页面 -->
<module-form v-if="handleType==='edit'" v-bind="$attrs" ref="tForm">
<template v-for="(index, name) in slots" v-slot:[name]="data">
<slot :name="name" v-bind="data"></slot>
</template>
</module-form>
<!-- 详情页面 -->
<module-detail v-else v-bind="$attrs">
<template v-for="(index, name) in slots" v-slot:[name]="data">
<slot :name="name" v-bind="data"></slot>
</template>
</module-detail>
<!-- tabs -->
<div class="tabs" v-if="tabs">
<el-tabs
v-if="tabs&&tabs.length > 1"
v-model="activeName"
@tab-click="(tab, event) => emits('tabsChange', tab, event)"
>
<el-tab-pane v-for="tab in tabs" :key="tab.key" :name="tab.key" :label="tab.title">
<slot :name="tab.key"></slot>
</el-tab-pane>
</el-tabs>
<slot v-else :name="tabs&&tabs[0].key"></slot>
</div>
<slot name="default"></slot>
</div>
<!-- 按钮 -->
<footer class="handle_wrap" v-if="footer!==null">
<slot name="footer" />
<div v-if="!slots.footer">
<el-button @click="back">取消</el-button>
<el-button
type="primary"
v-if="handleType==='edit'"
@click="saveHandle"
:loading="loading"
>{{btnTxt}}</el-button>
</div>
</footer>
</div>
</template>
<script lang="ts">
export default {
name: 'TModuleForm',
}
</script>
<script setup lang="ts">
import {computed,watch,ref,useAttrs,useSlots,nextTick,onMounted,} from 'vue'
// import { useRouter } from 'vue-router'
import ModuleDetail from './moduleDetail.vue'
import ModuleForm from './moduleForm.vue'
const props: any = defineProps({
handleType: {
type: String,
default: 'edit', // edit表form表单操作,desc表详情页面
},
// 是否使用插槽显示title
titleSlot: {
type: Boolean,
default: false,
},
// 是否显示返回箭头
isShowBack: {
type: Boolean,
default: false,
},
// 返回上一层触发方法
isGoBackEvent: {
type: Boolean,
default: false,
},
// 操作按钮文字
btnTxt: {
type: String,
default: '保存',
},
// 是否显示底部操作按钮 :footer="null"
footer: Object,
title: String,
subTitle: String,
tabs: Array,
submit: Function,
})
const attrs: any = useAttrs()
const slots = useSlots()
const activeName = ref(props.tabs && props.tabs[0].key)
const loading = ref(false)
// 获取ref
const tForm: any = ref<HTMLElement | null>(null)
// const router = useRouter()
onMounted(() => {
// console.log('router', router)
// console.log('onMounted', attrs)
// console.log('onMounted222', attrs.formOpts)
})
// 抛出事件
const emits = defineEmits(['validateError', 'back', 'tabsChange'])
// 点击保存
const saveHandle = async () => {
let form = {}
let formError = {}
let formOpts = {}
let successLength = 0
loading.value = true
// 过滤非插槽表单
Object.keys(attrs.formOpts).forEach((key) => {
if (attrs.formOpts[key].opts) {
formOpts[key] = attrs.formOpts[key]
}
})
Object.keys(formOpts).forEach(async (formIndex) => {
const { valid, formData } = await tForm.value.getChildRef(formIndex).validate()
// const { valid, formData } = await attrs.formOpts[formIndex].ref.validate()
// console.log('11111', valid)
if (valid) {
successLength = successLength + 1
form[formIndex] = attrs.formOpts[formIndex].opts.formData
// console.log('2222', successLength)
// console.log('3333', form)
}
})
setTimeout(async () => {
if (successLength === Object.keys(formOpts).length) {
// 所有表单都校验成功
const isSuccess = await props.submit(form)
if (isSuccess) {
// 成功
back()
}
} else {
// 校验失败抛出事件
Object.keys(formOpts).forEach((key) => {
if (Object.keys(form).length > 0) {
Object.keys(form).map((val) => {
if (key !== val) {
formError[key] = formOpts[key]
}
})
} else {
formError[key] = formOpts[key]
}
})
emits('validateError', formError)
}
loading.value = false
}, 300)
}
// 点击头部返回或者取消
const back = () => {
if (props.isShowBack) {
return
}
emits('back')
if (!props.isGoBackEvent) {
// router.go(-1)
history.go(-1)
}
}
const show = (formType) => {
nextTick(() => {
updateFormFields()
props.formType = formType
})
}
// 获取默认选中tab
const setSelectedTab = (key) => {
activeName.value = key
}
// 清空表单
const resetFormFields = () => {
let formOpts = {}
// 过滤非插槽表单
Object.keys(attrs.formOpts).forEach((key) => {
if (attrs.formOpts[key].opts) {
formOpts[key] = attrs.formOpts[key]
}
})
Object.keys(formOpts).forEach((formIndex) => {
tForm.value.getChildRef(formIndex).resetFields()
})
}
// 清空校验规则
const clearValidate = () => {
let formOpts = {}
// 过滤非插槽表单
Object.keys(attrs.formOpts).forEach((key) => {
if (attrs.formOpts[key].opts) {
formOpts[key] = attrs.formOpts[key]
}
})
Object.keys(formOpts).forEach((formIndex) => {
tForm.value.getChildRef(formIndex).clearValidate()
})
}
const updateFormFields = () => {
let formOpts = {}
// 过滤非插槽表单
Object.keys(attrs.formOpts).forEach((key) => {
if (attrs.formOpts[key].opts) {
formOpts[key] = attrs.formOpts[key]
}
})
Object.keys(formOpts).forEach((formIndex) => {
tForm.value.getChildRef(formIndex).updateFields(false)
})
}
const isShow = (name) => {
return Object.keys(slots).includes(name)
}
// 暴露方法出去
defineExpose({clearValidate,resetFormFields,updateFormFields,setSelectedTab})
</script>
六、组件地址
gitHub组件地址
gitee码云组件地址
七、相关文章
基于ElementUi&antdUi再次封装基础组件文档
vue3+ts基于Element-plus再次封装基础组件文档
vue2/3集成qiankun微前端
最后
以上就是谦让项链为你收集整理的vue3+element-plus 的form多表单组件及多Descriptions详情组件封装(可实现单页面有多个表单/详情按模块的方式展示并且可以收缩;Vue3项目)的全部内容,希望文章能够帮你解决vue3+element-plus 的form多表单组件及多Descriptions详情组件封装(可实现单页面有多个表单/详情按模块的方式展示并且可以收缩;Vue3项目)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复