본문으로 바로가기 본문 바로가기
WIKI 기술 지식 베이스

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는 검색창 하나에서 여러 분류 조건을 조합하는 실무형 필터 컴포넌트예요. 데모를 차례로 따라 해 보면 슬롯 커스터마이징과 확장 버튼 설정이 어떻게 연결되는지 감이 잡힐 거예요.