欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Element-plus封裝搜索組件的實現(xiàn)

 更新時間:2024年08月23日 10:00:35   作者:優(yōu)秀穩(wěn)妥的JiaJi  
在后臺管理系統(tǒng)中,經(jīng)常需要在多個頁面中使用搜索功能,本文就來介紹一下Element-plus封裝搜索組件的實現(xiàn),具有一定的參考價值,感興趣的可以了解一下

前言

在后臺管理系統(tǒng)中,經(jīng)常需要在多個頁面中使用搜索功能。搜索的形式可以包括文本搜索、時間范圍搜索、選擇框搜索、日期搜索和多級聯(lián)選搜索等。然而,在每個頁面中編寫重復(fù)的搜索功能代碼會導(dǎo)致效率低下且代碼冗余。為了解決這個問題,我們可以封裝一個通用的搜索組件,以節(jié)省開發(fā)時間和減少重復(fù)代碼的量。(僅供參考,歡迎評論區(qū)jym提出更好的意見)

首先,讓我們分析頁面布局和功能需求:

  • 搜索組件本質(zhì)上是一個表單。
  • 表單中包含了文本框、選擇框、級聯(lián)選擇器和日期選擇器等不同類型的輸入控件。
  • 當(dāng)點擊搜索按鈕時,應(yīng)觸發(fā)搜索事件;當(dāng)點擊重置按鈕時,應(yīng)觸發(fā)重置事件。

基于上述分析,我們可以逐步實現(xiàn)具體的功能。請按照以下步驟進(jìn)行操作:

  • 創(chuàng)建一個新的 Vue 3 項目:npm create vue@latest
  • 刪除項目中自動生成的文件和內(nèi)容。
  • 在項目中安裝 Element Plus:npm install element-plus --save

導(dǎo)入項目,自行查閱

在components目錄中創(chuàng)建 mySearch 組件,包含了一個基于 Element Plus 的表單 (el-form)。表單的屬性包括大小 (size)、數(shù)據(jù)模型 (model) 和標(biāo)簽寬度 (label-width),這些屬性通過組件的 props 傳遞進(jìn)來。

在 el-row 元素中,使用了 v-for 指令來遍歷 props.option 數(shù)組,該數(shù)組用于配置不同類型的搜索輸入控件。
搜索按鈕 (el-button) 和重置按鈕 (el-button),它們分別綁定了 search 方法和 reset 方法。這些方法會在用戶點擊按鈕時觸發(fā)相應(yīng)的事件。

<template>
    <div>
        <el-form ref="searchRef" :size="props.size" :model="searchVal" :label-width="props.labelWidth">
            <el-row :gutter="20">       
                <el-col :xs="24" :sm="12" :md="12" :lg="props.span" v-for="(item, index) in props.option" :key="index" class="mb20">
                </el-col>
                <el-col :xs="24" :sm="12" :md="12" :lg="props.span">         
                    <el-form-item>            
                        <el-button type="primary" @click="search">搜索</el-button>          
                        <el-button @click="reset(searchRef)">重置</el-button>          
                    </el-form-item>       
                </el-col>
            </el-row>
        </el-form>
    </div>
</template>

<script lang='ts' setup>
    import { onMounted, reactive, ref } from 'vue'
    import type { ElForm } from 'element-plus'
    import { ElMessage } from 'element-plus'
    import { formatDate } from '@/utils/formatTime'
    import type { Option } from '@/components/type.d.ts'

    type FormInstance = InstanceType<typeof ElForm>
        const searchRef = ref<FormInstance>()
    // 搜索值
    let searchVal: any = reactive({})
    // 搜索
    const search = () => {
        for (let i in searchVal) {
            if (searchVal[i] === undefined || searchVal[i] === '') {
                delete searchVal[i]
            }
        }
        emit('search', searchVal)
    }
    // 重置
    const reset = (formEl: FormInstance | undefined) => {
        if (!formEl) return
        formEl.resetFields()
        emit('search', searchVal)
    }
    interface Props {
        labelWidth?: number | string
        size?: 'small' | 'default' | 'large'
        span?: number
        option: Option[]
        defaultValue?: any
    }
    const props = withDefaults(defineProps<Props>(), {
        size: 'default',
        span: 8,
        labelWidth: 100
    })
</script>

聲明了一個類型別名 FormInstance,用于表示表單的實例。通過 ref 函數(shù)創(chuàng)建了一個響應(yīng)式引用 searchRef,用于引用表單實例。使用 reactive 函數(shù)創(chuàng)建了一個響應(yīng)式對象 searchVal,用于存儲搜索的值。

定義 search 方法,該方法會在搜索按鈕被點擊時觸發(fā)。遍歷 searchVal 對象的屬性,如果屬性值為空或未定義,則從 searchVal 中刪除該屬性。最后,我們通過 emit 方法觸發(fā) search 的自定義事件,并將 searchVal 作為參數(shù)傳遞給父組件。定義了 reset 方法,該方法會在重置按鈕被點擊時觸發(fā)。傳入的表單實例調(diào)用 resetFields 方法,將表單重置為初始狀態(tài)。最后,再次通過 emit 方法觸發(fā)search 的自定義事件,并將 searchVal 作為參數(shù)傳遞給父組件。

接下來分析option中的數(shù)據(jù),新建type.d.ts

//選擇框的option類型
interface SelectOption {
  label: string
  value: any
}
//選擇框和文本輸入框的option類型
interface InputOptions {
  prop: string
  option: SelectOption[]
}

export interface Option {
  label: string //標(biāo)簽名稱
  prop: string //表單項字段名
  endProp?: string //日期范圍的結(jié)束日期字段名
  placeholder?: string //輸入框占位文本
  type?: 'input' | 'select' | 'cascader' | 'date' | 'datetime' | 'daterange' | 'inputSelect' //表單項類型
  optionLabel?: string //選擇框的label字段
  optionValue?: string //選擇框的value字段
  option?: any[] //選擇框option
  inputOptions?: InputOptions //選擇框和文本輸入框的option
  max?: number //級聯(lián)選擇器的最大選擇數(shù)量
  children?: string //級聯(lián)選擇器children字段名
  multiple?: boolean //級聯(lián)選擇器是否多選
  value?: string //級聯(lián)選擇器返回值字段名
  itemLabel?: string //級聯(lián)選擇器選項名稱
  checkStrictly?: boolean //是否可選擇父節(jié)點和子節(jié)點
  emitPath?: boolean // 是否返回由該節(jié)點所在的各級菜單的值所組成的數(shù)組
  show?: boolean //是否顯示選中值的完整路徑
  filterable?: boolean //選擇框是否可搜索
}

完善表單,根據(jù)實際需求,暴露出表單的配置項,完整代碼如下
ini 代碼解讀復(fù)制代碼<template>
    <div>
        <el-form ref="searchRef" :size="props.size" :model="searchVal" :label-width="props.labelWidth">
            <el-row :gutter="20">
                <el-col :xs="24" :sm="12" :md="12" :lg="props.span" v-for="(item, index) in props.option" :key="index" class="mb20">
                    <el-form-item v-if="item.type == 'input' || !item.type" @keyup.enter="search" :prop="item.prop" :label="item.label">
                        <el-input v-model="searchVal[item.prop]" :placeholder="item.placeholder"></el-input>
                    </el-form-item>
                    <el-form-item v-if="item.type == 'inputSelect'" label-width="0" :prop="item.prop">
                        <el-input v-model="searchVal[item.prop]" clearable :placeholder="item.placeholder">
                            <template #prepend>
                                <el-select v-model="searchVal[item.inputOptions.prop]" :style="{ width: props.labelWidth + 'px' }">
                                    <el-option v-for="(sItem, sIndex) in item.inputOptions.option" :key="sIndex" :label="sItem.label" :value="sItem.value"></el-option>
                                </el-select>
                            </template>
                        </el-input>
                    </el-form-item>
                    <el-form-item v-else-if="item.type == 'select'" :prop="item.prop" :label="item.label">
                        <el-select v-model="searchVal[item.prop]" :filterable="item.filterable" :fit-input-width="true" style="width: 100%" :placeholder="item.placeholder">
                            <el-option v-for="(sItem, sIndex) in item.option" :key="sIndex" :label="sItem[item.optionLabel || 'label']" :value="sItem[item.optionValue || 'value']"></el-option>
                        </el-select>
                    </el-form-item>
                    <el-form-item v-else-if="item.type == 'cascader'" :prop="item.prop" :label="item.label">
                        <el-cascader
                                     v-model="searchVal[item.prop]"
                                     :options="item.option"
                                     :placeholder="item.placeholder"
                                     clearable
                                     :props="{
                                             value: item.value || 'value',
                                             label: item.itemLabel || 'label',
                                             children: item.children || 'children',
                                             multiple: item.multiple || false,
                                             emitPath: item.emitPath || false,
                                             checkStrictly: item.checkStrictly || false
                                             }"
                                     :show-all-levels="item.show || false"
                                     @change="(val: any) => changeType(val, item)"
                                     />
                    </el-form-item>
                    <el-form-item v-else-if="item.type == 'date'" :prop="item.prop" :label="item.label">
                        <el-date-picker
                                        v-model="searchVal[item.prop]"
                                        type="date"
                                        value-format="YYYY-MM-DD"
                                        format="YYYY-MM-DD"
                                        :placeholder="item.placeholder"
                                        style="width: 100%"
                                        ></el-date-picker>
                    </el-form-item>
                    <el-form-item v-else-if="item.type == 'datetime'" :prop="item.prop" :label="item.label">
                        <el-date-picker
                                        v-model="searchVal[item.prop]"
                                        type="datetime"
                                        value-format="YYYY-MM-DD HH:mm"
                                        format="YYYY-MM-DD HH:mm"
                                        :placeholder="item.placeholder"
                                        style="width: 100%"
                                        ></el-date-picker>
                    </el-form-item>
                    <el-form-item v-else-if="item.type == 'daterange'" :prop="item.prop" :label="item.label">
                        <el-date-picker
                                        v-model="searchVal[item.prop + 'Range']"
                                        style="width: 100%"
                                        type="daterange"
                                        range-separator="~"
                                        start-placeholder="開始時間"
                                        end-placeholder="結(jié)束時間"
                                        value-format="YYYY-MM-DD"
                                        format="YYYY-MM-DD"
                                        @change="changeDateRange(item)"
                                        >
                        </el-date-picker>
                    </el-form-item>
                </el-col>
                <el-col :xs="24" :sm="12" :md="12" :lg="props.span">
                    <el-form-item>
                        <el-button type="primary" @click="search">搜索</el-button>
                        <el-button @click="reset(searchRef)">重置</el-button>
                    </el-form-item>
                </el-col>
            </el-row>
        </el-form>
    </div>
</template>

<script lang="ts" setup>
    import { onMounted, reactive, ref } from 'vue'
    import type { ElForm } from 'element-plus'
    import { ElMessage } from 'element-plus'
    import { formatDate } from '@/utils/formatTime'
    import type { Option } from '@/components/type.d.ts'

    type FormInstance = InstanceType<typeof ElForm>

        const searchRef = ref<FormInstance>()

    // 搜索值
    let searchVal: any = reactive({})

    // 搜索
    const search = () => {
        for (let i in searchVal) {
            if (searchVal[i] === undefined || searchVal[i] === '') {
                delete searchVal[i]
            }
        }
        emit('search', searchVal)
    }

    // 重置
    const reset = (formEl: FormInstance | undefined) => {
        if (!formEl) return
        formEl.resetFields()
        emit('search', searchVal)
    }
    // 級聯(lián)選擇
    const changeType = (value: any, data: Option) => {
        if (!value) value = []
        if (value.length > (data.max as number)) {
            searchVal[data.prop] = value.slice(0, 4)
            ElMessage.error('館校類型數(shù)量限制為4個')
        }
    }
    // 日期范圍選擇
    const changeDateRange = (item: any) => {
        let dateArr = searchVal[item.prop + 'Range']
        if (dateArr) {
            searchVal[item.prop] = formatDate(dateArr[0], 'YYYY-mm-dd')
            searchVal[item.endProp] = formatDate(dateArr[1], 'YYYY-mm-dd')
        } else {
            searchVal[item.prop] = ''
            searchVal[item.endProp] = ''
        }
    }

    const emit = defineEmits(['search', 'reset'])

    interface Props {
        labelWidth?: number | string
        size?: 'small' | 'default' | 'large'
        span?: number
        option: Option[]
        defaultValue?: any
    }

        const props = withDefaults(defineProps<Props>(), {
            size: 'default',
            span: 8,
            labelWidth: 100
        })

        onMounted(() => {
            if (props.defaultValue) {
                props.option.forEach((p: any) => {
                    if (p.type == 'daterange' && props.defaultValue[p.prop]) {
                        searchVal[p.prop + 'Range'] = []
                        if (props.defaultValue[p.prop]) {
                            searchVal[p.prop + 'Range'][0] = props.defaultValue[p.prop]
                        }
                        if (props.defaultValue[p.endProp]) {
                            searchVal[p.prop + 'Range'][1] = props.defaultValue[p.endProp]
                        }
                    }
                })
                searchVal = Object.assign(searchVal, props.defaultValue)
            }
        })
</script>

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

實際使用,App.vue中

<template>
  <div class="main">
    <MySearch :option="searchOptions" :defaultValue="{ daterange: '', endDaterange: '' }" @search="search" />
  </div>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue'
import MySearch from './components/mySearch.vue'
import type { Option } from '@/components/type.d.ts'

const cascaderOptions = [
  {
    value: 'guide',
    label: 'Guide',
    children: [
      {
        value: 'disciplines',
        label: 'Disciplines',
        children: [
          {
            value: 'consistency',
            label: 'Consistency'
          },
          {
            value: 'feedback',
            label: 'Feedback'
          },
          {
            value: 'efficiency',
            label: 'Efficiency'
          },
          {
            value: 'controllability',
            label: 'Controllability'
          }
        ]
      },
      {
        value: 'navigation',
        label: 'Navigation',
        children: [
          {
            value: 'side nav',
            label: 'Side Navigation'
          },
          {
            value: 'top nav',
            label: 'Top Navigation'
          }
        ]
      }
    ]
  },
  {
    value: 'component',
    label: 'Component',
    children: [
      {
        value: 'basic',
        label: 'Basic',
        children: [
          {
            value: 'layout',
            label: 'Layout'
          },
          {
            value: 'color',
            label: 'Color'
          },
          {
            value: 'typography',
            label: 'Typography'
          },
          {
            value: 'icon',
            label: 'Icon'
          },
          {
            value: 'button',
            label: 'Button'
          }
        ]
      },
      {
        value: 'form',
        label: 'Form',
        children: [
          {
            value: 'radio',
            label: 'Radio'
          },
          {
            value: 'checkbox',
            label: 'Checkbox'
          },
          {
            value: 'input',
            label: 'Input'
          },
          {
            value: 'input-number',
            label: 'InputNumber'
          },
          {
            value: 'select',
            label: 'Select'
          },
          {
            value: 'cascader',
            label: 'Cascader'
          },
          {
            value: 'switch',
            label: 'Switch'
          },
          {
            value: 'slider',
            label: 'Slider'
          },
          {
            value: 'time-picker',
            label: 'TimePicker'
          },
          {
            value: 'date-picker',
            label: 'DatePicker'
          },
          {
            value: 'datetime-picker',
            label: 'DateTimePicker'
          },
          {
            value: 'upload',
            label: 'Upload'
          },
          {
            value: 'rate',
            label: 'Rate'
          },
          {
            value: 'form',
            label: 'Form'
          }
        ]
      },
      {
        value: 'data',
        label: 'Data',
        children: [
          {
            value: 'table',
            label: 'Table'
          },
          {
            value: 'tag',
            label: 'Tag'
          },
          {
            value: 'progress',
            label: 'Progress'
          },
          {
            value: 'tree',
            label: 'Tree'
          },
          {
            value: 'pagination',
            label: 'Pagination'
          },
          {
            value: 'badge',
            label: 'Badge'
          }
        ]
      },
      {
        value: 'notice',
        label: 'Notice',
        children: [
          {
            value: 'alert',
            label: 'Alert'
          },
          {
            value: 'loading',
            label: 'Loading'
          },
          {
            value: 'message',
            label: 'Message'
          },
          {
            value: 'message-box',
            label: 'MessageBox'
          },
          {
            value: 'notification',
            label: 'Notification'
          }
        ]
      },
      {
        value: 'navigation',
        label: 'Navigation',
        children: [
          {
            value: 'menu',
            label: 'Menu'
          },
          {
            value: 'tabs',
            label: 'Tabs'
          },
          {
            value: 'breadcrumb',
            label: 'Breadcrumb'
          },
          {
            value: 'dropdown',
            label: 'Dropdown'
          },
          {
            value: 'steps',
            label: 'Steps'
          }
        ]
      },
      {
        value: 'others',
        label: 'Others',
        children: [
          {
            value: 'dialog',
            label: 'Dialog'
          },
          {
            value: 'tooltip',
            label: 'Tooltip'
          },
          {
            value: 'popover',
            label: 'Popover'
          },
          {
            value: 'card',
            label: 'Card'
          },
          {
            value: 'carousel',
            label: 'Carousel'
          },
          {
            value: 'collapse',
            label: 'Collapse'
          }
        ]
      }
    ]
  },
  {
    value: 'resource',
    label: 'Resource',
    children: [
      {
        value: 'axure',
        label: 'Axure Components'
      },
      {
        value: 'sketch',
        label: 'Sketch Templates'
      },
      {
        value: 'docs',
        label: 'Design Documentation'
      }
    ]
  }
]

const searchOptions: Option[] = reactive([
  {
    label: '文本類型',
    placeholder: '請輸入文本',
    type: 'input',
    prop: 'input'
  },
  {
    label: '選擇框',
    prop: 'select',
    placeholder: '請選擇支付方式',
    type: 'select',
    option: [
      {
        label: '微信',
        value: 0
      },
      {
        label: '支付寶',
        value: 1
      }
    ]
  },
  {
    label: '文本選擇框',
    prop: 'inputSelect1',
    placeholder: '請輸入文本',
    type: 'inputSelect',
    inputOptions: {
      prop: 'inputSelect2',
      option: [
        {
          label: '微信',
          value: 0
        },
        {
          label: '支付寶',
          value: 1
        }
      ]
    }
  },
  {
    label: '級聯(lián)選擇器',
    placeholder: '請選擇級聯(lián)選擇器',
    type: 'cascader',
    prop: 'cascader',
    option: cascaderOptions
  },
  {
    label: '日期選擇',
    type: 'date',
    prop: 'date',
    placeholder: '請選擇日期'
  },
  {
    label: '日期時間',
    type: 'datetime',
    prop: 'datetime',
    placeholder: '請選擇日期時間'
  },
  {
    label: '日期范圍',
    type: 'daterange',
    prop: 'daterange',
    endProp: 'endDaterange'
  }
])
// 搜索
const search = (val: any) => {
  tableData.searchForm = val
  tableData.page.pageIndex = 1
  initTableData()
}

//表格數(shù)據(jù)
const tableData: any = reactive({
  data: [],
  searchForm: {},
  page: {
    pageIndex: 1,
    pageSize: 10,
    total: 0
  }
})

// 初始化表格數(shù)據(jù)
const initTableData = () => {
  console.log(tableData.searchForm)
}
</script>
<style scoped>
.main {
  padding: 20px;
}
</style>

總結(jié):

實現(xiàn)了一個搜索組件,根據(jù) props.option 數(shù)組動態(tài)生成不同類型的表單項,以便用戶輸入搜索條件。

  • 代碼中的 el-col 元素表示一個列布局,用于展示生成的表單項。
  • 根據(jù) props.option 數(shù)組的每一項 item,根據(jù) item.type 的不同選擇不同的表單項類型進(jìn)行渲染。
  • 支持的表單項類型包括輸入框、帶下拉選擇框的輸入框、選擇框、級聯(lián)選擇器、日期選擇器和日期范圍選擇器。
  • 每個表單項都綁定了相應(yīng)的數(shù)據(jù)模型,通過 v-model 實現(xiàn)了數(shù)據(jù)的雙向綁定。
  • 表單項的標(biāo)簽、屬性和占位符等信息都是根據(jù) item 對象中的屬性動態(tài)設(shè)置的。

這個搜索組件提供了一種靈活的方式來生成不同類型的表單項,以便用戶輸入搜索條件。通過配置 props.option 數(shù)組,可以定制化生成所需的表單項,并且支持不同的表單驗證和交互方式。如果需要進(jìn)一步定制和擴展,可以根據(jù)具體的需求修改和補充代碼。

到此這篇關(guān)于Element-plus封裝搜索組件的實現(xiàn)的文章就介紹到這了,更多相關(guān)Element-plus 搜索組件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 解決在el-dialog中無法正確獲取DOM的問題

    解決在el-dialog中無法正確獲取DOM的問題

    這篇文章主要介紹了解決在el-dialog中無法正確獲取DOM的問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • Vue的輪播圖組件實現(xiàn)方法

    Vue的輪播圖組件實現(xiàn)方法

    下面小編就為大家分享一篇Vue的輪播圖組件實現(xiàn)方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-03-03
  • mini-vue渲染的簡易實現(xiàn)

    mini-vue渲染的簡易實現(xiàn)

    本文主要介紹了mini-vue渲染的簡易實現(xiàn),主要簡單來實現(xiàn)一個虛擬dom渲染真實dom,以及更新的方法。具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • Vue 框架之鍵盤事件、健值修飾符、雙向數(shù)據(jù)綁定

    Vue 框架之鍵盤事件、健值修飾符、雙向數(shù)據(jù)綁定

    這篇文章主要介紹了Vue 框架之鍵盤事件、健值修飾符、雙向數(shù)據(jù)綁定問題,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2018-11-11
  • Vue3中插槽slot的使用方法詳解

    Vue3中插槽slot的使用方法詳解

    在Vue?3中,插槽(slot)是一種強大的內(nèi)容分發(fā)API,它允許組件的模板開發(fā)者定義一種插槽,下面就跟隨小編一起來學(xué)習(xí)一下它的具體使用吧
    2024-11-11
  • vue頁面圖片不顯示問題解決方案

    vue頁面圖片不顯示問題解決方案

    這篇文章主要介紹了vue頁面圖片不顯示問題解決方案,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-09-09
  • Vue.js之$emit用法案例詳解

    Vue.js之$emit用法案例詳解

    這篇文章主要介紹了Vue.js之$emit用法案例詳解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-09-09
  • vue等待數(shù)據(jù)渲染完成后執(zhí)行下一個方法問題

    vue等待數(shù)據(jù)渲染完成后執(zhí)行下一個方法問題

    這篇文章主要介紹了vue等待數(shù)據(jù)渲染完成后執(zhí)行下一個方法問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • vue動態(tài)路由配置及路由傳參的方式

    vue動態(tài)路由配置及路由傳參的方式

    這篇文章主要介紹了vue動態(tài)路由配置,vue路由傳參的方式,文中給大家提到了router-link這個組件的相關(guān)知識,需要的朋友可以參考下
    2018-05-05
  • 有關(guān)vue 開發(fā)釘釘 H5 微應(yīng)用 dd.ready() 不執(zhí)行問題及快速解決方案

    有關(guān)vue 開發(fā)釘釘 H5 微應(yīng)用 dd.ready() 不執(zhí)行問題及快速解決方案

    這篇文章主要介紹了有關(guān)vue 開發(fā)的釘釘 H5 微應(yīng)用 dd.ready() 不執(zhí)行問題及快速解決方案,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-05-05

最新評論