CategorySearch 카테고리 검색
타입(분류)별로 조건을 골라 검색할 수 있는 컴포넌트예요. 현재 지원하는 타입은 radio, checkbox, label, textInput, numberRange, keyword예요.
출처: 문서
본문
기본 사용법
:::demo
<template>
<d-category-search
:category="category"
:selected-tags="selectedTags"
search-key="basic"
:default-search-field="defaultSearchField"
:filter-name-rules="rules"
placeholder="Click here to choose a filter condition"
@search="onSearch"
@selectedTagsChange="onSelectedTagsChange"
@clearAll="onClearAll"
@createFilter="onCreateFilter"
@searchKeyChange="onSearchKeyChange"
></d-category-search>
</template>
<script>
import { defineComponent, ref } from 'vue';
export default defineComponent({
setup() {
const category = ref([
{
label: 'status',
field: 'status',
type: 'radio',
group: 'Basic',
filterKey: 'status',
options: [
{ status: 'new' },
{ status: 'developing' },
{ status: 'completed' },
{ status: 'under acceptance' },
{ status: 'closed-loop' },
],
},
{
label: 'checker',
field: 'checker',
type: 'checkbox',
group: 'Personnel-related',
filterKey: 'name',
options: [
{ name: 'Jack', value: 'Jack' },
{ name: 'Tom', value: 'Tom' },
{ name: 'Jerry', value: 'Jerry' },
],
},
{
label: 'tag',
field: 'tag',
type: 'label',
group: 'Basic',
filterKey: 'label',
colorKey: 'color',
options: [
{ label: 'Bug', color: '#f66f6a' },
{ label: 'Epic', color: '#5e7ce0' },
{ label: 'Story', color: '#50d4ab' },
],
},
{
label: 'release version',
field: 'releaseVersion',
type: 'textInput',
group: 'Basic',
maxLength: 10,
validateRules: [
{ required: true, message: '不能为空', trigger: 'change' },
{ min: 3, max: 10, message: '不小于3个字符,不大于6个字符', trigger: 'change' },
],
},
{
label: 'commit number',
field: 'commitNumber',
type: 'numberRange',
group: 'User-defined',
min: { left: 0 },
max: { left: 30, right: 50 },
step: { left: 2, right: 3 },
placeholder: { left: 'min', right: 'max' },
},
]);
const selectedTags = ref([
{
label: 'status',
field: 'status',
value: {
status: 'developing',
value: 'developing',
},
},
]);
const defaultSearchField = ['creator', 'status'];
const rules = [
{ required: true, message: '不能为空', trigger: 'change' },
{ min: 3, max: 16, message: '不小于3个字符,不大于6个字符', trigger: 'change' },
];
const onSearch = (e) => {
console.log('search items:', e);
};
const onSelectedTagsChange = (e) => {
console.log('selected tags change', e);
};
const onClearAll = (e) => {
console.log('clear all:', e);
};
const onCreateFilter = (e) => {
console.log('create filter', e);
};
const onSearchKeyChange = (e) => {
console.log('search key change:', e);
};
return {
category,
selectedTags,
defaultSearchField,
rules,
onSelectedTagsChange,
onClearAll,
onCreateFilter,
onSearchKeyChange,
onSearch,
};
},
});
</script>
:::
사용자 지정 표시 템플릿
:::demo 분류 드롭다운 표시 템플릿과 선택 후 태그 표시 템플릿을 직접 바꿀 수 있어요. 분류 드롭다운 표시 템플릿의 슬롯 이름은 ${field}Menu, 태그 표시 템플릿의 슬롯 이름은 ${field}Tag이고, field는 분류의 필드 이름이에요. 슬롯 인자로는 category 파라미터에서 해당 분류에 대응하는 데이터가 넘어와요.
<template>
<d-category-search
ref="categorySearchRef"
:category="category"
:selected-tags="selectedTags"
search-key="custom"
:default-search-field="defaultSearchField"
:text-config="textConfig"
:tag-max-width="160"
>
<template #statusMenu="scope">
<ul class="dp-dropdown-menu-template">
<li
v-for="(item, index) in scope.tagOption.options"
:key="index"
:class="['dp-dropdown-item', { active: scope.tagOption.value.status === item.status }]"
@click="() => chooseItem(scope.tagOption, item)"
>
<span>Status Name: {{ item.status }}</span>
</li>
</ul>
</template>
<template #tagTag="scope">
<span>{{ scope.tag.label }}: </span>
<template v-for="(item, index) in scope.tag.value.cache" :key="index">
<span style="margin:0 4px">{{ index + 1 }}.</span>
<span :style="{ color: item.color }">{{ item.label }}</span>
</template>
</template>
</d-category-search>
</template>
<script>
import { defineComponent, ref } from 'vue';
export default defineComponent({
setup() {
const category = ref([
{
label: 'status',
field: 'status',
type: 'radio',
group: 'Basic',
filterKey: 'status',
options: [
{ status: 'new' },
{ status: 'developing' },
{ status: 'completed' },
{ status: 'under acceptance' },
{ status: 'closed-loop' },
],
},
{
label: 'tag',
field: 'tag',
type: 'label',
group: 'Basic',
filterKey: 'label',
colorKey: 'color',
options: [
{ label: 'Bug', color: '#f66f6a' },
{ label: 'Epic', color: '#5e7ce0' },
{ label: 'Story', color: '#50d4ab' },
],
},
]);
const selectedTags = ref([
{
label: 'status',
field: 'status',
value: {
status: 'developing',
value: 'developing',
},
},
]);
const categorySearchRef = ref();
const defaultSearchField = ['status'];
const textConfig = {
keywordName: '模糊查找',
labelConnector: '&&',
};
const chooseItem = (tag, item) => {
categorySearchRef.value.chooseItem(tag, item);
};
return { category, selectedTags, categorySearchRef, defaultSearchField, textConfig, chooseItem };
},
});
</script>
:::
사용자 지정 확장 버튼
:::demo 분류 드롭다운 표시 템플릿과 선택 후 태그 표시 템플릿을 직접 바꿀 수 있어요. 분류 드롭다운 표시 템플릿의 슬롯 이름은 ${field}Menu, 태그 표시 템플릿의 슬롯 이름은 ${field}Tag이고, field는 분류의 필드 이름이에요. 슬롯 인자로는 category 파라미터에서 해당 분류에 대응하는 데이터가 넘어와요.
<template>
<d-category-search
ref="categorySearchRef"
:category="category"
:selected-tags="selectedTags"
:default-search-field="defaultSearchField"
:text-config="textConfig"
:extend-config="extendConfig"
:show-search-category="showSearchCategory"
@selectedTagsChange="onSelectedTagsChange"
>
<template #operation>
<div :class="['dp-category-search-icon reset', { disabled: !extendConfig.save.disabled }]" @click="reset">
<svg width="14px" height="14px" viewBox="0 0 16 16">
<title>reset status</title>
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<path
d="M2.21674752,9.5653401 C3.07840863,12.7589841 6.38381399,14.6542343 9.59957703,13.7985 C11.2074586,13.3706328 12.4884935,12.3360318 13.2598504,11.0091921 L15,12.0069575 C13.9715241,13.7760771 12.2634775,15.1555451 10.1196355,15.7260346 C5.83195146,16.8670137 1.42474431,14.3400134 0.275862827,10.0818215 C-0.0982576084,8.69518874 -0.0807292122,7.29596891 0.261105679,6 L5.12807455,8.79061807 L2.21674752,9.5653401 L2.21674752,9.5653401 Z M15.7241372,5.91817855 C16.0982576,7.30481126 16.0807292,8.70403109 15.7388943,10 L10.8719255,7.20938193 L13.7832525,6.4346599 C12.9215914,3.24101592 9.61618601,1.34576568 6.40042297,2.20150001 C4.79254145,2.62936717 3.51150652,3.66396818 2.74014961,4.99080789 L1,3.99304254 C2.02847588,2.22392292 3.73652245,0.844454904 5.88036448,0.273965353 C10.1680485,-0.867013747 14.5752557,1.65998658 15.7241372,5.91817855 L15.7241372,5.91817855 Z"
fill-rule="nonzero"
></path>
</g>
</svg>
</div>
</template>
</d-category-search>
</template>
<script>
import { defineComponent, ref, reactive } from 'vue';
export default defineComponent({
setup() {
const category = ref([
{
label: 'status',
field: 'status',
type: 'radio',
group: 'Basic',
filterKey: 'status',
options: [
{ status: 'new' },
{ status: 'developing' },
{ status: 'completed' },
{ status: 'under acceptance' },
{ status: 'closed-loop' },
],
},
]);
const selectedTags = ref([
{
label: 'status',
field: 'status',
value: {
status: 'developing',
value: 'developing',
},
},
]);
const categorySearchRef = ref();
const extendConfig = reactive({
show: true,
save: { disabled: false },
customTemplate: undefined,
});
const defaultSearchField = ['status'];
const textConfig = {
createFilter: '自定义过滤器',
filterTitle: '自定义过滤器标题',
noCategoriesAvailable: '自定义无可用分类',
};
const showSearchCategory = reactive({
keyword: false,
fieldDescription: (label) => `添加至 ${label} `,
category: false,
});
const onSelectedTagsChange = (event) => {
console.log('selected tag', event);
extendConfig.save.disabled = true;
};
const reset = () => {
selectedTags.value = [
{
label: 'status',
field: 'status',
value: {
status: 'developing',
value: 'developing',
},
},
];
extendConfig.save.disabled = false;
};
return {
category,
selectedTags,
categorySearchRef,
defaultSearchField,
textConfig,
extendConfig,
showSearchCategory,
onSelectedTagsChange,
reset,
};
},
});
</script>
:::
CategorySearch 파라미터
| 파라미터 | 타입 | 기본값 | 설명 | Demo 링크 |
|---|---|---|---|---|
| category | ICategorySearchTagItem[] | [] | 필수, 분류 검색 원본 데이터를 넘겨줘요 | 기본 사용법 |
| default-search-field | String[] |
[] | 선택, 키워드를 입력했을 때 어떤 분류를 대상으로 필터링할지 설정해요 | 기본 사용법 |
| selected-tags | ICategorySearchTagItem[] | [] | 선택, 기본으로 선택돼 있어야 하는 분류 데이터를 넘겨줘요 | 기본 사용법 |
| search-key | string |
'' | 선택, 검색창에 기본으로 표시할 값이에요 | 기본 사용법 |
| placeholder | string |
'' | 선택, 검색 입력창 placeholder 문구를 직접 정할 수 있어요 | 기본 사용법 |
| input-read-only | boolean |
false | 선택, 검색창에 키워드를 입력해 검색할 수 있는지 정해요. true면 키워드를 입력할 수 없고 제공된 분류 데이터로만 필터링할 수 있어요 |
|
| before-tag-change | (tag: ICategorySearchTagItem, searchKey: string, operation: string) => boolean | Promise<boolean> |
-- | 선택, 태그가 바뀌기 전에 호출되는 메서드예요. false를 반환하면 분류 값 변경을 막을 수 있어요 | |
| show-search-category | boolean | SearchConfig |
true | 선택, 검색 키워드 드롭다운 메뉴 표시 여부예요 | |
| filter-name-rules | Record<string, any>[] |
-- | 선택, 저장하는 필터 제목의 검증 규칙을 설정해요. 자세한 규칙은 vue-devui 라이브러리의 form 컴포넌트를 참고하세요 | 기본 사용법 |
| text-config | [TextConfig] | -- | 선택, 컴포넌트 기본 문구를 설정해요 | 사용자 지정 표시 템플릿 |
| extend-config | ExtendConfig | -- | 선택, 오른쪽 확장 버튼 기능을 설정해요 | 사용자 지정 확장 버튼 |
| tag-max-width | number |
-- | 선택, 개별 필터 조건의 최대 너비예요. 넘으면 말줄임표를 표시하고, 설정하지 않으면 제한이 없어요 | 사용자 지정 표시 템플릿 |
| append-to-body | boolean |
true | 선택, 드롭다운 메뉴를 body에 append할지 여부예요 | |
| input-autofocus | boolean |
true | 선택, 검색창 자동 포커스를 허용할지 여부예요. 스크롤바가 있는 화면에서 자동 포커스로 생기는 화면 밀림을 피할 수 있어요 | |
| collapse-tags | boolean | number |
false | 선택, 선택 값이 많을 때 선택 값을 개수 표시로 접을지 여부예요 | |
| collapse-tags-tooltip | Popover 파라미터 | { trigger: 'hover', position: ['top','bottom'] } | 선택, 선택 값을 개수로 접어 표시할 때 마우스를 올리면 뜨는 툴팁 설정이에요 |
CategorySearch 이벤트
| 이벤트명 | 콜백 파라미터 | 설명 |
|---|---|---|
| search | Function(SearchEvent) |
검색 버튼을 클릭하면 발생해요. 현재 선택된 분류 데이터와 검색창의 키워드를 반환해요 |
| selectedTagsChange | Function(SelectedTagsEvent) |
분류 데이터가 변경되면 발생해요. 현재 선택된 분류 데이터를 반환해요 |
| createFilter | Function(CreateFilterEvent) |
저장 버튼을 클릭하면 발생해요. 현재 선택된 분류 데이터와 검색창의 키워드를 반환해요 |
| clearAll | Function(e:Event) |
지우기 버튼을 클릭하면 발생해요. 현재 선택된 분류 데이터와 검색창의 키워드를 반환해요 |
| searchKeyChange | Function(val: string) |
검색 키워드가 바뀌면 발생해요. 입력창에 바인딩된 값을 반환해요 |
| selectedCategory | Function(e: SelectedCategoryEvent) |
분류를 클릭하면 발생해요. 현재 선택된 분류 데이터를 반환해요 |
CategorySearch 슬롯
| 슬롯명 | 설명 | 파라미터 | Demo 링크 |
|---|---|---|---|
| ${field}Menu | 분류별 드롭다운 패널을 직접 만들 수 있어요. field는 분류의 필드 이름이고, tagOption 인자는 현재 분류의 데이터, close 인자는 현재 드롭다운 패널을 닫는 메서드예요 |
{ tagOption: ICategorySearchTagItem, close: () => void } |
사용자 지정 표시 템플릿 |
| ${field}Tag | 분류별로 선택된 태그를 직접 만들 수 있어요. field는 분류의 필드 이름이고, tag 인자는 현재 분류의 데이터예요 |
{ tag: ICategorySearchTagItem } |
사용자 지정 표시 템플릿 |
| clear | 지우기 아이콘을 직접 만들 수 있어요 | ||
| save | 저장 아이콘을 직접 만들 수 있어요 | ||
| more | 더보기 아이콘을 직접 만들 수 있어요 | ||
| operation | clear, save, more를 제외한 다른 아이콘을 직접 만들 수 있어요 |
사용자 지정 확장 버튼 | |
| searchIcon | 검색 아이콘을 직접 만들 수 있어요 |
CategorySearch 메서드
| 메서드명 | 설명 | 파라미터 |
|---|---|---|
| chooseItem | 컴포넌트 메서드를 호출해 선택 데이터를 처리해요. radio 타입용이며, 인자는 현재 tag와 선택 항목이에요 |
(tag: ICategorySearchTagItem, chooseItem: ITagOption) => void |
| chooseItems | 컴포넌트 메서드를 호출해 선택 데이터를 처리해요. checkbox | label 타입용이며, 인자는 현재 tag예요 |
(tag: ICategorySearchTagItem) => void |
| getTextInputValue | 컴포넌트 메서드를 호출해 선택 데이터를 처리해요. textInput 타입용이며, 인자는 현재 tag와 입력 내용이에요 |
(tag: ICategorySearchTagItem, inputValue: string) => void |
| getNumberRangeValue | 컴포넌트 메서드를 호출해 선택 데이터를 처리해요. numberRange 타입용이며, 인자는 현재 tag와 입력 내용이에요 |
(tag: ICategorySearchTagItem, rangeValue: number[]) => void |
| toggleTagMenu | 선택된 tag에 대응하는 드롭다운의 펼침/접힘 상태를 조절해요. status 인자로 펼침/접힘 상태를 지정할 수 있어요 |
(field: string, status?: boolean) => void |
타입 정의
ICategorySearchTagItem
interface ICategorySearchTagItem {
/**
* 搜索字段,tag的键,用于区分不同的分类,需要唯一
*/
field: string;
/**
* tag 键的显示值
*/
label: string;
/**
* 配置项可生产的tag类型
*/
type?: CategorySearchTagType;
/**
* 配置项所属的分组
*/
group?: string;
/**
* tag 值的选择项数据
*/
options?: Array<ITagOption>;
/**
* 用于显示的 tag 值的键值,如未设置默认取label
*/
filterKey?: string | 'label';
/**
* 用于显示的label类型中色值的键值,如未设置默认取color
*/
colorKey?: string | 'color';
/**
* 已选中值
*/
value?: {
label?: string;
value?: string | ITagOption | Array<ITagOption | number | string | Date>;
cache?: string | ITagOption | Array<ITagOption | number | string | Date>;
[propName: string]: any;
};
/**
* textInput 类型设置最大长度
*/
maxLength?: number;
/**
* textInput | numberRange 类型设置占位符,numberRange需传入对象分别设置左右
*/
placeholder?: string | { left: string; right: string };
/**
* textInput 表单校验规则
*/
validateRules?: any[];
[propName: string]: any;
}
CategorySearchTagType
type CategorySearchTagType = 'radio' | 'checkbox' | 'label' | 'textInput' | 'numberRange' | 'keyword';
ITagOption
interface ITagOption {
/**
* 选项,label和color默认都会取对应的 filterKey 和 colorKey,如未设置取默认值
*/
label?: string; // 通用默认属性,用于设置分类名称
color?: string; // label 专用,用于设置标签颜色
[propName: string]: any;
}
SearchEvent
interface SearchEvent {
selectedTags: Array<ICategorySearchTagItem>;
searchKey: string;
}
SelectedCategoryEvent
interface SelectedCategoryEvent {
tag: ICategorySearchTagItem;
}
SelectedTagsEvent
interface SelectedTagsEvent {
selectedTags: Array<ICategorySearchTagItem>;
currentChangeTag: ICategorySearchTagItem;
operation: 'add' | 'delete' | 'clear';
}
CreateFilterEvent
interface CreateFilterEvent {
name: string;
selectedTags: Array<ICategorySearchTagItem>;
keyword: string;
}
ExtendConfig
interface ExtendConfig {
show?: boolean;
clear?: {
show?: boolean;
disabled?: boolean;
};
save?: {
show?: boolean;
disabled?: boolean;
};
more?: {
show?: boolean;
disabled?: boolean;
};
}
TextConfig
interface TextConfig {
keywordName?: string; // 关键字
createFilter?: string; // 保存过滤器
filterTitle?: string; // 过滤器标题
labelConnector?: string; // 链接符,默认'|'
noCategoriesAvailable?: string; // 没有筛选条件
tagMenuEmpty?: string; // 分类下拉菜单无数据展示的内容,默认'暂无数据'
}
더 알아보기 (Learn more)
CategorySearch는 검색창 하나에서 여러 분류 조건을 조합하는 실무형 필터 컴포넌트예요. 데모를 차례로 따라 해 보면 슬롯 커스터마이징과 확장 버튼 설정이 어떻게 연결되는지 감이 잡힐 거예요.