表单组件封装
组件代码
<template>
<el-form
ref="ruleFormRef"
class="elForm"
:inline="true"
:rules="rules"
:model="TableList"
label-width="150"
>
<template v-if="fromlist.isInput">
//父组件传递的数据对象
<template v-for="(item, key, index) in fromlist.listData">
<!-- 输入框 -->
<el-form-item
:prop="key"
:label="item.title"
v-if="item.type == 'input' && item.show"
:key="index"
>
<el-input
:disabled="item.disabled"
v-model="TableList[key]"
:clearable="item.clearable"
:placeholder="'请输入' + item.title"
:suffix-icon="item.icon"
:style="{ width: fromlist.with }"
/>
</el-form-item>
<!-- 密码框 -->
<el-form-item
:prop="key"
:label="item.title"
v-if="item.type == 'password' && item.show"
:key="index"
>
<el-input
v-model="TableList[key]"
:clearable="item.clearable"
:placeholder="'请输入' + item.title"
:suffix-icon="item.icon"
:style="{ width: fromlist.with }"
/>
</el-form-item>
<!-- 下拉框 -->
<el-form-item
:prop="key"
:key="item.show"
:label="item.title"
v-if="item.type == 'select' && item.show"
>
<el-select
collapse-tags
l-select
v-model="TableList[key]"
:max-collapse-tags="1"
:filterable="item.filterable"
:multiple="item.multiple"
:clearable="item.clearable"
:placeholder="'请输入' + item.title"
:style="{ width: fromlist.with }"
>
<span v-if="item.children.constructor === Object">
<el-option
v-for="(value, key) in item.children"
:key="key"
:label="value"
:value="key"
>
</el-option>
</span>
<span v-if="item.children.constructor === Array">
<el-option
v-for="(item, key) in item.children"
:key="key"
:label="item.label"
v-html="item.label2 ? item.label2 : item.label"
:value="item.value"
>
</el-option>
</span>
</el-select>
</el-form-item>
<!-- 开始时间 -->
<el-form-item
:prop="key"
:key="item.show"
:label="item.title"
v-if="item.type == 'time' && item.show"
>
<el-date-picker
v-model="TableList[key]"
type="datetimerange"
start-placeholder="Date"
end-placeholder="End Date"
date-format="YYYY/MM/DD"
time-format="hh:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
:style="{ width: fromlist.with }"
/>
</el-form-item>
<!-- 年月日时分秒 -->
<el-form-item
class="daterange_dom"
:prop="key"
:key="item.show"
:label="item.title"
v-if="item.type == 'picker' && item.show"
>
<el-date-picker
v-model="TableList[key]"
type="daterange"
start-placeholder="开始时间"
end-placeholder="结束时间"
value-format="YYYY-MM-DD"
:default-value="[new Date(2010, 9, 1), new Date(2010, 10, 1)]"
:style="{ width: fromlist.with }"
/>
</el-form-item>
<!-- 单选框 -->
<el-form-item
:prop="key"
:label="item.title"
v-if="item.type == 'radio' && item.show"
:key="index"
>
<el-radio-group
v-model="TableList[key]"
v-for="(res, index) in item.children"
>
<el-radio-button
:label="item.children[index].value"
>{{item.children[index].label}}</el-radio-button>
</el-radio-group>
</el-form-item>
<!-- 单选 -->
<el-form-item
:prop="key"
:label="item.title"
v-if="item.type == 'radio1' && item.show"
>
<el-radio-group
v-model="TableList[key]"
v-for="(val, index) in item.children"
>
<el-radio :label="item.children[index].value" >
{{item.children[index].label}}
</el-radio>
</el-radio-group>
</el-form-item>
<!-- 文本框 -->
<el-form-item
:prop="key"
:label="item.title"
v-if="item.type == 'textarea' && item.show"
:key="index"
>
<el-input
type="textarea"
v-model="TableList[key]"
:clearable="item.clearable"
:placeholder="'请输入' + item.title"
:suffix-icon="item.icon"
:style="{ width: fromlist.with }"
/>
</el-form-item>
</template>
<!-- 操作按钮 -->
<el-form-item
id="form_But"
style="display: block"
v-if="fromlist.index !== '2'"
>
<div class="form_But_div">
<el-button type="primary" @click="onSubmit(ruleFormRef)">查询</el-button>
<Button
plain
:title="'重置'"
@click="ResetForm(ruleFormRef)"
:pattern="'centre'"
/>
<el-link
v-if="isshow"
class="Rigth_ellink"
@click="handelClickShow(show, fromlist)"
:underline="false"
>
<span>
<span v-show="!show">展开</span>
<span v-show="show">合并</span>
</span>
<span class="show_icon">
<Icons
:theme="'outline'"
:size="24"
:is="!show ? 'expand-down-one' : 'fold-up-one'"
/>
</span>
</el-link>
</div>
</el-form-item>
</template>
</el-form>
</template>
<script setup lang="ts">
import ElementResizeDetectorMaker from "element-resize-detector";
import {
reactive,
defineProps,
ref,
getCurrentInstance,
onMounted,
defineExpose,
} from "vue";
import { User } from "@element-plus/icons-vue";
import { Icons } from "@/components";
import { Button } from "@/components";
const { proxy } = getCurrentInstance();
//接收父级弹窗组件传递过来的数据
const props = defineProps(["fromlist", "Radio", "submitValue"]);
const data = ref({});
//(列表页面),显示查询参数是否显示 true为显示 show将动态赋值给fromlist数据对象中传递过来的查询参数,根据上面template的判断,是否显示
let show = ref(false);
//(列表页面,显示查询参数的数量(比如输入框等等)
let DomNumber = ref(0);
//(弹窗表单) 接收弹窗组件传递过来的页面查询的数据对象
let fromlist = ref(props.fromlist);
//表单组件ref
const ruleFormRef = ref(null);
//(弹窗表单)定义表单组件的校验,弹窗表单中使用
const rules = reactive(getRulesList(fromlist.value.listData))
//(弹窗表单)定义绑定在表单中的数据接收对象, rules 和 TableList中对应上才能校验。
let TableList = reactive(TableListParameter(fromlist.value.listData))
//(弹窗表单)根据弹窗组件传递过来的数据类型,重新定义表单接收输入数据的对象。
function TableListParameter(params:object) {
let list = {}
for(const key in params){
list[key] = params[key].value
}
return list
}
//(弹窗表单)根据弹窗组件传递过来的数据类型,动态定义表单校验规则。
function getRulesList(params:type) {
let list = {}
for (const key in params) {
if(params[key].required){
let data = []
//判断传递过来的参数类型是输入框还是下拉框
switch (params[key].type) {
case 'input':
data = [
{required: true, message: `请输入${params[key].title}`, trigger: 'blur' }
]
break;
case 'select':
data = [
{required: true, message: `请选择${params[key].title}`, trigger: 'change' }
]
break;
}
list[key] = data
}
}
return list
}
//(列表页面)emit 父子组件通信,UserSearch是父组件传定义接收子组件传递接收数据的方法
const emit = defineEmits([`UserSearch`]);
//(列表页面判断是否显示表单组件中的 (查询) (重置) 按钮,弹窗表单组件是不现实的
let isshow = ref(false);
onMounted(() => {
//(列表页面 判断是否传递过来的是表单查询,如果是就调用显示查询参数方法 type:tabulation 表示列表页面
if (
props.fromlist.listData &&
props.fromlist.isInput &&
props.fromlist.type == 'tabulation'
) {
OnToPage();
} else {
//(弹窗表单)
proxy.$PublicAPI.UpdataFormList(props.fromlist.listData);
}
});
//(弹窗表单) 将子组件 变量、方法 抛出,父组件可以直接电泳
defineExpose({
TableList,ResetForm,FormresetFields
});
//(列表页面)列表查询控制查询参数的显示隐藏,如果查询参数超过2行内容,多的隐藏,此方法点击展开可展示全部查询参数,折叠就只显示两行的查询参数
function handelClickShow(type: boolean) {
show.value = !show.value;
UpPorpsData(fromlist, show.value);
}
//(列表页面) 进入页面,定义请求参数显示两行方法
function OnToPage() {
let erd = ElementResizeDetectorMaker();
let jianshiDom = document.querySelector(".elForm");
let butDom =
(document.querySelector("#form_But").offsetHeight + 8) * 5 + 8 + "px";
document
.getElementsByTagName("body")[0]
.style.setProperty("--input_Width", butDom);
erd.listenTo(jianshiDom, (ele) => {
let inputWidth = jianshiDom?.children[0].offsetWidth;
let OneContentWidth = Math.floor(jianshiDom.offsetWidth / inputWidth);
DomNumber.value = OneContentWidth * 2;
UpPorpsData(fromlist, show.value);
});
}
//(列表页面)根据上面的方法,多出两行的查询参数对象定义show为false使元素隐藏起来
function UpPorpsData(data: type, type: boolean) {
let forKey = Object.keys(data.value.listData);
if (type) {
forKey.map((itme, index, key) => {
data.value.listData[itme].show = true;
});
} else {
forKey.map((itme, index) => {
let kk = DomNumber.value;
if (kk < Object.keys(fromlist.value.listData).length) {
isshow.value = true;
if (kk > 0) {
if (index < kk) {
data.value.listData[itme].show = true;
} else {
data.value.listData[itme].show = false;
}
}
} else {
isshow.value = false;
data.value.listData[itme].show = true;
}
});
}
return data.value;
}
//(列表页面) 列表中点击查询,传递给父组件,proxy.$store.rou_Name 获取到的当前路由如:/user 将改变为:User ,此行就是 UserSearch ,这是在user页面中引用了表单组件 @UserSearch 定义接收子组件传递回来的方法。TableList:提交给父组件的数据,submit:点击的按钮类型(查询按钮) resetting :点击的按钮类型(重置按钮)
async function onSubmit(formEl: FormInstance | undefined) {
emit(`${proxy.$store.rou_Name}Search`, TableList, "submit");
}
function FormresetFields() {
ruleFormRef.value.resetFields();
}
//重置
function ResetForm(formEl: FormInstance | undefined) {
if (!ruleFormRef) return;
//清空输入的内容
ruleFormRef.value.resetFields();
emit(`${proxy.$store.rou_Name}Search`, TableList, "resetting");
}
</script>
<style >
:root {
--input_Width: 500px;
}
</style>
<style scoped lang="less" >
::v-deep.elForm {
padding: 8px 16px 0px 16px;
background: white;
position: relative;
max-height: var(--input_Width) !important;
overflow: hidden;
overflow-y: auto;
}
::v-deep .el-input,
.el-select {
height: 32px !important;
}
::v-deep .el-input .el-input__wrapper {
height: 32px !important;
}
::v-deep .el-input__wrapper:hover,
::v-deep .el-select__wrapper:hover {
box-shadow: 0 0 0 1px var(--theme_background) inset !important;
}
::v-deep.el-button {
min-width: 88px;
height: 32px;
}
::v-deep.el-form--inline .el-form-item {
margin-right: 14px !important;
}
::v-deep.Button {
margin-left: 29px !important;
}
.form_But {
height: 32px;
position: absolute;
right: -27px;
}
::v-deep .el-form-item__content {
display: flex;
justify-content: end;
// width: 248px;
}
.Rigth_ellink {
min-width: 88px;
display: flex;
}
.show_icon {
display: flex;
justify-content: center;
align-items: center;
margin-left: 3px;
}
::v-deep(.el-form-item) {
margin-bottom: 8px;
}
#form_But {
width: 398px;
}
.form_But_div {
display: flex;
align-items: center;
}
::v-deep .el-form-item {
margin-bottom: 8px;
}
::v-deep.el-button--primary {
background: var(--secondary_but_Backgroun) !important;
color: var(--theme_background) !important;
border: 1px solid var(--secondary_but_border);
}
::v-deep.el-button--primary:hover {
border: 1px solid var(--theme_background);
}
::v-deep.el-button--primary:active {
border: 1px solid var(--secondary_but_Click);
}
::v-deep .el-range__icon {
float: none !important;
position: absolute !important;
right: 10px !important;
}
::v-deep(.el-input__prefix) {
display: none;
}
::v-deep(.el-radio-button__inner) {
border-radius: 20px !important;
}
</style>
弹窗组件调用
<template>
<div>
<el-dialog
:title="props.FormList.title"
v-model="drawer"
width="40%"
:before-close="handleClose"
>
<div class="dialog">
<!--props.FormList 父组件传递的表单渲染组件数据 -->
<FromData
:fromlist="props.FormList"
:Radio="Radio"
ref="formDataRef"
></FromData>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleClose">取 消</el-button>
<el-button type="primary" @click="submit()">确 定</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts">
import { ref, watch, getCurrentInstance, defineProps, onMounted,defineExpose } from "vue";
import { FromData } from "@/components";
const { proxy } = getCurrentInstance();
import bus from "@/mitt";
import router from "/src/router/index";
//接收调用弹窗组件传递过来的参数
const props = defineProps(["FormList"]);
//点击弹窗可传给调用弹窗页面的接受方法
const emit = defineEmits(['UserPopUpWindow','ConfigPopUpWindow'])
// 弹窗默认打开,调用组件的页面中控制弹窗组件的显示隐藏即可
const drawer = ref(true);
const title = ref("");
const fromlist = ref({});
const submitValue = ref("");
// 创建一个 ref 来引用子组件
const formDataRef = ref(null);
const Radio = ref({});
//弹窗确认按钮
const submit = () => {
//formDataRef 表单组件ref ,因为表单组件中抛出了方法或者变量数据,在这里可以直接调用
const childComponent = formDataRef.value;
if (childComponent && childComponent.TableList) {
const list = childComponent.TableList;
//提交给调用弹窗组件的页面
emit(`${proxy.$store.rou_Name}PopUpWindow`,list,childComponent,props.FormList.type)
}
};
onMounted(() => {
});
//关闭弹窗
const handleClose = () => {
//调用表单组件中的重置操作
formDataRef.value.FormresetFields()
emit(`${proxy.$store.rou_Name}PopUpWindow`, false)
};
</script>
<style lang="less" scoped>
.dialog {
width: 90%;
margin: 10px auto 0 auto;
}
::v-deep(.el-dialog) {
--el-dialog-padding-primary: 5px 0 0 0;
}
::v-deep(.el-dialog__header) {
border-bottom: 1px solid #ccc;
line-height: 40px !important;
}
::v-deep(.el-dialog__title) {
margin-left: 16px;
}
::v-deep .elForm {
max-height: 100% !important;
}
::v-deep .el-form-item {
margin-bottom: 20px;
}
::v-deep .el-form-item__content,
::v-deep .el-input,
::v-deep.el-select {
height: 40px !important;
}
::v-deep .el-input__inner {
line-height: 40px !important;
}
::v-deep(.el-radio-group:nth-child(2)) {
margin-left: 20px;
}
::v-deep(.el-dialog__footer) {
border-top: 1px solid #ccc;
padding: 10px 15px 10px 0;
}
</style>
页面调用表单组
<template>
<div class="box">
<div class="title">WEB权限 <span>列表</span></div>
<div class="contet">
<div class="button">
<div >
<Button :type="'primary'" @click="handleClickUp('expand')" :icon="'plus'" :title="'展开'" :pattern="'centre'" />
<Button :type="'primary'" @click="handleClickUp('retract')" :icon="'plus'" :title="'收起'" :pattern="'centre'" />
<Button :type="'primary'" @click="handelSubmit" :icon="'plus'" :title="'保存'" :pattern="'centre'" />
<Button plain :title="'刷新'" @click="clickRefresh" :pattern="'centre'" :icon="'download'"/>
</div>
<div>
<Button :type="'primary'" @click="handelCreateConfig" :icon="'plus'" :title="'新增'" :pattern="'centre'" />
</div>
</div>
<!-- 树状结构 -->
<div class="Tree" >
<Tree :isUp="isUp" ref="treelist" :treeApiObject="treeApiObject" @ConfigTree="ConfigTree" />
</div>
</div>
<!-- 新增编辑弹出框 -->
<PopUpWindow :FormList="FormList" @ConfigPopUpWindow="ConfigPopUpWindow" v-if="PopUpWindowShow" ></PopUpWindow>
</div>
</template>
<script lang="ts" setup>
import { Button ,Tree , PopUpWindow, } from "@/components";
import { onMounted, ref } from "vue";
import useCurrentInstance from "@/hooks/useCurrentInstance";
const { proxy } = useCurrentInstance();
const isUp = ref({
number : 0,
type : ''
})
const treelist = ref(null)
const treeApiObject = ref({
deleteUrl:'/system/permission/delete',
editUrl :'/system/permission/edit'
})
const PopUpWindowShow = ref(false)
//定义传递给
const FormList = ref({
index:'2',
formInline:true,
isInput:true,
type:'create',
title:'新增权限',
with:'448px',
listData:{
"parent_id":{
title:'父级',
type:'select',
clearable:true,
required:true,
value:'',
children:[]
},
"permission_type":{
title:'权限类型',
type:'select',
required:true,
clearable:true,
value:'',
children:[{
label:"菜单",
value:1
},
{
label:"列表",
value:2
},
{
label:"按钮",
value:3
},
]
},
"name":{
title:'名称',
type:'input',
required:true,
clearable:true,
value:'',
},
"slug":{
title:'权限标识',
type:'input',
required:true,
clearable:true,
value:'',
},
"guard_name":{
title:'规则',
type:'input',
disabled:true,
clearable:true,
value:'web',
},
"web_path":{
title:'前端访问路径',
type:'input',
required:true,
clearable:true,
value:'',
},
}
})
const resettingFormList = ref(null)
onMounted(()=>{
getSessingStorageList()
})
function handleClickUp(type:string) {
isUp.value.type = type
if(type == 'expand'){
isUp.value.number += 1
}else{
isUp.value.number += 1
}
}
function clickRefresh() {
treelist.value.GetTreeList()
}
function handelSubmit() {
let list:number[] = []
proxy.$PublicAPI.UpdataTreeList(treelist.value.data,list)
proxy.$project_interface.SaveTreeList({"permission_data":list}).then(res=>{
console.log('res',res);
})
}
//点击新增 传递首次进入的数据类型
function handelCreateConfig() {
PopUpWindowShow.value = true
}
//这个是获取添加弹窗表单的下拉数据
function getSessingStorageList() {
let list:number[] = []
let navlist = [{
id:0,
hidden:1,
name:'系统',
order:2,
Permissions:1,
web_path:'',
children:JSON.parse(sessionStorage.getItem('NavList'))
}]
proxy.$PublicAPI.UpdataSelectTree(navlist,list,1)
console.log('list',list);
FormList.listData['parent_id'].children = list
resettingFormList.value = JSON.parse(JSON.stringify(FormList.value))
}
//接收菜单树状点击编辑传递过来的数据
function ConfigTree(params:object){
FormList.value.title = '编辑权限'
FormList.value.type = 'edit'
FormList.value.listData['id'] = {
value:params.id
}
for (const key in params) {
for (const index in FormList.value.listData) {
if(index == key){
if(FormList.value.listData[index].type == 'select'){
FormList.value.listData[index].value = parseInt(params[key])
}else{
FormList.value.listData[index].value = params[key]
}
}
}
}
PopUpWindowShow.value = true
}
//根据弹窗组件传递过来的数据来判断是点击了取消还是确认,并做出相应的处理
function ConfigAxios(params:object, subset:object,type:string) {
let apiName = ''
if(type == 'create'){
apiName = 'Createconfig'
}else if(type == 'edit'){
apiName = 'Editconfig'
}
proxy.$project_interface[apiName](params).then(res=>{
if(res.code == 200){
subset.ResetForm()
PopUpWindowShow.value = false
clickRefresh()
}
})
}
//接收弹窗关闭传递过来的数据
function ConfigPopUpWindow(params:boolean,subset:object,type:string) {
if(typeof(params) == 'boolean'){
PopUpWindowShow.value= params
FormList.value = JSON.parse(JSON.stringify(resettingFormList.value))
}else{
ConfigAxios(params,subset,type)
}
}
</script>
<style scoped lang="less">
.box{
width: 99%;
height: 100%;
margin: auto;
.title{
font-size: 24px;
letter-spacing: 0.1em;
color: var(--PublicFonteColor);
span{
color:var(--Nav_Font_Color);
font-size:var(--Nav_FontSize) ;
}
}
.contet{
margin-top: 18px;
width: 100%;
background: white;
.button{
display: flex;
justify-content: space-between;
padding: 16px 0;
border-bottom:1px solid #ccc;
div {
padding: 0 5px;
display: flex;
}
}
.Tree{
padding: 16px 10px;
}
}
}
</style>
本站资源均来自互联网,仅供研究学习,禁止违法使用和商用,产生法律纠纷本站概不负责!如果侵犯了您的权益请与我们联系!
转载请注明出处: 免费源码网-免费的源码资源网站 » Vue3:ElementPlus分装动态列表查询表单和弹窗动态表单
发表评论 取消回复