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

news2024/11/14 23:54:20

目录

一、应用场景

二、开发流程

三、详细开发流程

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/1114151.html

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

相关文章

【笔记】centos7 python2.7.5安装paramiko

更直接的方式&#xff0c;参考: 离线安装_离线安装paramiko 这个更简单。 准备 资源链接: https://download.csdn.net/download/qq_26834611/88445708https://download.csdn.net/download/qq_26834611/88445708 或者选择自己下载 1. 下载python-devel 在一台能联网的cent…

静电放电保护和片式压敏电阻器

1 引言 随着电子设备功能的增加&#xff0c;输入∕输出连接器也随之增多&#xff0c;这为静电放电&#xff08;ESD&#xff09;提供了进入电路的路径&#xff0c;静电放电保护问题变得不容忽视。因此&#xff0c;有必要采用静电放电保护元件&#xff0c;在静电放电进入电路板之…

Doris删库元数据删除怎么办?紧急恢复单副本情况

简介 正常情况下&#xff0c;如果是多副本的数据存储很容易修复&#xff0c;删除一个两个be也能根据doris自身的恢复机制恢复起来&#xff0c;但是&#xff0c;有时候可能有些表没有弄多个副本&#xff0c;那么就有点搞头了。 案例说明&#xff1a;fe的master节点的数据误删除…

笔记本电脑Windows10安装

0 前提 安装windows10的电脑为老版联想笔记本电脑&#xff0c;内部没有硬盘&#xff0c;临时加装了1T的硬盘。 1u盘准备 准备u盘&#xff0c;大小大于16G。u盘作为系统盘时&#xff0c;需要将内部的其他文件备份&#xff0c;然后格式化。u盘格式化后&#xff0c;插入一款可以…

eNSP-OSPF协议其他区域不与骨干区域相连解决方法2

隧道技术 AR1 [ar1]int g0/0/0 [ar1-GigabitEthernet0/0/0]ip add 192.168.1.1 24 [ar1-GigabitEthernet0/0/0]quit [ar1]ospf [ar1-ospf-1]area 0 [ar1-ospf-1-area-0.0.0.0]net 192.168.1.0 0.0.0.255 [ar1-ospf-1-area-0.0.0.0]quit AR2 [ar2]int g0/0/0 [ar2-GigabitEthe…

父组件与子组件的属性透传

透传是vue中一种特性&#xff0c;官方的解释是&#xff1a;“透传 attribute”指的是传递给一个组件&#xff0c;却没有被该组件声明为 props 或 emits 的 attribute 或者 v-on 事件监听器。最常见的例子就是 class、style 和 id。这句话解释过来就是一些不被prop定义的属性直接…

信钰证券:这些板块,逆市走强!

A股商场今天上午出现调整&#xff0c;上证指数跌破3000点&#xff0c;不过跌幅不大。 新动力赛道股打开反弹&#xff0c;其间&#xff0c;锂矿概念股成为上午商场最大亮点&#xff0c;吉翔股份2连板&#xff0c;龙头股赣锋锂业暴升7.74%。风电股也震荡走强&#xff0c;威力传动…

Hadoop学习总结(搭建Hadoop集群(完全分布式模式))

学习搭建Hadoop集群&#xff08;完全分布式模式&#xff09; 链接&#xff1a;https://pan.baidu.com/s/1wwTKk-XxHbccHjE-Xk2PTA 提取码&#xff1a;q7j7 在SecurityCRT 或者在 Xshell 进行虚拟机链接 &#xff08;这里使用Xshell &#xff09; 在hadoop001里配置 如果没…

【c#】Quartz开源任务调度框架学习及练习Demo

Quartz开源任务调度框架学习及练习Demo 1、定义、作用 2、原理 3、使用步骤 4、使用场景 5、Demo代码参考示例 6、注意事项 7、一些Trigger属性说明 1、定义、作用 Quartz是一个开源的任务调度框架&#xff0c;作用是支持开发人员可以定时处理业务&#xff0c;比如定时…

【C语言入门】C语言的历史 与 编程环境的安装选择与搭建

C语言入门 前言C语言的概念与历史一、什么是C语言&#xff1f;二、 C语言的历史与辉煌环境的选择三、编译器的选择 VS2022&#xff08;一&#xff09;编译和链接&#xff08;二&#xff09;编译器的对比&#xff08;三&#xff09;VS2022 的优缺点&#xff08;四&#xff09;VS…

解决 阿里云oss 对象存储 bucket 中的文件不能在线预览 只能下载

我的域名是在腾讯云的&#xff0c;所以点开腾讯云的域名解析后台。 点击添加记录&#xff1b; 记录类型选 CNAME&#xff1b;主机记录 随便写&#xff1b;解析线路 默认&#xff1b; 记录值 填你的bucketname 就是你存储文件的bucket的名字 然后 . 域名所在区域 北京就是oss-c…

SqueezeNet 一维,二维网络复现 pytorch 小白易懂版

SqueezeNet 时隔一年我又开始复现神经网络的经典模型&#xff0c;这次主要复的是轻量级网络全家桶&#xff0c;轻量级神经网络旨在使用更小的参数量&#xff0c;无限的接近大模型的准确率&#xff0c;降低处理时间和运算量&#xff0c;这次要复现的是轻量级网络的非常经典的一…

WebSocket 入门案例

目录 WebSocket入门案例WebSocket-server新增项目:添加依赖:yml:启动类&#xff1a; frontend-server前端项目&#xff1a;添加依赖&#xff1a;添加yml&#xff1a;启动类&#xff1a;前端引入JS:前端页面&#xff1a;后端代码&#xff1a;测试&#xff1a; WebSocket 入门案…

众和策略:地产板块发力走高,荣盛发展涨停,碧桂园等大幅拉升

地产板块20日盘中发力走高&#xff0c;到发稿&#xff0c;金科股份、荣盛展开涨停&#xff0c;中南建造、富丽家族涨超7%&#xff0c;华夏夸姣涨逾6%。 港服方面&#xff0c;内资地产股亦走强&#xff0c;到发稿&#xff0c;珠光控股涨超20%&#xff0c;碧桂园涨近10%&#xf…

PBA.常用人工智能预测分析算法

相同的数据型态&#xff0c;利用不同的方法分析&#xff0c;就可以解决不同的课题。例如目前已相当纯熟的人脸识别技术&#xff0c;在国防应用可以进行安保工作&#xff1b;企业可做员工门禁系统&#xff1b;可结合性别、年龄辨识让卖场进行市调分析&#xff0c;或结合追踪技术…

聚焦于先进电池技术等领域的前沿研究和应用,龙讯旷腾出席中国化学会第二届能源化学青年论坛

成都站电催化培训 2023年龙讯团队线下培训已走过北京、西安等城市&#xff0c;前几期均以定向邀请非公开的形式培训&#xff0c;应大家的积极号召&#xff0c;本期电催化成都站的培训我们将以公开招募的形式举办&#xff0c;并且保留前几期的优惠&#xff08;前30位免费&#…

html网页代码块高亮加行号

程序示例精选 html网页代码块高亮加行号 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对《html网页代码块高亮加行号》编写代码&#xff0c;代码整洁&#xff0c;规则&#xff0c;易读。 学习…

shopee平台现在好做吗

Shopee 是一家知名的电子商务平台&#xff0c;特别在东南亚地区非常流行。是否在 Shopee 平台做生意是否好做取决于多种因素&#xff0c;包括你的产品、市场竞争、营销策略和运营能力等。 以下是一些考虑因素&#xff1a; 1、产品选择&#xff1a;选择畅销的产品或具有市场需求…

需要在 MySQL 服务器中监控的重要指标

MySQL是一个开源的关系数据库管理系统&#xff0c;它基于客户端-服务器模型运行&#xff0c;使用SQL作为其通信模式。它具有灵活性和可扩展性、高安全性、易用性以及无缝处理大型数据集的能力&#xff0c;由于其广泛的功能&#xff0c;MySQL 被用作数据库管理系统的一部分。 什…

初识Java 14-2 测试

目录 测试驱动开发&#xff08;TDD&#xff09; 日志 调试 使用JDB进行调试 基准测试 微基准测试 Java微基准测试工具&#xff08;JMH&#xff09; 分析和优化 重构 本笔记参考自&#xff1a; 《On Java 中文版》 测试驱动开发&#xff08;TDD&#xff09; 测试驱动开…