近期产物提出了一个需求,要求一个form的表单内里的一个组件既可以下拉含糊搜索,又可以弹窗搜索,我就为这个封装了一个组件,下面看效果图。


效果大家看到了,下面就看组件封装和实现方法
第一步,组件封装,我取名为C_SerachBtn 组件,其中的C_Select组件也可以用el-select组件来代替,C_Select使我们自己封装的组件。

- <template>
- <div class="search-box">
- <C_Select
- v-bind="$attrs"
- v-model="_modelValue"
- filterable
- remote
- clearable
- reserve-keyword
- remote-show-suffix
- :remote-method="overhaulProjectCodeMethod"
- :options="_options || []"
- :loading="_loading"
- @focus="focus"
- @change="handleChangeSearchBtn($event)"
- />
- <el-button
- :icon="Search"
- color="#f5f7fa"
- class="search-box-btn"
- @click="handleBtnClick"
- />
- </div>
- </template>
- <script lang="ts" setup>
- import { isFunction } from '@/utils/d_is'
- import { Search } from '@element-plus/icons-vue'
- interface Props {
- value: any
- label?: any
- option?: any
- options?: any[]
- // query代表的值
- queryValue: string
- // 列表label代表的字段
- labelField?: string
- // 列表label代表的字段
- valueField?: string
- disabledField?: string
- // 下拉数据请求接口
- api?: (arg?: any) => Promise<any>
- // 接口参数
- params?: any
- //返回的值和赋值的值
- callBackNames: any[],
- // 返回列表数据字段
- resultField?: string
- // 是否立即请求接口,否则将在第一次获取焦点时触发请求
- immediate?: boolean
- // 是否多选
- multiple?: boolean
- }
- const props = withDefaults(defineProps<Props>(), {
- labelField: 'label',
- valueField: 'value',
- disabledField: 'disabled',
- resultField: 'records',
- queryValue:'',
- callBackNames:[],
- immediate: true,
- })
- const emits = defineEmits([
- 'update:value',
- 'update:label',
- 'update:option',
- 'change',
- 'visible-change',
- 'remove-tag',
- 'clear',
- 'blur',
- 'focus',
- // 下拉接口重新请求,数据更新后触发
- 'options-change',
- //按钮点击
- 'btn-click',
- ])
- const _selectRef = ref()
- const _modelValue = ref(props.value || '')
- const _options = ref(props.options || [])
- const _option = ref(props.option || {})
- const _loading = ref(false)
- watch(
- () => props.options,
- (newVal) => {
- if (props.api) return
- _options.value = newVal
- },
- {
- deep: true,
- }
- )
- watch(
- () => props.option,
- (newVal) => {
- _option.value = newVal
- },
- {
- deep: true,
- }
- )
- watch(
- () => props.value,
- (newVal) => {
- if (props.multiple && !Array.isArray(newVal)) {
- console.error('multiple 为true时,传入的value数据类型必须为array')
- }
- _modelValue.value = newVal
- },
- {
- immediate: true,
- }
- )
- watch(
- () => _modelValue.value,
- () => {
- emits('update:value', _modelValue.value)
- },
- {
- immediate: true,
- }
- )
- //标准项目编号-搜索开始
- const overhaulProjectCodeMethod = async (query: string) => {
- if (query) {
- const api = props.api
- if (!api || !isFunction(api)) return
- _options.value = []
- _loading.value = true
- let obj= {
- pageNum: 1,
- pageSize: 10,
- ...props.params,
- }
- obj[props.queryValue] = query
- let res = await api(obj)
- _loading.value = false
- let arr = props.labelField.split(',')
- _options.value = res.records.map((item) => {
- let str =''
- arr.forEach(p=> str += item[p] +' ')
- return {
- label: str,
- value: item[props.valueField],
- name: item[props.valueField],
- key: item[props.valueField],
- ...item,
- }
- })
- } else {
- _options.value = []
- }
- }
- async function handleChangeSearchBtn(val) {
- if(!val){
- props.callBackNames.forEach(p=>{
- _option.value[p.value] = ''
- })
- return
- }
- let obj = _options.value.filter(
- (el) => el.value == val
- )[0]
- props.callBackNames.forEach(p=>{
- _option.value[p.value] = obj[p.name]
- })
- change(val)
- }
- //按钮点击
- const handleBtnClick = () => {
- emits('btn-click', unref(_options))
- }
- // 下拉接口重新请求,数据更新后触发
- const emitChange = () => {
- emits('options-change', unref(_options))
- }
- // 当 input 获得焦点时触发
- const focus = (e) => {
- emits('focus', e)
- }
- // 选中值发生变化时触发
- const change = (val) => {
- let data = _options.value?.filter((x) => x.value == val)
- emits('change', val, data)
- }
- // 下拉框出现/隐藏时触发
- const visibleChange = (val: boolean) => {
- handleFetch()
- emits('visible-change', val)
- }
- // 多选模式下移除tag时触发
- const removeTag = (val) => {
- emits('remove-tag', val)
- }
- // 可清空的单选模式下用户点击清空按钮时触发
- const clear = (e) => {
- emits('clear', e)
- }
- // 当 input 失去焦点时触发
- const blur = (e) => {
- emits('blur', e)
- }
- const getOptions = () => _options.value
- defineExpose({ selectMethods: _selectRef, getOptions })
- </script>
- <style scoped>
- .search-box{
- display: flex;
- width: 100%;
- .search-box-btn{
- border-top-left-radius: 0px;
- border-bottom-left-radius: 0px;
- border-top: 1px solid #dcdfe6;
- border-right: 1px solid #dcdfe6;
- border-bottom: 1px solid #dcdfe6;
- color: #a8abb2;
- }
- }
- </style>
复制代码 第二步,页面使用,在页面中el-table中当做slot使用,我的slot取名为 overhaulProjectCode
- <!-- 标准项目编号 -->
- <template #overhaulProjectCode="{ row, index }">
- <C_SearchBtn
- v-model:value="row.overhaulProjectCode"
- :placeholder="'请选择'"
- :api="ListOverhaulProject"
- :option="row"
- :queryValue="'overhaulCode'"
- :params="{
- deviceCode: 0,
- status: 3,
- }"
- :labelField="'overhaulCode,overhaulName'"
- :valueField="'overhaulCode'"
- :options="[]"
- :callBackNames="[
- {
- name: 'id',
- value: 'overhaulProjectId',
- },
- {
- name: 'overhaulCode',
- value: 'overhaulProjectCode',
- },
- {
- name: 'overhaulName',
- value: 'overhaulProjectName',
- },
- ]"
- @btn-click="handleOverhaulCodeModalVisible(row, index)"
- @focus="handleFocus(index)"
- />
- </template>
复制代码 第三步,弹窗,和一般的弹窗一样,自行封装。
- <!-- 生产设备 -->
- <materialOne
- title="选择生产设备"
- v-if="materialOneModalVisible"
- :data="curRow"
- v-model:visible="materialOneModalVisible"
- @select="handleMaterialOneSelect2"
- @close="materialOneModalVisible = false"
- />
复制代码 以上就是基本的做的c_SerachBtn的组件的封装,其中的一些比方handleOverhaulCodeModalVisibl 和 handleFocus 方法需要自己定义,根据自己的详细的需求举行修改。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |