功能
input输入框
autocomplete自动补齐输入框
radio 单选框
checkbox 复选框
date 日期选择框
select 下拉框
如需添加更多功能参考elementplus或者根据业务需求自行
自定义组件
效果图
目录结构
input
<template> <el-input v-bind="$attrs" v-model="modelvalue" w-full @blur="props.blur ? props.blur($event) : false" @focus="props.focus ? props.focus($event) : false" @change="props.change ? props.change($event) : false" @input="props.input ? props.input($event) : false" @clear="props.clear ? props.clear() : false" /> </template> <script lang="ts" setup> import { ref, watch } from "vue"; const emit = defineemits(["update:modelvalue"]); const props = defineprops({ modelvalue: { type: string, default: () => "", }, blur: { type: function, default: () => () => {}, }, focus: { type: function, default: () => () => {}, }, change: { type: function, default: () => () => {}, }, input: { type: function, default: () => () => {}, }, clear: { type: function, default: () => () => {}, }, }); const modelvalue = ref(props.modelvalue); //监听父组件的值 watch( () => props.modelvalue, () => { modelvalue.value = props.modelvalue; }, ); // 通过emit将值传递给父组件 emit("update:modelvalue", modelvalue); </script> <style lang="scss" scoped></style>
select
<template> <el-select v-model="modelvalue" v-bind="$attrs" w-full @change="props.change ? props.change($event) : false" @visible-change="props.visiblechange ? props.visiblechange($event) : false" @remove-tag="props.removetag ? props.removetag($event) : false" @clear="props.clear ? props.clear() : false" @blur="props.blur ? props.blur($event) : false" @focus="props.focus ? props.focus($event) : false" > <el-option v-for="item in options" :key="item[valuefiled]" :label="item[labelfiled]" :value="item[valuefiled]" ></el-option> </el-select> </template> <script lang="ts" setup> import { ref, watch } from "vue"; const emit = defineemits(["update:modelvalue"]); const props = defineprops({ modelvalue: { type: [string, array], default: () => "", }, options: { type: array as any, default: () => [], }, valuefiled: { type: string, default: "value", }, labelfiled: { type: string, default: "label", }, change: { type: function, default: () => () => {}, }, visiblechange: { type: function, default: () => () => {}, }, removetag: { type: function, default: () => () => {}, }, clear: { type: function, default: () => () => {}, }, blur: { type: function, default: () => () => {}, }, focus: { type: function, default: () => () => {}, }, }); const modelvalue = ref(props.modelvalue); //监听父组件的值 watch( () => props.modelvalue, () => { modelvalue.value = props.modelvalue; }, ); // 通过emit将值传递给父组件 emit("update:modelvalue", modelvalue); </script> <style lang="scss" scoped></style>
autocomplete
<template> <el-autocomplete v-bind="$attrs" v-model="modelvalue" style="width: 100%" @select="props.select ? props.select($event) : false" @change="props.change ? props.change($event) : false" /> </template> <script lang="ts" setup> import { ref, watch } from "vue"; const emit = defineemits(["update:modelvalue"]); const props = defineprops({ modelvalue: { type: string, default: () => "", }, select: { type: function, default: () => () => {}, }, change: { type: function, default: () => () => {}, }, }); const modelvalue = ref(props.modelvalue); //监听父组件的值 watch( () => props.modelvalue, () => { modelvalue.value = props.modelvalue; }, ); // 通过emit将值传递给父组件 emit("update:modelvalue", modelvalue); </script>
date
<template> <el-date-picker v-model="val" v-bind="$attrs" style="width: 100%" @change="props.change ? props.change($event) : false" @blur="props.blur ? props.blur($event) : false" @focus="props.focus ? props.focus($event) : false" @calendar-change="props.calendarchange ? props.calendarchange($event) : false" @panel-change="(a, b, c) => (props.panelchange ? props.panelchange(a, b, c) : false)" @visible-change="props.visiblechange ? props.visiblechange($event) : false" ></el-date-picker> </template> <script lang="ts" setup> import { ref, watch } from "vue"; const emit = defineemits(["update:modelvalue"]); const props = defineprops({ modelvalue: { type: [string, array, date], default: () => "", }, change: { type: function, default: () => () => {}, }, blur: { type: function, default: () => () => {}, }, focus: { type: function, default: () => () => {}, }, calendarchange: { type: function, default: () => () => {}, }, panelchange: { type: function, default: () => () => {}, }, visiblechange: { type: function, default: () => () => {}, }, }); const val = ref(props.modelvalue); //监听父组件的值 watch( () => props.modelvalue, () => { val.value = props.modelvalue; }, ); // 通过emit将值传递给父组件 emit("update:modelvalue", val); </script>
checkbox
<template> <el-checkbox-group v-model="val" v-bind="$attrs" @change="props.change ? props.change($event) : false" > <template v-if="props.ctype === 'button'"> <el-checkbox-button v-for="item in options" :key="item[valuefiled]" :value="item[valuefiled]" >{{ item[labelfiled] }}</el-checkbox-button > </template> <template v-else> <el-checkbox v-for="item in options" :key="item[valuefiled]" :value="item[valuefiled]" :border="props.ctype === 'border'" >{{ item[labelfiled] }}</el-checkbox > </template> </el-checkbox-group> </template> <script lang="ts" setup> import { ref, watch } from "vue"; const emit = defineemits(["update:modelvalue"]); const props = defineprops({ modelvalue: { type: array, default: () => "", }, options: { type: array as any, default: () => [], }, valuefiled: { type: string, default: "value", }, labelfiled: { type: string, default: "label", }, ctype: { type: string, default: "", }, change: { type: function, default: () => () => {}, }, }); const val = ref(props.modelvalue); //监听父组件的值 watch( () => props.modelvalue, () => { val.value = props.modelvalue; }, ); // 通过emit将值传递给父组件 emit("update:modelvalue", val); </script>
radio
<template> <el-radio-group v-model="modelvalue" v-bind="$attrs" @change="props.change ? props.change($event) : false" > <template v-if="props.ctype === 'button'"> <el-radio-button v-for="item in options" :key="item[valuefiled]" :value="item[valuefiled]">{{ item[labelfiled] }}</el-radio-button> </template> <template v-else> <el-radio v-for="item in options" :border="props.ctype === 'border'" :key="item[valuefiled]" :value="item[valuefiled]" >{{ item[labelfiled] }}</el-radio > </template> </el-radio-group> </template> <script lang="ts" setup> import { ref, watch } from "vue"; const emit = defineemits(["update:modelvalue"]); const props = defineprops({ modelvalue: { type: [number, string, boolean], default: () => "", }, options: { type: array as any, default: () => [], }, valuefiled: { type: string, default: "value", }, labelfiled: { type: string, default: "label", }, ctype: { //radio类型:button/border type: string, default: "", }, change: { type: function, default: () => () => {}, }, }); const modelvalue = ref(props.modelvalue); //监听父组件的值 watch( () => props.modelvalue, () => { modelvalue.value = props.modelvalue; }, ); // 通过emit将值传递给父组件 emit("update:modelvalue", modelvalue); </script>
cascader
<template> <el-cascader v-bind="$attrs" v-model="modelvalue" style="width: 100%" @change="props.change ? props.change($event) : false" @expand-change="props.expandchange ? props.expandchange($event) : false" /> </template> <script lang="ts" setup> import { ref, watch } from "vue"; const emit = defineemits(["update:modelvalue"]); const props = defineprops({ modelvalue: { type: array, default: () => [], }, change: { type: function, default: () => () => {}, }, expandchange: { type: function, default: () => () => {}, }, }); const modelvalue = ref(props.modelvalue); //监听父组件的值 watch( () => props.modelvalue, () => { modelvalue.value = props.modelvalue; }, ); // 通过emit将值传递给父组件 emit("update:modelvalue", modelvalue); </script>
types
/* * @author: vhen * @date: 2024-03-24 00:36:03 * @lastedittime: 2024-03-24 15:21:30 * @description: 现在的努力是为了小时候吹过的牛逼! * @filepath: \vhen-vue3-admin-pro\src\components\searchform\types.ts * */ export type formtype = "input" | "select" | "radio" | "cascader" | "autocomplete" | "date" | "daterange" | "checkbox"; export interface itemoption { label: string value: string | number disabled?: boolean } export interface formitemvo { type: formtype //输入框类型 label: string //输入框标题 disabled?: boolean//表单是否可修改 默认false placeholder?: any //输入框默认显示内容 prop: string //表单校验 options?: itemoption[] | (() => itemoption[]) //选择器的可选子选项 select span?: number // 表单栅格数 offset?: number // 表单栅格偏移 clearable?: boolean // 是否可清空 size?: string // 输入框大小 multiple?: boolean // 是否多选 collapsetags?: boolean // 是否折叠 collapsetagsthreshold?: number // 多选时标签的阈值,大于该阈值时折叠 filterable?: boolean // 是否可搜索 allowcreate?: boolean // 是否支持创建 radiotype?: string // 单选框类型 } export interface propsvo { formdata: object // 表单数据 formitem: formitemvo[] // 表单配置项 span?: number // 表单栅格数 isseniorsearch?: boolean // 是否高级搜索 gutter?: number // 表单栅格间隔 showbutton?: boolean // 是否显示查询按钮 }
index.vue
<template> <section class="search-form"> <el-form :model="props.formdata" v-bind="$attrs"> <el-row :gutter="props.gutter"> <el-col v-for="column in useformitem" :key="column.prop" :span="column.span" :offset="column.offset" > <el-form-item :label="`${column.label}`" :prop="column.prop"> <component :is="componenttype[column.type]" v-bind="column" v-model="props.formdata[column.prop]" /> </el-form-item> </el-col> <template v-if="$slots.default"> <slot /> </template> <el-col :span="props.span" style="flex: 1; max-width: 100%" v-if="showbutton"> <div flex justify="end" items-center w-full h-full> <div v-if="isseniorsearch" flex items-center mr-2 class="senior-search" @click="isshow = !isshow" cursor="pointer" > <div class="text">{{ isshow ? "收起" : "展开" }}</div> <div class="flex m-left-4"> <el-icon> <arrowup v-if="isshow" /> <arrowdown v-else /> </el-icon> </div> </div> <el-button @click="$emit('reset')" :icon="refreshleft">重置</el-button> <el-button type="primary" class="m-bottom-12" @click="$emit('search')" :icon="search" >查询</el-button > </div> </el-col> </el-row> </el-form> </section> </template> <script lang="ts" setup> import { refreshleft, search } from "@element-plus/icons-vue"; import { forminstance } from "element-plus"; import { computed, markraw, ref } from "vue"; import vhenautocomplete from "./src/vhenautocomplete.vue"; import vhencascader from "./src/vhencascader.vue"; import vhencheckbox from "./src/vhencheckbox.vue"; import vhendatepicker from "./src/vhendatepicker.vue"; import vheninput from "./src/vheninput.vue"; import vhenradio from "./src/vhenradio.vue"; import vhenselect from "./src/vhenselect.vue"; import { propsvo } from "./types"; const emit = defineemits<{ (e: "reset"): void; (e: "search"): void; }>(); const props = withdefaults(defineprops<propsvo>(), { isseniorsearch: false, gutter: 12, span: 8, showbutton: true, }); const isshow = ref(false); const useformitem = computed(() => { const isshowrow = props.isseniorsearch && !isshow.value && props.showbutton; if (isshowrow) { const num = math.floor(24 / props.span) - 1; return props.formitem.slice(0, num); } else { return props.formitem; } }); const componenttype = markraw({ input: vheninput, select: vhenselect, radio: vhenradio, cascader: vhencascader, autocomplete: vhenautocomplete, date: vhendatepicker, daterange: vhendatepicker, checkbox: vhencheckbox, }); const formref = ref<forminstance>(); defineexpose({ formref }); </script> <style lang="scss" scoped> .senior-search { color: var(--el-text-color-regular); .text { font-size: 14px; } } </style>
组件案例
<template> <div> <searchform :formdata="formdata" :form-item="formitemlist" :rules="formrules" :span="6" label-position="top" label-width="100px" isseniorsearch @reset="resetdata" @search="handlesearch" > </searchform> <pre> {{ formdata }} </pre> </div> </template> <script lang="ts" setup> import searchform from "@/components/searchform/index.vue"; import { formrules } from "element-plus"; import { reactive } from "vue"; const formdata = reactive({ username: "", email: "843348394@qq.com", sex: "1", area: [], city: "", }); const formitemlist = reactive([ { type: "input", label: "姓名", prop: "username", clearable: true, span: 6, placeholder: "请输入姓名", // disabled: true, input: handleinput, }, { type: "autocomplete", label: "邮箱", prop: "email", span: 6, "fetch-suggestions": querysearch, }, { type: "daterange", label: "出生日期", prop: "birthday", span: 6, }, { type: "radio", label: "-", prop: "sex", ctype: "button", span: 6, options: [ { value: "0", label: "男", }, { value: "1", label: "女", }, ], }, { type: "checkbox", label: "工作地点", prop: "area", span: 6, options: [ { label: "北京", value: "beijing", }, { label: "上海", value: "shanghai", }, { label: "深圳", value: "shenzhen", }, ], }, { type: "select", prop: "city", label: "城市", span: 6, options: [ { label: "北京", value: "beijing", }, { label: "上海", value: "shanghai", }, { label: "深圳", value: "shenzhen", }, ], }, ]); const resetdata = () => { console.log(formdata); }; const handlesearch = () => { console.log(formdata); }; const formrules = reactive<formrules>({ username: [{ required: true, message: "请输入姓名", trigger: "blur" }], email: [{ required: true, message: "请输入邮箱", trigger: "blur" }], }); function handleinput(val: string | number) { console.log(val); } function querysearch(query: string, cb: any) { console.log(query); cb([query]); } </script> <style lang="scss" scoped></style>
结束语
简单二次封装form 表单组件,如大家有更好的方案,欢迎大家评论区讨论,一起学习一起成长....
以上就是vue3+elementplus二次封装表单的实现代码的详细内容,更多关于vue3 elementplus二次封装表单的资料请关注代码网其它相关文章!
发表评论