首页 > 其他分享 >vue搜索表单封装

vue搜索表单封装

时间:2024-08-06 15:25:51浏览次数:7  
标签:vue const import formData 表单 props 封装 type

表单封装

封装基于Antd,如果使用其他组件库在types.ts替换, searchForm.vue更换form即可

searchForm.vue

<template>
  <view class="form">
    <view class="left">
      <a-form v-bind="props.formProps" :model="formData">
        <a-row>
          <a-col
            v-for="(item, index) in props.formOptions"
            :key="index"
            :span="item.span"
          >
            <a-form-item :label="item.label" :name="item.dataIndex">
              <view :style="{ ...item.style }">
                <template v-if="item.type !== 'Slot'">
                  <formItem
                    :type="item.type"
                    :comProps="item.comProps"
                    v-model="formData[item.dataIndex]"
                  />
                </template>
                <template v-else>
                  <slot
                    :name="item.dataIndex"
                    :formData="formData"
                    :item="item"
                  ></slot>
                </template>
              </view>
            </a-form-item>
          </a-col>
        </a-row>
      </a-form>
    </view>
    <view class="right">
      <view class="btn-view">
        <a-button v-if="props.queryCallback" type="primary" @click="query">
          搜索
        </a-button>
        <a-button v-if="props.resetCallback" @click="reset" class="cancel-btn">
          重置
        </a-button>
      </view>
      <slot name="underRight"></slot>
    </view>
  </view>
</template>

<script lang="ts">
import { defineComponent, ref, watch, PropType } from 'vue'
import { FormOption } from './types'
import formItem from './formItem.vue'
import CityCascader from '@/components/CityCascader/index.vue'

export default defineComponent({
  props: {
    formProps: {
      type: Object,
      default: {},
    }, // 透传表单属性
    modelValue: {
      type: Object as () => any,
      required: true,
    }, // 双向绑定表单数据, 通过 v-model="" 传递
    formOptions: {
      type: Array as PropType<FormOption[]>,
      required: true,
    }, // form 选项
    queryCallback: {
      type: Function,
    },
    resetCallback: {
      type: Function,
    },
    /* 插槽
      underRight 为按钮下方插槽
      formOptions type 为 Slot 时为具名插槽,携带 formData 和 item
    */
  },
  components: { formItem, CityCascader },
  setup(props, { emit }) {
    const formData = ref({ ...props.modelValue })
    const isOutsideChange = ref<boolean>(false)
    // 双向绑定
    watch(
      formData,
      (newData) => {
        if (isOutsideChange.value) {
          return (isOutsideChange.value = false)
        }
        updataValue(newData)
      },
      { deep: true },
    )
    watch(
      () => props.modelValue,
      (newVal) => {
        formData.value = newVal
        isOutsideChange.value = true
      },
    )
    const updataValue = (data?: any) => {
      emit('update:modelValue', data || {})
    }
    const query = () => {
      props.queryCallback && props.queryCallback(formData.value)
    }
    const reset = () => {
      updataValue()
      props.resetCallback && props.resetCallback()
    }

    return { props, formData, query, reset }
  },
})
</script>

<style lang="scss" scoped>
.form {
  display: flex;
  width: 100%;
  background-color: white;
  padding: 15px;
  box-sizing: border-box;
  .left {
    display: block;
    width: calc(100% - 160px);
  }
  .right {
    display: block;
    width: 160px;
    .btn-view {
      width: 100%;
      display: flex;
      justify-content: flex-end;
    }
  }
}
</style>

formItem.vue

<template>
  <component :is="com" v-model:value="data" v-bind="props.comProps" />
</template>

<script lang="ts">
import { defineComponent, computed, PropType, ref, watch } from 'vue'
import { components, ComponentsType } from './types'

export default defineComponent({
  props: {
    type: {
      type: String as PropType<ComponentsType>,
      required: true,
    },
    comProps: {
      type: Object,
      default: {},
    },
    modelValue: {
      type: Object as () => any,
      required: true,
    }, // 双向绑定表单数据
  },
  setup(props, { emit }) {
    const data = ref<any>(props.modelValue)
    const isOutsideChange = ref<boolean>(false)
    // 双向绑定
    watch(
      data,
      (newData) => {
        if (isOutsideChange.value) {
          return (isOutsideChange.value = false)
        }
        updataValue(newData)
      },
      { deep: true },
    )
    watch(
      () => props.modelValue,
      (newVal) => {
        data.value = newVal
        isOutsideChange.value = true
      },
    )
    const com = computed(() => {
      return components[props.type] || null
    })

    const updataValue = (data?: any) => {
      emit('update:modelValue', data || {})
    }

    return { props, com, data }
  },
})
</script>

<style lang="scss" scoped></style>

types.ts

import {
  Input,
  Checkbox,
  CheckboxGroup,
  DatePicker,
  Radio,
  Select,
  InputNumber,
  Rate,
  Switch,
  Slider,
} from 'ant-design-vue'

export const components = {
  Input,
  Checkbox,
  CheckboxGroup,
  DatePicker,
  Radio,
  Select,
  InputNumber,
  Rate,
  Switch,
  Slider,
  Slot: 'Slot', // 插槽
} as const
export type ComponentsType = keyof typeof components

// formOptions 的类型
export interface FormOption {
  label?: string // 文本
  type: ComponentsType // 类型
  dataIndex: string // 数据索引,插槽时为插槽的名称
  comProps?: object // 组件透传属性
  span: number // 栅格布局宽度
  style?: object // 样式
}

使用案例

<template>
  <searchForm
    v-model="formData"
    :formOptions="formOptions"
    :queryCallback="queryCallback"
    :resetCallback="resetCallback"
  >
    <template #otherInfo="{ formData, item }">
      {{ formData.cardCatalogName }}
    </template>
  </searchForm>
</template>

<script lang="ts">
import { defineComponent, ref } from 'vue'
import searchForm from '@/components/Form/searchForm.vue'
import { FormOption } from '@/components/Form/types'
import { cardType } from './options'

export default defineComponent({
  components: { searchForm },
  setup() {
    const formData = ref()
    const formOptions: FormOption[] = [
      {
        label: '会员卡名称',
        type: 'Input',
        dataIndex: 'cardCatalogName',
        comProps: { autocomplete: 'off', allowClear: true, maxlength: 20 },
        span: 7,
      },
      {
        label: '会员卡类别',
        type: 'CheckboxGroup',
        dataIndex: 'cardTypes',
        comProps: { options: cardType },
        span: 13,
      },
      {
        type: 'Slot',
        dataIndex: 'otherInfo',
        span: 6,
      },
    ]

    const queryCallback = (res: object) => {
      console.log(res)
    }
    const resetCallback = () => {}

    return { formData, formOptions, queryCallback, resetCallback }
  },
})
</script>

标签:vue,const,import,formData,表单,props,封装,type
From: https://blog.csdn.net/JoveTAT/article/details/140954318

相关文章

  • 【C++/STL】map和set的封装(红黑树)
     ......
  • springboot+vue农产品在线管理系统【程序+论文+开题】-计算机毕业设计
    系统程序文件列表开题报告内容研究背景随着信息技术的飞速发展和互联网的普及,电子商务已成为推动各行各业转型升级的重要力量。在农业领域,传统农产品销售模式面临着信息不对称、流通环节多、成本高企等挑战,严重制约了农产品的市场竞争力与农民的收入增长。因此,构建一个高效......
  • springboot+vue农产品销售与管理系统【程序+论文+开题】-计算机毕业设计
    系统程序文件列表开题报告内容进度安研究背景随着信息技术的飞速发展和农业现代化进程的加快,农产品销售与管理模式正经历着深刻的变革。传统农产品销售链条长、信息不对称、流通效率低等问题日益凸显,严重制约了农业产业的升级与农民收入的增加。特别是在“互联网+”背景......
  • springboot+vue农产品托管系统【程序+论文+开题】-计算机毕业设计
    系统程序文件列表开题报告内容研究背景随着现代农业的快速发展,农产品生产与管理的复杂性和专业性日益增强,传统的农业经营模式已难以满足现代农业高效、精准、信息化的需求。特别是在农产品生产、农机服务及农产品收购等关键环节,信息不对称、资源配置不合理、效率低下等问题......
  • springboot+vue农产品供销服务系统【程序+论文+开题】-计算机毕业设计
    系统程序文件列表开题报告内容研究背景随着农业现代化的不断推进和互联网技术的广泛应用,农产品市场正经历着前所未有的变革。传统农产品供销模式存在信息不对称、流通环节多、效率低下等问题,严重制约了农业经济的发展和农民收入的提升。当前,消费者对农产品品质、安全及购买......
  • uniapp中的websocket的研究,以及相关的封装
    官方文档---官方文档写的跟屎一样https://uniapp.dcloud.net.cn/api/request/websocket.html相关博客https://www.cnblogs.com/sunnyeve/p/16757633.html还是这个博客清晰https://blog.csdn.net/lyandgh/article/details/100642941......
  • 计算机毕业设计django+vue出租车服务管理信息系统【开题+论文+程序】
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着城市化进程的加速和共享经济的兴起,出租车服务行业正经历着前所未有的变革。传统出租车行业面临着调度效率低下、乘客体验不佳、车辆管......
  • 计算机毕业设计django+vue校园网络跳蚤市场系统的设计与应用【开题+论文+程序】
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着高等教育的普及和校园生活的丰富多彩,学生们在日常学习和生活中积累了大量的二手物品,如书籍、电子产品、生活用品等。这些物品往往因为......
  • 计算机毕业设计django+vue宠物销售系统【开题+论文+程序】
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着宠物市场的持续繁荣,宠物销售行业迎来了前所未有的发展机遇。然而,传统的宠物销售方式往往受限于地域、信息不对称以及管理效率低下等问......
  • 计算机毕业设计django+vue德林超市连锁超市触屏收银系统设计与实现【开题+论文+程序】
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着信息技术的飞速发展,零售业正经历着前所未有的变革。传统超市在面对电商冲击和消费者需求日益多样化的背景下,亟需通过技术创新提升服务......