搜索结果列表页面开发
This commit is contained in:
65
src/components/SearchBar/README.md
Normal file
65
src/components/SearchBar/README.md
Normal file
@@ -0,0 +1,65 @@
|
||||
# SearchBar
|
||||
|
||||
### 说明
|
||||
- 基于d-select、RichBar等组件,组合而成的SearchBar
|
||||
|
||||
``` js
|
||||
import SearchBar from '@/components/SearchBar/index.vue';
|
||||
|
||||
<SearchBar
|
||||
:typeOptions="typeOptions"
|
||||
:searchOptions="searchOptions"
|
||||
:filter="filterFunc"
|
||||
@onSearch="handleSearch"
|
||||
>
|
||||
<!-- 右侧内容插槽 可以为空 -->
|
||||
<template #right>
|
||||
<RichLabel icon="milestone" :number="6522223" black group>里程碑</RichLabel>
|
||||
</template>
|
||||
</SearchBar>
|
||||
|
||||
const typeOptions = ref([{ name: '全部', value: '' }, { name: '类1', value: 'class1' }]);
|
||||
const searchOptions = ref([{ name: '全部', value: 'all' }, { name: '类1', value: 'class1' }]);
|
||||
|
||||
const filterFunc = (query: string): void => {
|
||||
// query为搜索框输入的文字,自动触发。d-select已自动debounce
|
||||
// 直接更新searchOptions数据
|
||||
};
|
||||
|
||||
const handleSearch = ({ type, query }): void => {
|
||||
// type对应左侧类型,query对应搜索框的搜索条件
|
||||
};
|
||||
```
|
||||
|
||||
### Props
|
||||
|
||||
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
|
||||
|-----------|------------------------|----------------------------|----------|-----------|
|
||||
| searchOptions? | 搜索框搜索词关联的下拉框数据 | Array<Option> | - | - |
|
||||
| typeOptions? | 左侧类型下拉框数据。若数据为空切不插槽,则隐藏类型选择组件 | Array<Option> | - | - |
|
||||
| placeholder? | 搜索框提示语 | string | - | '搜索...' |
|
||||
| resetTip? | 搜索框下方重置的文字 | string | - | '清空当前搜索、筛选及排序条件' |
|
||||
| filter? | d-select参数透传,是否开启过滤筛选,也可以直接传入过滤方法 | boolean \| function | - | false |
|
||||
| loading? | d-select参数透传,数据加载中(需搭配filter和remote) | boolean | - | false |
|
||||
| remote? | d-select参数透传,是否开启远程搜索(需搭配filter和loading) | boolean | - | false |
|
||||
| defaultType | d-select 默认选中项 | string | - | '' |
|
||||
|
||||
其中,type Option = { name: string, value: string }
|
||||
|
||||
### Emits
|
||||
|
||||
| 方法 | 说明 | 返回值 |
|
||||
|-----------------|------------------------------------|---------------------|
|
||||
| onSearch | 搜索框或者左侧下拉框选中 | { type: string, search: string } |
|
||||
| onReset | 重置搜索,清空左侧下拉框和搜索框输入 | |
|
||||
|
||||
|
||||
### Slots
|
||||
|
||||
| 名称 | 说明 |
|
||||
|---------------------|---------------------------------------------|
|
||||
| default | 搜索框下拉内容 |
|
||||
| search | 搜索框整体插槽 |
|
||||
| type | 左侧类型下拉框 |
|
||||
| right | 搜索框右侧 |
|
||||
| reset | 重置行整体插槽 |
|
||||
131
src/components/SearchBar/index.vue
Normal file
131
src/components/SearchBar/index.vue
Normal file
@@ -0,0 +1,131 @@
|
||||
<template>
|
||||
<div class="g-search-bar">
|
||||
<div class="g-search-bar-row">
|
||||
<div class="g-search-bar-row-search">
|
||||
<!-- 搜索框-左侧下拉框 -->
|
||||
<slot name="type">
|
||||
<d-select
|
||||
v-if="typeOptions?.length"
|
||||
class="g-search-bar-row-search-type"
|
||||
v-model="search.type"
|
||||
:options="typeOptions"
|
||||
@value-change="handleSearch"
|
||||
/>
|
||||
</slot>
|
||||
<!-- 搜索框 -->
|
||||
<slot name="search">
|
||||
<d-select
|
||||
class="g-search-bar-row-search-input"
|
||||
v-model="search.query"
|
||||
:filter="filter"
|
||||
:loading="loading"
|
||||
remote
|
||||
allow-clear
|
||||
:placeholder="placeholder"
|
||||
@value-change="handleSearch"
|
||||
>
|
||||
<slot name="default">
|
||||
<gc-option v-for="item in searchOptions" :key="item.value" :name="item.name" :value="item.value" />
|
||||
</slot>
|
||||
</d-select>
|
||||
</slot>
|
||||
</div>
|
||||
<!-- 搜索框右侧内容 -->
|
||||
<slot name="right"></slot>
|
||||
</div>
|
||||
<!-- 搜索框下方清空过滤 -->
|
||||
<slot name="reset">
|
||||
<div class="g-search-bar-reset">
|
||||
<span @click="handleReset">
|
||||
<i class="icon icon-remove" /> {{ resetTip }}
|
||||
</span>
|
||||
</div>
|
||||
</slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, Ref } from 'vue';
|
||||
|
||||
// Option的定义,与dev-ui保持一致
|
||||
type Option = {
|
||||
name: string,
|
||||
value: string | number | null,
|
||||
disabled?: boolean
|
||||
}
|
||||
interface IProps {
|
||||
searchOptions?: Array<Option>,
|
||||
typeOptions?: Array<Option>,
|
||||
placeholder?: string,
|
||||
resetTip?: string,
|
||||
remote?: boolean,
|
||||
filter?: boolean | any,
|
||||
loading?: boolean,
|
||||
defaultType?: string
|
||||
}
|
||||
const props = withDefaults(defineProps<IProps>(), {
|
||||
defaultType: '',
|
||||
placeholder: '搜索...',
|
||||
resetTip: '清空当前搜索、筛选及排序条件'
|
||||
});
|
||||
|
||||
const search: Ref<{
|
||||
query: string,
|
||||
type: string
|
||||
}> = ref({
|
||||
query: '',
|
||||
type: props.defaultType
|
||||
});
|
||||
|
||||
const emit = defineEmits(['onSearch', 'onReset']);
|
||||
|
||||
// 搜索条件发生变更
|
||||
const handleSearch = () => {
|
||||
emit('onSearch', search.value);
|
||||
};
|
||||
|
||||
// 重置搜索条件
|
||||
const handleReset = () => {
|
||||
search.value.query = '';
|
||||
search.value.type = '';
|
||||
|
||||
emit('onReset');
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.g-search-bar {
|
||||
&-row {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
&-search {
|
||||
display: inline-flex;
|
||||
flex: 1;
|
||||
&-type {
|
||||
width: 120px;
|
||||
margin-right: -1px;
|
||||
:deep(.devui-select__selection) {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
& + .g-search-bar-row-search-input {
|
||||
:deep(.devui-select__selection) {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
&-input {
|
||||
flex: 1;
|
||||
}
|
||||
.devui-select--open {
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
&-reset {
|
||||
margin-top: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user