XXXForm组件

devtools/2024/9/22 17:29:15/

效果展示

2024-04-182.40.57-ezgif.com-video-to-gif-converter.gif

代码

XXXForm

<template><div class="search-container"><el-form ref="formRef" class="form_is_hidden" :model="form" v-bind="formAttrs"><el-row :gutter="20" class="search-row"><el-colv-for="item in shows.columns":key="item.inputType + JSON.stringify(item.values)":span="item.span || 6"><el-form-item v-bind="item.formItemAttrs || {}"><FormItemv-if="typeof item.values == 'string'"v-bind="item.inputAttrs || {}"v-model="form[item.values]":input-type="item.inputType"/><FormItemv-elsev-model:one="form[item.values[0]]"v-model:two="form[item.values[1]]":input-type="item.inputType"v-bind="item.inputAttrs || {}"/></el-form-item></el-col><el-col :span="shows.btnsSpan" class="search-btn-container"><el-form-item class="search-btn" label="1" label-width="0"><el-tooltipv-if="shows.collapsedBtn":content="collapsed ? '收起' : '展开'"placement="top"trigger="hover"><el-button class="coll" text bg type="info" @click="toggleCollapse"><el-icon class="form_is_hidden_icon"><DArrowRight v-if="!collapsed" /><DArrowLeft v-else /></el-icon></el-button></el-tooltip><el-button text bg type="info" @click="resetForm">重置</el-button><el-button type="primary" @click="search">查询</el-button></el-form-item></el-col></el-row></el-form></div>
</template>
<script lang="ts" setup>
import { computed, ref } from 'vue';
import { useVModel } from '@vueuse/core';
import { SearchFormColum } from './type';
import FormItem from './formItem.vue';
import { DArrowRight, DArrowLeft } from '@element-plus/icons-vue';const props = defineProps({columns: {type: Array,default: () => [],},collapse: {type: Boolean,default: false,},modelValue: {type: Object,default: () => {return {};},},resttForm: {type: Object,default: () => {return {};},},formAttrs: {type: Object,default: () => {return {};},},
});
const emit = defineEmits(['update:modelValue', 'search', 'reset']);
const collapsed = ref(props.collapse);
const form = useVModel(props, 'modelValue', emit);
const shows = computed(() => {const cols = props.columns as SearchFormColum;const spans = cols?.map((i) => i.span || 6).reduce((a, b) => a + b, 0);if (spans > 18) {if (!collapsed.value) {let spanss = 0;let index = 0;try {cols?.forEach((i, idx) => {if (spanss < 18) {if ((i.span || 6) + spanss > 18) {throw new Error('');}spanss += i.span || 6;index = idx;} else {throw new Error('');}});} catch (error) {// console.log('跳出循环');}return {columns: cols.filter((_i, idx) => idx <= index),btnsSpan: 24 - spanss,collapsedBtn: true,};} else {const spanss = cols?.map((i) => i.span || 6).reduce((a, b) => {if (a + b > 24) {return b;} else if (a + b == 24) {return 0;} else {return a + b;}}, 0);const btnsSpan = spanss > 18 ? 24 : 24 - spanss;return {columns: cols,btnsSpan,collapsedBtn: true,};}} else {return {columns: cols,btnsSpan: 24 - spans,collapsedBtn: false,};}
});
const search = () => {emit('search');
};
const resetForm = () => {const resett = { ...props.resttForm };form.value = resett;emit('reset');
};
const toggleCollapse = () => {collapsed.value = !collapsed.value;
};
</script>
<style lang="less" scoped>
.search-container {// margin-bottom: 20px;.form_is_hidden_icon {transform: rotate(90deg);}.search-btn-container {.search-btn {:deep(.el-form-item__content) {justify-content: end;}:deep(.el-form-item__label) {color:transparent;}}}.search-row {// transition: height 0.3s;overflow: hidden;}.search-label {font-size: 14px;color: var(--hiwork-global-color);padding-bottom: 8px;}
}
:deep(.el-button).coll {padding: 10px 12px !important;
}
</style>

formItem

<template><component :is="currentCom" />
</template>
<script lang="tsx" setup>
// import cityCascader from './cityCascader';
import DateMonthPicker from './components/dateMonthPicker';
import DateRangePicker from './components/dateRangePicker';
import DateYearPicker from './components/dateYearPicker';
import Select from './components/select';
import CountryAutoComplete from './components/countryAutoComplete.vue';
import CountryAutoCompleteOne from './components/countryAutoCompleteOne.vue';
import HiInput from './components/hiInput.vue';
import { computed } from 'vue';
const props = defineProps({inputType: {type: String,default: 'input',},
});const currentCom = computed(() => {switch (props.inputType) {case 'date':return DateRangePicker;case 'month':return DateMonthPicker;case 'year':return DateYearPicker;// case 'cascader'://   return cityCascader;case 'select':return Select;case 'countryAuto':return CountryAutoComplete;case 'countryAuto1':return CountryAutoCompleteOne;default:return HiInput;}
});
</script>

XXXInput

<template><!-- hiInput --><el-input v-model="modelValue" @blur="hBlur" />
</template>
<script setup>
import { computed } from 'vue';
const props = defineProps({modelValue: {type: String,default: '',},
});
const emit = defineEmits(['update:modelValue']);
const modelValue = computed({get() {return props.modelValue;},set(v) {emit('update:modelValue', v);},
});
const hBlur = () => {modelValue.value = modelValue.value.trim();
};
</script>
// dateRangePicker
import { ElDatePicker } from 'element-plus';
import { defineComponent, reactive, watchEffect } from 'vue';
import dayjs from 'dayjs';export default defineComponent({props: {one: { type: String, default: () => '' },two: { type: String, default: () => '' },format: { type: String, default: () => '' },},emits: ['update:one', 'update:two'],// emits: {//   'update:one': (v: string) => true,//   'update:two': (v: string) => true,// },setup(props, { attrs, emit }) {const state = reactive({ivalue: [],});const updateValue = (v: (string | number | Date | dayjs.Dayjs | null | undefined)[],) => {emit('update:one',v ? dayjs(v[0]).format(props.format || 'YYYY-MM-DD') : '',);emit('update:two',v ? dayjs(v[1]).format(props.format || 'YYYY-MM-DD') : '',);};watchEffect(() => {state.ivalue = [props.one, props.two] as any;});return () => (<ElDatePickermodelValue={state.ivalue as any}onUpdate:modelValue={updateValue}type='daterange'range-separator='-'start-placeholder='开始'end-placeholder='结束'{...attrs}/>);},
});
// cityCascader
import { getLocationDetailInfo } from '@/axios/api';
import { ElCascader } from 'element-plus';
import { defineComponent, ref } from 'vue';export default defineComponent((_p, { attrs }) => {const cityList = ref([]);getLocationDetailInfo().then((res) => {cityList.value = res.data;});return () => (<ElCascader{...attrs}placeholder='请选择省市区'style={'width: 100%'}props={{ children: 'child', value: 'name', label: 'name' }}options={cityList.value}/>);
});

XXXInput,自己想要啥补充啥就行。

使用

props

参数说明类型可选值默认值
columns配置表单展示项object[]--
collapse是否收起booleantrue/falsefalse
modelValueform 对象{}-{}
resttForm重制 form 默认值{}-{}
formAttrs支持 el 的 form 属性{}-{}
cloumns 说明
参数说明类型可选值默认值
inputType输入框类型string--
spanformitem 占用空间(参考el-col)number1-246
formItemAttrs继承 el 的 formitem 的 props + emit,配置formitem 像 el 一样。{}--
valuesform 中对应的 keystring/string[]--
inputAttrs继承 el 的 input 的 props + emit,配置 input 像 el 一样。也是拓展属性的地方。{}--

emit

方法名说明类型
update:modelValue更新 form 对象-
search搜索-
reset重制-

使用示例

searchFormC

import { defineComponent, ref } from 'vue';
//@ts-ignore
import SearchForm from '@/components/searchForm/index.vue';
export default defineComponent((_p, { attrs }) => {const columns = ref([{values: 'nickname',inputType: 'input',span: 6,inputAttrs: {placeholder: '请输入',},formItemAttrs: {label: '姓名',labelWidth: '80px',},},{values: 'country',inputType: 'countryAuto1',inputAttrs: {placeholder: '请输入',},formItemAttrs: {label: '国家',labelWidth: '80px',},},{values: 'email',inputType: 'input',span: 6,inputAttrs: {placeholder: '请输入',},formItemAttrs: {label: '邮箱',labelWidth: '80px',},},{values: 'employeeCode',inputType: 'input',span: 12,inputAttrs: {placeholder: '请输入',},formItemAttrs: {label: '员工编号',labelWidth: '80px',},},{values: ['createStartTime', 'createEndTime'],inputType: 'date',span: 12,inputAttrs: {format: 'YYYY-MM-DD',placeholder: '请输入',},formItemAttrs: {label: '创建时间',labelWidth: '80px',},},]);return () => (<SearchForm {...attrs} columns={columns.value} collapse={false} formAttrs={{ labelPosition: 'left' }} />);
});

vue

<template><SearchFormC v-model="form" @search="search" @reset="rest" />
</template><script setup lang="ts">
import SearchFormC from './components/searchFormC'
import { ref } from 'vue';
const form = ref({})const search = () => {console.log(form.value)
}const rest = () => {console.log(form.value)
}
</script>

http://www.ppmy.cn/devtools/92441.html

相关文章

C++中的智能指针

目录 1.为什么需要智能指针 2.内存泄漏 2.1 什么是内存泄漏&#xff0c;内存泄漏的危害 2.2 内存泄漏分类&#xff08;了解&#xff09; 2.3 如何检测内存泄漏&#xff08;了解&#xff09; 2.4 如何避免内存泄漏 3.智能指针的使用及原理 3.1 RAII 3.2 智能指针的原理…

vscode配置代码片段生成快捷键

一开始还以为是装个插件的事&#xff0c;没想到是自己定义的快捷键。 以vue3代码片段为例 在vscode左下角点击红框处 选择新建全局代码片段文件 输入快捷键名称 vue3&#xff08;可以自定义&#xff09;&#xff0c;以.json结尾&#xff0c;回车 在打开的文件里编写需要的代…

深度学习 —— 个人学习笔记15(图像增广、微调)

声明 本文章为个人学习使用&#xff0c;版面观感若有不适请谅解&#xff0c;文中知识仅代表个人观点&#xff0c;若出现错误&#xff0c;欢迎各位批评指正。 三十、图像增广 import torch import time import torchvision from torch import nn from IPython import display …

node指令记录

查询当前镜像地址 npm config get registry替换镜像地址为阿里云 npm config set registry http://registry.npmmirror.com切换镜像地址为默认 npm config set registry https://registry.npmjs.org创建vue3 npm create vuelatest

k8s 部署RuoYi-Vue-Plus之minio搭建

1.直接部署一个pod 需要挂载存储款, 可参考 之前文章设置 https://blog.csdn.net/weimeibuqieryu/article/details/140183843 2.部署yaml 创建部署文件 minio-deploy.yaml apiVersion: v1 kind: PersistentVolume metadata:name: minio-pvnamespace: ruoyi #使用ns ruoyi s…

【网络安全】IDOR实现ATO(账户接管)

未经许可,不得转载。 文章目录 正文正文 目标站点:target.com,注册A账号和B账号。 A账号查看个人资料(包括用户名、密码)的请求包大致为: GET /api/v1/user/profile? user_id=273948261&auth_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWI iOiIxMjM0NTY3O…

【读取Kafka信息以及加密配置--Java】

文章目录 读取Kafka的某个topic&#xff0c;所有集群的IP都要写吗配置示例Java代码示例重要注意事项总结 SSL/TLS或SASL获取配置、设置配置1. 配置SSL/TLS获取配置设置配置Java代码示例 2. 配置SASL获取配置设置配置Java代码示例 3. 配置SSL/TLS和SASL联合使用获取配置设置配置…

【C++ 面试 - 基础题】每日 3 题(九)

✍个人博客&#xff1a;Pandaconda-CSDN博客 &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/fYaBd &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞&#x1f44d;收藏&…