vue3+element-plus 封装高度搜索组件,支持多种类型

news2024/11/18 20:45:35

目录

一、应用场景

二、开发流程

三、详细开发流程

1.新建文件

2.开始步骤

3.详细代码

(1).index.vue

(2).搜索组件

(3).单个搜索组件

总结


一、应用场景

一般很多网站,有很多数据列表,基本都要做搜索的功能,如果涉及很多页面,很多列表,那么搜索组件,一般要求统一样式之类的,并且封装搜索组件主要目的是提高代码的可维护性、可复用性和可扩展性,毕竟系统越写越多,列表页越来越多,不得不封装了,比如你看我这参与的项目,就从一开始的十几个页面,变成现在路由表快1000行的大项目,引用搜索组件的地方也高达:

问癌,它说,封装搜索组件的意义:

  1. 代码复用性: 封装搜索组件允许你在多个页面或组件中重复使用相同的搜索功能。这减少了代码的冗余,提高了开发效率。

  2. 可维护性: 通过将搜索功能封装到一个独立的组件中,可以更容易地维护和更新搜索逻辑。如果需要对搜索功能进行修改或添加新的功能,你只需要更新搜索组件而不必修改每个使用它的页面或组件。

  3. 可扩展性: 封装的搜索组件通常可以轻松扩展以支持不同类型的搜索字段或过滤条件。这使得在不同页面或应用中实现不同的搜索需求变得更加容易。

  4. 统一风格和用户体验: 通过使用相同的搜索组件,你可以确保整个应用的搜索界面保持一致的风格和用户体验,提高了应用的整体质量。

  5. 降低开发成本: 封装搜索组件可以节省开发时间和开发资源。开发人员可以专注于构建具体的业务逻辑而不必重复编写搜索功能。

  6. 易于测试: 独立的搜索组件可以更容易地进行单元测试,确保搜索功能的稳定性和正确性。

  7. 降低错误率: 通过减少手动编码搜索功能的机会,封装搜索组件有助于减少潜在的错误和bug。


二、开发流程

首先要明白,封装搜索组件,组件里都有什么,我这里封装的组件支持:

1.输入框

2.单选/多选/多选搜索/多选的远程搜索

3.时间选择器

通过form表单进行上面的封装

如下:

实现的效果,大概如此:

因为要考虑布局,所以使用的是col来控制布局,基本上一行放3个搜索框,加一组按钮,按钮有常见的查询,重置,折叠/展开,以及最右侧的业务按钮,比如:导出

上面的例子里,有几种类型(下面详细流程里有大图):

1.医生信息:el-input 输入框

2.所属医院:多选,带搜索和远程搜索(是否可以搜索、可以远程搜索、远程搜索的接口、传参、选项列表、选项的配置、是否能全选等自定义功能

3.患者id:输入框

4.患者状态:多选(单选、可清空)

5.创建时间:日期时间选择器 (显示默认时间:默认是最近7天、时间选择范围:如不能超过180天、在此日期之前的时间禁止选中)

接下来的开发过程都是以上面的图片为例子实现。 


三、详细开发流程

这里根据上面的例子封装一个搜索组件:

1.新建文件

(1)index.vue  需要引用搜索组件的页面

(2)src\components\searchOptionsBox.vue  这是外层的表单

(3)src\components\searchOptionItem.vue  这是单个组件的文件

2.开始步骤

先建一个空页面,随便写点东西,index.vue 里作为需要引入搜索组件的地方,先引入:

import SearchOptionsBox from '@/components/searchOptionsBox.vue'


页面
<el-row>
    <SearchOptionsBox  />
</el-row>

先考虑父组件,通常都是在父组件写查数据的操作,那么就需要拿到搜索的值,①输入文字,点击搜索后,进行查询,②点击重置,这些搜索的值都是空的,③再输入值,再搜索,那么再次搜索。

所以,父组件基本上,就需要给搜索组件传一些组件的配置和获取搜索的值的操作,至于其他的控制搜索组件的一些配置,那就另外加。

基础的是这些:

<SearchOptionsBox :search-options="searchOptions" @search="searchData" />

特殊的配置如下:

<SearchOptionsBox
          :search-options="searchOptions"
          :show-button="true"
          :btn-loading="btnLoading"
          button-name="导出"
          :buttons-span="7"
          @search="searchData"
        />

 这些特殊的配置,分别是控制,是否显示按钮组最右边的按钮,以及按钮的名字,按钮组占据的宽度比例

3.详细代码

(1).index.vue

const searchOptions = ref([
  {
    label: '医生信息',
    prop: 'doctor_info',
    inputType: 'String',
    optionType: 'input',
    placeHolder: '请输入医生信息'
  },
  {
    label: '所属医院',
    prop: 'hospital_id', //传array
    inputType: 'Array',
    optionType: 'select',
    multiple: true,
    isRemote: true, //远程搜索
    remoteSelectUrl: '/hospital-list',
    remoteParams: {
      disease_id: '...'
    },
    placeHolder: '请搜索或选择',
    selectOptions: [],
    selectLabel: 'center_name',
    selectValue: 'center_id'
  },
  {
    label: '患者id',
    prop: 'patient_id',
    inputType: 'String',
    optionType: 'input',
    placeHolder: '请输入患者id'
  },
  {
    label: '患者状态',
    prop: 'patient_status',
    inputType: 'Array',

    optionType: 'select',
    multiple: true,
    placeHolder: '请选择患者状态',
    selectOptions: [
      { label: '住院', value: 1 },
      { label: '出院', value: 2 },
      { label: '其他', value: 3 }
    ]
  },
  {
    label: '创建时间',
    prop: 'create_at',
    inputType: 'Array',
    optionType: 'datePicker',
    placeHolder: ''
  }
])



let searchParams = reactive({})
const searchData = (searchForm) => {
  params.page = 1
  searchParams = JSON.parse(JSON.stringify(searchForm))  ///深拷贝
  if (searchForm.patient_status) {   //如果是get请求,为了业务就数组转存为string了
    searchParams.patient_status = JSON.stringify(searchParams.patient_status)
  }
  
  getDataList() //获取数据,searchParams是搜索的值
}

//在获取数据时,把传参拼接一下
//let tempParams = { ...params, ...searchParams }

这个页面,主要定义一些搜索组件的配置,和搜索时的参数处理。

弊端是:会出现一些不必要的参数,比如一些没有值的参数也会传,当然可以清掉。

如果有导出功能,那么需要按照上面的特殊配置进行,同时,获取数据时,需要另外处理,如下:

let searchParams = ref({})
const searchData = (searchForm, download) => {
  params.page = 1
  searchParams.value = JSON.parse(JSON.stringify(searchForm))
  //post 接口可以直接传array,不用再次处理
  if (!download) {
    download = 0//或者false,这里我是以1代表true
    isSearch.value = true
  } else {
    isDownload.value = true
  }
//获取数据时
}

 这里是详细的数据。

还有一个注意点,如果搜索组件的配置,有些比如多选组件,那么它的列表需要调接口才能拿到,要控制好页面加载的生命周期,一定要拿到数据再去加载搜索组件。

(2).搜索组件

首先,因为我懒得布局,所以就借用的form和col的布局方式,外层一个表单,每一个组件就是一个item,然后一个组件在col里用24布局,默认一个占6的大小,当然个别的可以调整,只要一行最大24就行,如此,一行也就能放3个组件一个按钮组,那么肯定要考虑折叠展开的逻辑,所以会有第二行,第三行,不过我的业务不涉及第三行,一般就两行。布局就大概这样。

这个页面详细的代码如下:

<template>
  <div class="search-component">
    <el-form ref="searchFormRef" :inline="true" :model="searchForm" class="demo-form-inline" label-position="left">
      <!-- 一行分为四部分,可以换行,控制折叠的选项 -->
      <el-row class="first-row">
        <el-col
          :span="option.span ? option.span : option.optionType == 'input' ? 6 : option.optionType == 'select' ? 5 : 7"
          v-for="(option, index) in firstFormOptions.splice(0, 3)"
          :key="index"
        >
          <el-form-item :label="option.label" :prop="option.prop" style="width: 100%; margin-right: 10px">
            <SearchOptionItem
              :placeHolder="option.placeHolder"
              :prop="option.prop"
              :inputType="option.inputType"
              :optionType="option.optionType"
              :isDefaultTime="option.isDefaultTime"
              :timeRangeDays="option.timeRangeDays"
              :disabledTime="option.disabledTime"
              :multiple="option.multiple"
              :disabled="option.disabled"
              :isRemote="option.isRemote"
              :remoteSelectUrl="option.remoteSelectUrl"
              :remoteParams="option.remoteParams"
              :searchField="option.searchField"
              :ifParamsChange="option.ifParamsChange"
              :nowRemoteParams="props.nowRemoteParams"
              :selectOptions="option.selectOptions"
              :selectAll="option.selectAll"
              :selectLabel="option.selectLabel"
              :selectValue="option.selectValue"
              :value="searchForm[option.prop]"
              @returnValue="getValue"
              style="margin-right: 10px"
            />
          </el-form-item>
        </el-col>

        <el-col :span="searchOptions.length == 2 ? 12 : props.buttonsSpan">
          <el-form-item style="width: 100%">
            <div class="button-container">
              <div>
                <el-button class="ml-1" type="primary" :icon="Search" @click="search">查询</el-button>
                <el-button @click="resetForm(searchFormRef)">重置</el-button>
                <el-button v-if="searchOptions.length > 3 && !isExpanded" link type="primary" @click="toggle">
                  展开&nbsp;
                  <el-icon><ArrowDownBold /></el-icon>
                </el-button>
                <el-button v-else-if="searchOptions.length > 3" link type="primary" @click="toggle">
                  收起&nbsp;
                  <el-icon><ArrowUpBold /></el-icon>
                </el-button>
              </div>

              <el-button v-if="showButton" :loading="btnLoading" @click="clickButton" type="primary">
                {{ buttonName }}
              </el-button>
            </div>
          </el-form-item>
        </el-col>
      </el-row>
      <el-row v-if="isExpanded && searchOptions.length > 3" class="second-row">
        <el-col
          :span="option.span || option.optionType == 'input' ? 6 : option.optionType == 'select' ? 5 : 7"
          v-for="(option, index) in secondFormOptions"
          :key="index"
        >
          <el-form-item :label="option.label" :prop="option.prop" style="width: 100%">
            <SearchOptionItem
              :placeHolder="option.placeHolder"
              :prop="option.prop"
              :inputType="option.inputType"
              :optionType="option.optionType"
              :isDefaultTime="option.isDefaultTime"
              :timeRangeDays="option.timeRangeDays"
              :disabledTime="option.disabledTime"
              :multiple="option.multiple"
              :disabled="option.disabled"
              :isRemote="option.isRemote"
              :remoteSelectUrl="option.remoteSelectUrl"
              :remoteParams="option.remoteParams"
              :searchField="option.searchField"
              :ifParamsChange="option.ifParamsChange"
              :nowRemoteParams="props.nowRemoteParams"
              :selectOptions="option.selectOptions"
              :selectAll="option.selectAll"
              :selectLabel="option.selectLabel"
              :selectValue="option.selectValue"
              :value="searchForm[option.prop]"
              @returnValue="getValue"
              style="margin-right: 10px"
            />
          </el-form-item>
        </el-col>
      </el-row>
    </el-form>
  </div>
</template>

模块代码中,没有复杂的逻辑,都是给SearchOptionItem传一些数据的。

主要是SearchOptionItem需要的数据结构,都需要什么配置,需要在这个页面都传过去,就如上面index.vue里配置的那样。

js部分如下:


<script setup>
import { ref, reactive, watch, computed, onMounted, defineProps, defineEmits } from 'vue'
import { Search } from '@element-plus/icons-vue'
import SearchOptionItem from './searchOptionItem.vue'
import { getFormattedTime } from '@/utils/validate'

//changeRemoteParams  用于更新远程搜索的字段
const emit = defineEmits(['search', 'changeRemoteParams'])
const props = defineProps({
  searchOptions: {
    default: [
      {
        label: '搜索',
        prop: 'search',
        inputType: 'String',
        optionType: 'input',
        placeHolder: '请输入关键字'
      },
      {
        label: '中心名称',
        prop: 'center_name',
        inputType: 'Array',//组件绑定值的类型
        optionType: 'select', //组件类型
        multiple: true, //是否多选
        span: 6, // 占据宽度
        isRemote: true,
        remoteSelectUrl: '', //远程搜索的接口
        remoteParams: {
          search: '',  
          disease_id: ''  //接口传参
        },
        disabled: false,
        searchField: '', //搜索时传的字段名
        placeHolder: '请选择中心',
        selectLabel: 'center_name',  //option的Label
        selectValue: 'center_id',
        selectAll: false,  //是否能全选,自定义的功能
        selectOptions: [  //搜索选项
          { label: '筛选中', value: 1 },
          { label: '在组', value: 2 },
          { label: '已出组', value: 3 }
        ]
      },
      {
        label: '时间范围',
        prop: 'create_at',
        inputType: 'Array',
        optionType: 'datePicker',
        placeHolder: '',
        isDefaultTime: true, //显示默认时间,默认是最近7天
        timeRangeDays: 180, //时间选择范围,不能超过180天
        disabledTime: '2023-06-20' //在此日期之前的时间禁止选中
      }
    ],
    type: Array
  },
  showButton: {
    default: false,
    type: Boolean
  },
  btnLoading: {
    default: true,
    type: Boolean
  },
  buttonName: { default: '导出', type: String },
  labelPosition: {
    default: 'right',
    type: String
  },
  //新参数
  nowRemoteParams: {  // 远程搜索的新参数,适配不同业务需要
    default: null,
    type: Object
  },
  //按钮组占据的宽度
  buttonsSpan: {
    default: 6,
    type: Number
  },
  // 用于初始化搜索框的值
  searchFormValue: {
    default: null,
    type: Object
  }
})

const isExpanded = ref(false)
//搜索选项form数据
const searchForm = ref({})
const firstFormOptions = ref([]) //第一行选项框
const secondFormOptions = ref([]) //折叠的选项框

onMounted(() => {
  //初始化搜索选项的值
  props.searchFormValue ? (searchForm.value = props.searchFormValue) : ''

  //根据数组的长度,判断显示的字段,前三个和后面折叠的多个
  firstFormOptions.value = JSON.parse(JSON.stringify(props.searchOptions)).splice(0, 3) || props.searchOptions
  secondFormOptions.value = JSON.parse(JSON.stringify(props.searchOptions)).splice(3) || props.searchOptions
})

const searchFormRef = ref(null)
const timeRanges = ref([])

//处理数据
const getValue = (value, prop, optionType, ifParamsChange) => {
  //删除没有数据的选项字段
  if (optionType == 'datePicker') {  //时间选择器,这里的数据处理是根据业务需求写的
    if (value === null) {
      deleteDate()
    } else {
      searchForm.value.start_time = getFormattedTime(value[0]) //格式化时间
      searchForm.value.end_time = getFormattedTime(value[1])
    }
  } else if (!value && value !== 0) {  //如果数据为空就删掉这个属性
    delete searchForm.value[prop]
  } else {
    searchForm.value[prop] = value
  }
  if (ifParamsChange) { //如果数据改变了,就更新一下index.vue里的值
    emit('changeRemoteParams', searchForm.value[prop])
  }
}



const search = (download) => {
  emit('search', searchForm.value, 0)
}

const clickButton = () => {
  emit('search', searchForm.value, 1)
}

const resetForm = (formEl) => {
  searchForm.value = {}
  deleteDate()
}

const deleteDate = () => {
  delete searchForm.value.start_time
  delete searchForm.value.end_time
  //清空项目名称的值,找到为时间选择器的值,全部清空
  props.searchOptions.forEach((item) => {
    if (item.optionType == 'datePicker') {
      searchForm.value[item.prop] = []
    }
  })
}
const toggle = () => {
  isExpanded.value = !isExpanded.value
}
</script>

具体的逻辑都在上面,有注释,大部分是跟业务有关的 

下面是我自定的样式,可以跳过。

.search-component {
  width: 100%;
  .el-form--inline .el-form-item {
    margin-right: 10px;
  }
  :deep(.el-form-item__label) {
    font-weight: bold !important;
  }
  .first-row {
    display: flex;
    flex-direction: row;
    flex-wrap: nowrap;
    .el-col {
      height: 32px !important;
    }
  }
  .second-row {
    display: flex;
    flex-direction: row;
    flex-wrap: nowrap;
    margin-top: 10px;
    .el-col {
      height: 32px !important;
    }
  }

  .option-container {
    width: 25%;
  }
  .button-container {
    width: 100%;
    display: flex;
    justify-content: space-between;
  }

  .el-button + .el-button {
    margin-left: 10px;
  }
}

.select-item {
  .el-select .el-select-tags-wrapper.has-prefix {
    display: flex;
    max-width: 70% !important; //设置最大宽度 超出显示...
    flex-wrap: nowrap;
  }
  .el-tag.is-closable {
    // width: 45%;
    // max-width: 70px;
  }
  .el-select__tags .el-tag:last-child {
    // width: 45%;
    // max-width: 70px;
  }
  .el-tag__content {
    width: 100%;
  }
  .el-select .el-select__tags-text {
    max-width: 45px !important; //设置最大宽度 超出显示...
    display: inline-block;
    overflow: hidden;
    vertical-align: bottom;
    text-overflow: ellipsis;
  }
  .el-select__input {
    margin-left: 5px;
  }
}

</style>

(3).单个搜索组件

 页面是三个判断,就根据不同的类型,进行不同的配置,现在页面的类型还比较少,还不卡,后面越来越多,可能不友好吧。

<template>
  <div class="item-container">
    <div v-if="optionType == 'input'" class="input-item">
      <el-input v-model="inputValue" :placeholder="placeHolder" clearable @change="returnValue" @clear="returnValue" />
    </div>
    <div v-if="optionType == 'datePicker'" class="date-picker-item">
      <el-date-picker
        v-model="timeRange"
        type="datetimerange"
        :shortcuts="shortcuts"
        :disabled-date="disabledDate"
        :default-time="defaultTime"
        placeholder="请选择日期"
        format="YYYY-MM-DD HH:mm:ss"
        range-separator="至"
        start-placeholder="开始日期"
        end-placeholder="结束日期"
        @change="chooseData"
        @clear="chooseData"
        style="width: 100%"
      />
    </div>
    <div v-if="optionType == 'select'" class="select-item">
      <el-select
        v-model="inputValue"
        :placeholder="placeHolder"
        style="width: 100%"
        clearable
        :filterable="isRemote"
        :remote="isRemote"
        :remote-method="selectRemoteMethod"
        :loading="selectLoading"
        :multiple="multiple"
        :collapse-tags="multiple"
        :disabled="disabled"
        @clear="returnValue"
        @change="returnValue"
        @visible-change="openChange"
      >
        <el-option v-if="selectAll" key="all" label="全选" value="all" />
        <el-option
          v-for="item in newSelectOptions"
          :key="item[props.selectValue]"
          :label="item[props.selectLabel]"
          :value="item[props.selectValue]"
        />
      </el-select>
    </div>
  </div>
</template>

这里面绑定的值,value是从上个页面传来的,因为不能改,所以用新的值代替了。

 

<script setup>
import { ref, reactive, computed, onMounted, defineProps, defineEmits } from 'vue'
import { ElMessage } from 'element-plus'

const emit = defineEmits(['returnValue'])
const props = defineProps({
  prop: {
    default: '',
    type: String
  },
  placeHolder: {
    default: '',
    type: String
  },
  inputType: {
    // 字段类型,String,Array
    default: 'String',
    type: String
  },
  optionType: {
    //选择的类型:input,select,datePicker
    default: 'input',
    type: String
  },
  //多选框的选项
  selectOptions: {
    default: [{ label: '是', value: 1 }],
    type: Array
  },
  // 多选框是否多选
  multiple: {
    default: true,
    type: Boolean
  },
  disabled: { //是否禁用
    default: false,
    type: Boolean
  },
  //选择器是否远程搜索
  isRemote: {
    default: false,
    type: Boolean
  },
  //远程搜索的地址
  remoteSelectUrl: {
    default: '',
    type: String
  },
  //远程搜索需要的参数
  remoteParams: {
    default: { search: '', disease_id: '' },
    type: Object
  },
  //远程搜索需要的参数是否会发生改变,比如审核任务效率统计的页面里研究者中的项目id
  ifParamsChange: {
    default: false,
    type: Boolean
  },
  //新参数,需要替换
  nowRemoteParams: {
    default: { search: '', disease_id: [] },
    type: Object
  },
  //远程搜索时的字段,默认是search
  searchField: {
    default: 'search',
    type: String
  },
  //远程搜索获取的列表的label和value
  selectLabel: {
    default: 'label',
    type: String
  },
  selectValue: {
    default: 'value',
    type: String
  },
  //是否显示全选
  selectAll: {
    default: false,
    type: Boolean
  },
  //是否显示默认时间,默认是最近7天,进入页面时,请求时参数未传入,只是显示
  isDefaultTime: {
    default: false,
    type: Boolean
  },
  //时间选择范围,不能超过180天
  timeRangeDays: {
    default: null,
    type: Number
  },
  //在此日期之前的时间禁止选中
  disabledTime: {
    default: '',
    type: String
  },
  //绑定的值
  value: {}
})
watch(
  () => props.value,
  (newValue, oldValue) => {
    inputValue.value = props.value
    timeRange.value = props.value
  },
  () => props.selectOptions,
  (newValue, oldValue) => {
    newSelectOptions.value = props.selectOptions
  },
  () => props.nowRemoteParams, // 自定义的功能,可以不看
  (newValue, oldValue) => {
    if (props.prop == 'researcher') {
      params = { ...tempParams, ...props.nowRemoteParams }
    } else {
      params = { ...tempParams, ...props.remoteParams }
    }
  }
)

const inputValue = ref(null)
const timeRange = ref([])
const newSelectOptions = ref(null) //新的选项配置
const shortcuts = [
  {
    text: '最近一周',
    value: () => {
      const end = new Date()
      const start = new Date()
      start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
      return [start, end]
    }
  },
  {
    text: '最近一个月',
    value: () => {
      const end = new Date()
      const start = new Date()
      start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
      return [start, end]
    }
  },
  {
    text: '最近三个月',
    value: () => {
      const end = new Date()
      const start = new Date()
      start.setTime(start.getTime() - 3600 * 1000 * 24 * 90)
      return [start, end]
    }
  },
  {
    text: '最近半年',
    value: () => {
      const end = new Date()
      const start = new Date()
      start.setTime(start.getTime() - 3600 * 1000 * 24 * 180)
      return [start, end]
    }
  }
]

const defaultTime = reactive([new Date(0, 0, 0, 0, 0, 0), new Date(0, 0, 0, 23, 59, 59)])

onMounted(() => {
  inputValue.value = props.value
  newSelectOptions.value = props.selectOptions
  if (props.isRemote) {
    getOPtions('') //先默认获取选项列表
  }
  //设置默认时间为最近七天
  if (props.optionType == 'datePicker') {
    timeRange.value = props.isDefaultTime ? [getStartDate(), getEndDate()] : props.value
  }
})
const getStartDate = () => {
  const endDate = new Date() // 当前日期
  const startDate = new Date()
  startDate.setDate(endDate.getDate() - 6) // 最近七天的开始日期
  return startDate
}

const getEndDate = () => {
  const endDate = new Date() // 当前日期
  return endDate
}


const selectLoading = ref(false)
const selectRemoteMethod = (value) => {//远程搜
  getOPtions(value)
}

//这是为了处理,多选远程搜索时,输入框聚焦就能显示选项
const openChange = (open, value) => {
  let valueLength = inputValue.value ? inputValue.value.length : 0
  if (open && valueLength == 0 && props.isRemote) {
    getOPtions('')
  }
}
let params = reactive({})
const getOPtions = async (value) => {
  // 搜索的字段,可更改,根据业务需求来的

  let tempParams = {}
  tempParams[props.searchField] = value

  if (props.prop == 'researcher') {
    params = { ...tempParams, ...props.nowRemoteParams }
  } else {
    params = { ...tempParams, ...props.remoteParams }
  }
  selectLoading.value = true
  newSelectOptions.value = []
  let res = (
    await axios.get(props.remoteSelectUrl, {
      params: params
    })
  ).data
  if (res.code == 200) {
    if (res.data.length > 0) {
      newSelectOptions.value = res.data
    }
    selectLoading.value = false
  } else {
    ElMessage.error(res.message || '搜索失败!')
  }
}

//往上个页面emit数据
const returnValue = (val) => {
  // 若全选
  if (props.selectAll && val.some((el) => el == 'all')) {
    inputValue.value = newSelectOptions.value.map((item) => item[props.selectValue])
  }
  emit('returnValue', inputValue.value, props.prop, props.optionType, props.ifParamsChange)
}

//emit 时间
const returnData = () => {
  emit('returnValue', timeRange.value, props.prop, props.optionType)
}

/*
 *@target: 设置禁止选中的时间
 *@description: time不能在设置的默认日期前,如2023-06-20,该功能有些占性能,缺点之一
 
 */
const disabledDate = (time) => {
  const selectedTime = time.getTime() // 选中时间
  // 限制日期范围在 disabledTime之前不能选
  if (props.disabledTime) {
    const minDate = new Date(props.disabledTime).getTime()
    return selectedTime < minDate
  } else {
    true
  }
}

/*
 *@target: 限制时间段范围
 *@description: time 不能与现在的时间间隔超过特定天数,如180天
 *
 */
// 进入页面的时候,时间显示但是搜索值里没有
const chooseData = () => {
  // 设置时间
  if (timeRange.value) {
    const startDate = timeRange.value[0] || ''
    const endDate = timeRange.value[1] || ''
    // 限制时间段在 180 天以内
    const intervalDays = Math.floor((endDate - startDate) / (24 * 60 * 60 * 1000))
    if (props.timeRangeDays && intervalDays > props.timeRangeDays) {
      // 超过特定天数,进行处理,重置日期范围并提示用户
      timeRange.value = null
      ElMessage.warning('时间范围不能超过180天,请重新选择')
    } else if (props.disabledTime && startDate < new Date(props.disabledTime)) {
      //在时间结构表里选择时间时,不能选择特定限制日期前的时间
      timeRange.value = null
      ElMessage.warning(`不支持选择${props.disabledTime}前的时间,请重新选择`)
    }
  }
  returnData()
}

逻辑都在上面,注释写的很详细。

很多都是自定义方法,因为跟业务有关。

这上面封装的是比较简单。

总结

总的来说,封装搜索组件有助于提高前端应用的开发效率、质量和可维护性,特别是在大型应用中或需要频繁使用搜索功能的情况下,封装搜索组件是一个明智的选择。

但是!

我写的感觉还是不要高级,很多配置都是在业务堆积的过程中,一点点添加的。希望下次写个可扩展性和维护性高的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1112766.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

从裸机启动开始运行一个C++程序(十一)

前序文章请看&#xff1a; 从裸机启动开始运行一个C程序&#xff08;十&#xff09; 从裸机启动开始运行一个C程序&#xff08;九&#xff09; 从裸机启动开始运行一个C程序&#xff08;八&#xff09; 从裸机启动开始运行一个C程序&#xff08;七&#xff09; 从裸机启动开始运…

Vant和ElementPlus在vue的hash模式的路由下路由离开拦截使用Dialog和MessageBox失效

问题复现 ElementPlus&#xff1a;当点击返回或者地址栏回退时&#xff0c;MessageBox无效 <template><div>Element Plus Dialog 路由离开拦截测试</div><el-button type"primary" click"$router.back()">返回</el-button>…

Vue3 + TypeScript

Vue3 TS开发环境创建 1. 创建环境 vite除了支持基础阶段的纯TS环境之外&#xff0c;还支持 Vue TS开发环境的快速创建, 命令如下&#xff1a; $ npm create vitelatest vue-ts-pro -- --template vue-ts 说明&#xff1a; npm create vitelatest 基于最新版本的vite进行…

Linux搭建文件服务器

搭建简单文件服务器 基于centos7.9搭建http文件服务器基于centos7.9搭建nginx文件服务器基于ubuntu2204搭建http文件服务器 IP环境192.168.200.100VMware17 基于centos7.9搭建http文件服务器 安装httpd [rootlocalhost ~]# yum install -y httpd关闭防火墙以及selinux [roo…

【Qt-20】Qt信号与槽

一、什么是信号和槽 信号是特定情况下被发射的事件&#xff0c;发射信号使用emit关键字&#xff0c;定义信号使用signals关键字&#xff0c;在signals前面不能使用public、private、protected等限定符&#xff0c;信号只用声明&#xff0c;不需也不能对其进行定义实现。另外&am…

【Jetson 设备】window10主机下使用VNC可视化控制Jetson Orin NX

文章目录 前言VNC连接搭建(WiFi模式)Jetson Orin NX操作本地主机操作 VNC连接搭建(以太网模式)Jetson Orin NX操作本地主机操作 总结 前言 最近需要使用Jetson Orin NX对一些深度学习算法进行测试&#xff0c;为了方便主机与Jetson Orin NX之间的数据的传输&#xff0c;以及方…

MATLAB - 不能使用PYTHON,缺少matplotlib模块的解决办法

matlab缺少python-matplotlib模块的解决办法 1. 前言、概述2. 解决办法3. 可能出现问题4. 结果 1. 前言、概述 起因是我用习惯的colormap函数getPyPlot_cMap不能用了&#xff1a;【这个函数要调用PYTHON】 报错的地方&#xff1a; ModuleNotFoundError: No module named ‘ma…

html中公用css、js提取、使用

前言 开发中&#xff0c;页面会有引用相同的css、js的情况&#xff0c;如需更改则每个页面都需要调整&#xff0c;重复性工作较多&#xff0c;另外在更改内容之后上传至服务器中会有缓存问题&#xff0c;特针对该情况对公用css、js进行了提取并对引用时增加了版本号 一、提取…

微信小程序开发之会议OA的会议界面,投票界面

一、自定义组件 1&#xff0c;自定义组件介绍 从小程序基础库版本 1.6.3 开始&#xff0c;小程序支持简洁的组件化编程。所有自定义组件相关特性都需要基础库版本 1.6.3 或更高。 开发者可以将页面内的功能模块抽象成自定义组件&#xff0c;以便在不同的页面中重复使用&#xf…

grpc实现跨语言(go与java)服务通信

Golang微服务实战&#xff1a;使用gRPC实现跨语言通信&#xff01;随着微服务架构的发展&#xff0c;越来越多的企业开始采用微服务架构来构建分布式系统。在微服务架构中&#xff0c;服务之间的通信是非常重要的。而gRPC作为一种高效、跨平台、跨语言的RPC框架&#xff0c;成为…

小目标检测闲谈

学术界在小目标检测领域的研究进展似乎已经相对缓慢&#xff0c;这一趋势在年度顶级学术会议的相关论文中也有所体现。这部分停滞可能与深度学习领域整体的发展趋势有关。然而&#xff0c;小目标检测仍然是一个具有重要应用潜力的领域&#xff0c;尤其在实际部署中&#xff0c;…

ChatGPT(1):ChatGPT初识

1 ChatGPT原理 ChatGPT 是基于 GPT-3.5 架构的一个大型语言模型&#xff0c;它的工作原理涵盖了深度学习和自然语言处理技术。以下是 ChatGPT 的工作原理的一些关键要点&#xff1a; 神经网络架构&#xff1a;ChatGPT 的核心是一个深度神经网络&#xff0c;采用了变种的 Tran…

1 tcp协议20问

1什么是TCP网络分层 1.1分层描述 网络访问层&#xff1a; 2 TCP的三次握⼿中为什么是三次&#xff1f;为什么不是两次、四次&#xff1f; 两次握手的话&#xff0c;服务端会单方面认为建立已经成功&#xff0c;但是对于客户端而言&#xff0c;可能只是开个玩笑的&#xff0c…

形式化验证笔记

参考视频&#xff1a; 形式化验证的原理与新应用【DatenLord达坦科技】形式化验证入门(我强推&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;) 形式化验证&#xff1a;在状态机表征的空间里面进行搜索&#xff0c;验证某个模型是否按规范执行且测试覆盖率达到1…

058:mapboxGL监听键盘事件,通过panBy控制前后左右移动

第058个 点击查看专栏目录 本示例是介绍演示如何在vue+mapbox中监听键盘事件,控制前后左右移动。 本例通过panBy方法来移动一定距离的地图,通过.addEventListener的方法来监听键盘的按键动作。注意这里面style中一定要设置好pitch,不能为0,不然就撞墙,不能移动了。 直接复…

OpenCV 笔记(2):图像的属性以及像素相关的操作

Part11. 图像的属性 11.1 Mat 的主要属性 在前文中&#xff0c;我们大致了解了 Mat 的基本结构以及它的创建与赋值。接下来我们通过一个例子&#xff0c;来看看 Mat 所包含的常用属性。 先创建一个 3*4 的四通道的矩阵&#xff0c;并打印出其相关的属性&#xff0c;稍后会详细…

数据库索引种类

文章目录 索引的优缺点优点缺点 聚簇索引特点优点缺点 非聚簇索引特点优点缺点使用场景&#xff1a; 在MyISAM与InnoDB中的使用 索引的优缺点 索引概述 MySQL官方将索引定义为帮助MySQL高效获取数据的数据结构。索引的本质是一种排好序的快速查找数据结构&#xff0c;用于满足…

YOLOv5/v7/v8改进实验(五)之使用timm更换YOLOv5模型主干网络Backbone篇

&#x1f680;&#x1f680; 前言 &#x1f680;&#x1f680; timm 库实现了最新的几乎所有的具有影响力的视觉模型&#xff0c;它不仅提供了模型的权重&#xff0c;还提供了一个很棒的分布式训练和评估的代码框架&#xff0c;方便后人开发。更难能可贵的是它还在不断地更新迭…

(H5轮播)vue一个轮播里显示多个内容/一屏展示两个半内容

效果图 : html: <div class"content"><van-swipeclass"my-swipe com-long-swipe-indicator":autoplay"2500"indicator-color"#00C4FF"><van-swipe-itemclass"flex-row-wrap"v-for"(items, index) in M…

Kubernetes 进阶

Kubernetes 进阶  Service 控制器  Ingress 对象(对外暴露应用)  管理应用程序配置  K8s 数据卷与持久数据卷  再谈有状态应用部署:StatefulSet控制器  K8s 安全访问控制  K8s 部署利器Helm初探 Service 控制器 • Service存在的意义 • Pod与…