Vue3中搜索表单的二次封装

最近使用Vue3+ElementPlus开发项目,从整体上构思组件的封装。能写成组件的内容都进行封装,方便多个地方使用。

受AntDesign的启发,在项目中有搜索表单+table+分页的地方可以封装为一个组件,只需要对组件传入table的列,组成一个配置项,通过配置可以显示搜索表单、table项的内容展示等等。

那么在使用ElemenPlus开发时,是没有这样的组件可以使用的。又一想项目中好多个地方都有搜索表单+Table的形式,那不如直接封装个搜索表单,这样就省去了一遍一遍的表单的重复编写。封装好的组件只需要传入进入配置内容即可实现搜索的效果。

实现思路:

  1. 搜索表单无非就是文本框、选择框、时间选择、时间范围选择、数字框,通过配置项里传入type即可判断展示哪种类型的form-item。
  2. 数值绑定,v-model与传入项的匹配,在配置项中传入prop,然后在子组件中创建form响应式对象。
  3. 数据初始值、选项列表等等都通过配置项传入。
  4. 搜索表单的搜索与重置按钮,提交emit事件即可。

首先:创建SearchForm.vue组件

该组件实现了输入框、选择框、单日期、双日期(一般搜索表单也就这些,如果还有其他的类型,读者可以自己添加)。

javascript 复制代码
<script setup>
    import { reactive, onMounted } from "vue"
    import DateRangePicker from '@/components/DateRangePicker/index.vue'

    const props = defineProps({
        itemList: Array
    })
    const emit = defineEmits(['search', 'reset'])
    
    let form = reactive({})
    onMounted(() => {
      props.itemList.map(item => {
        if(item.type === 'dateRange') {
            form[item.start] = ''
            form[item.end] = ''
        }else {
            form[item.prop] = item.initValue ? item.initValue : ''
        }
      })
    })
</script>

<template>
    <el-form :model="form" inline label-width="120px">
        <template v-for="(item, index) in props.itemList" :key="index">
            <el-form-item
                :label="item.label"
                :prop="item.prop"
            >
                <el-select v-if="item.type === 'select'" v-model="form[item.prop]" placeholder="请选择" clearable>
                  <el-option v-for="i in item.list" :key="i.value" :label="i.label" :value="i.value"/>
                </el-select>
                <el-date-picker 
                    v-if="item.type === 'date'" 
                    :type="item.dateType" 
                    v-model="form[item.prop]" 
                    placeholder="请选择" 
                    clearable
                />
                <date-range-picker
                    v-if="item.type === 'dateRange'"
                    v-model:start="form[item.start]"
                    v-model:end="form[item.end]"
                />
                <el-input-number v-if="item.type === 'number'" v-model="form[item.prop]" placeholder="请输入" clearable/>
                <el-input v-if="item.type === 'input'" v-model="form[item.prop]" placeholder="请输入" clearable/>
            </el-form-item>
        </template>
        <el-form-item>
            <el-button @click="emit('search', form)" type="primary" icon="Search">查询</el-button>
            <el-button @click="emit('reset')" type="primary" plain icon="Refresh">重置</el-button>
        </el-form-item>
    </el-form>
</template>

其次:DateRangePicker组件

这个组件是用来实现选择范围日期的,因为范围日期返回的是一个数组,如果不进行封装处理一下的话,在项目中每写一个该组件都会要写change事件来处理数据值,还挺麻烦。封装之后,只需要将对应的model传给该组件即可实现双向绑定。

javascript 复制代码
<script setup>
import { ref } from "vue";
const emit = defineEmits(['update:start', 'update:end'])
const props = defineProps({
    start: {
        type: String,
        required: true
    },
    end: {
        type: String,
        required: true
    },
    type: {
        default: 'daterange'  // daterange、datetimerange、monthrange
    },
    format: {
        default: 'YYYY-MM-DD'
    },
    valueFormat: {
        default: 'YYYY-MM-DD HH:mm:ss'
    }
})
let dateRange = ref([])

const dateChange = (e) => {
    emit('update:start', e ? e[0] : '')
    emit('update:end', e ? e[1] : '')
}
</script>

<template>
    <el-date-picker 
        v-model="dateRange"
        :type="props.type"
        :format="props.format"
        :value-format="props.valueFormat"
        start-placeholder="开始日期"
        end-placeholder="结束日期"
        @change="dateChange"
    />
</template>

最后一步:使用SearchForm组件

经过前两步的封装之后,在使用的SearchForm组件时,简直是爽的不要不要的。看示例:

javascript 复制代码
<script setup>
  import { reactive, ref } from 'vue'
  import SearchForm from '@/components/SearchForm/index.vue'
  import ProListItem from '@/views/project/components/ProListItem.vue'
  import { projectList } from '@/api/project';
  const searchFormList = [
    {label: '项目名称', prop: 'name', type: 'input'},
    {label: '项目编码', prop: 'code', type: 'input'},
    {label: '项目描述', prop: 'desc', type: 'select', list: [{label: '未开始', value: 1}, {label: '已开始', value: 2}]},
    {label: '创建日期', type: 'dateRange', start: 'startTime', end: 'endTime'}
  ]
  const dataSource = ref([])
  const queryForm = ref()
  const pagination = reactive({
    pageNum: 1,
    pageSize: 10,
    total: 0
  })
  const search = (form) => {
    console.log(form);
    queryForm.value = form
    queryProject()
  }
  const queryProject = () => {
    projectList({
      ...queryForm.value,
      pageNum: pagination.pageNum,
      pageSize: pagination.pageSize
    }).then((result) => {
      dataSource.value = result.data.list
      data.total = result.data.total
    }).catch((err) => {
      
    });
  }
</script>
<template>
  <search-form 
    :item-list="searchFormList"
    @search="search"
    />
  <pro-list-item :data="dataSource"/>
</template>

啥也不说了,直接看示例,用起来多方便!!!只要项目中有要写搜索表单的地方,直接引入SearchForm组件,配置一下itemList即可实现完整功能!学会了的小伙伴赶紧去用起来吧。

相关推荐
桃园码工几秒前
15_HTML5 表单属性 --[HTML5 API 学习之旅]
前端·html5·表单属性
百万蹄蹄向前冲41 分钟前
2024不一样的VUE3期末考查
前端·javascript·程序员
轻口味1 小时前
【每日学点鸿蒙知识】AVCodec、SmartPerf工具、web组件加载、监听键盘的显示隐藏、Asset Store Kit
前端·华为·harmonyos
alikami1 小时前
【若依】用 post 请求传 json 格式的数据下载文件
前端·javascript·json
wakangda2 小时前
React Native 集成原生Android功能
javascript·react native·react.js
吃杠碰小鸡2 小时前
lodash常用函数
前端·javascript
emoji1111112 小时前
前端对页面数据进行缓存
开发语言·前端·javascript
泰伦闲鱼2 小时前
nestjs:GET REQUEST 缓存问题
服务器·前端·缓存·node.js·nestjs
m0_748250032 小时前
Web 第一次作业 初探html 使用VSCode工具开发
前端·html
一个处女座的程序猿O(∩_∩)O2 小时前
vue3 如何使用 mounted
前端·javascript·vue.js