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

EditableSelect 입력 가능한 드롭다운 선택 상자

원문 보기 위키 갱신

입력과 드롭다운 선택을 동시에 지원하는 입력 컴포넌트예요.

출처: 문서

본문

언제 사용하나요

사용자가 데이터를 직접 입력하는 것과 기존 데이터에서 고르는 것을 모두 지원해야 할 때 사용해요. 입력 연상(자동완성) 기능을 더해 기존 데이터를 검색하기 편하게 만들 수 있어요.

기본 사용법

v-model의 값은 현재 선택된 value 속성 값이에요. :::demo

<template>
  <d-editable-select v-model="value" :options="options" :width="450"></d-editable-select>
</template>

<script>
import { defineComponent, ref, reactive } from 'vue';

export default defineComponent({
  setup() {
    const value = ref('');
    const options = reactive([
      {
        label: 'label0',
        value: 'label0',
      },
      {
        label: 'label1',
        value: 'label1',
      },
      {
        label: 'label2',
        value: 'label2',
      },
    ]);

    return {
      value,
      options,
    };
  },
});
</script>

:::

크기

sm, md, lg 세 가지 크기를 지원하고, 기본값은 md예요. :::demo

<template>
  <h5>small</h5>

  <d-editable-select v-model="value" :options="options" :width="450" size="sm"></d-editable-select>

  <h4>middle</h4>

  <d-editable-select v-model="value" :options="options" :width="450"></d-editable-select>

  <h3>large</h3>

  <d-editable-select v-model="value" :options="options" :width="450" size="lg"></d-editable-select>
</template>

<script>
import { defineComponent, ref, reactive } from 'vue';

export default defineComponent({
  setup() {
    const value = ref('');

    const options = reactive([
      {
        label: 'label0',
        value: 'label0',
      },
      {
        label: 'label1',
        value: 'label1',
      },
      {
        label: 'label2',
        value: 'label2',
      },
    ]);

    return {
      value,
      options,
    };
  },
});
</script>

:::

선택기 자체 비활성화

선택기 컴포넌트 전체를 비활성화해요.

disabled 속성을 설정하면 선택기 전체를 사용할 수 없게 돼요. :::demo

<template>
  <d-row type="flex">
    <d-col :flex="4">
      <d-editable-select v-model="value" :disabled="isDisabled" :width="450" :options="options"></d-editable-select>
    </d-col>
    <d-col :flex="2">
      <d-button id="primaryBtn" @click="toggle" style="margin-left:10px">
        {{ isDisabled ? 'Enable EditableSelect' : 'Disable EditableSelect' }}
      </d-button>
    </d-col>
  </d-row>
</template>
<script>
import { defineComponent, ref, reactive } from 'vue';

export default defineComponent({
  setup() {
    const value = ref('');

    const options = reactive([
      {
        label: 'label0',
        value: 'label0',
      },
      {
        label: 'label1',
        value: 'label1',
      },
      {
        label: 'label2',
        value: 'label2',
      },
    ]);

    const isDisabled = ref(false);

    const toggle = () => {
      isDisabled.value = !isDisabled.value;
    };
    return {
      value,
      options,
      isDisabled,
      toggle,
    };
  },
});
</script>

:::

비활성화 옵션이 있는 경우

disabled-key 값을 설정해 비활성화할 옵션의 Key 값을 직접 지정할 수 있어요.

:::demo

<template>
  <d-editable-select v-model="value" :width="450" :options="options" disabled-key="disabled"></d-editable-select>
</template>

<script>
import { defineComponent, ref, reactive } from 'vue';

export default defineComponent({
  setup() {
    const value = ref('');

    const options = reactive([
      {
        label: 'label0',
        value: 'label0',
        disabled: true,
      },
      {
        label: 'label1',
        value: 'label1',
      },
      {
        label: 'label2',
        value: 'label2',
      },
    ]);

    return {
      value,
      options,
    };
  },
});
</script>

:::

선택 초기화(클리어) 기능

선택기를 초기 상태로 비울 수 있어요.

allow-clear 속성을 설정하면 선택기를 비울 수 있어요. :::demo

<template>
  <d-editable-select v-model="value" :width="450" :options="options" allow-clear @input-change="handleInputChange"></d-editable-select>
</template>

<script>
import { defineComponent, ref, reactive } from 'vue';

export default defineComponent({
  setup() {
    const value = ref('');

    const options = reactive([
      {
        label: 'label0',
        value: 'label0',
      },
      {
        label: 'label1',
        value: 'label1',
      },
      {
        label: 'label2',
        value: 'label2',
      },
    ]);

    const handleInputChange = (val) => {
      console.log(val);
    };

    return {
      value,
      options,
      handleInputChange,
    };
  },
});
</script>

:::

커스텀 필터 메서드

로컬 검색에 사용할 필터 메서드를 직접 정의할 수 있고, 로컬 검색에서만 동작해요. :::demo

<template>
  <d-editable-select v-model="value" :width="450" :options="options" :filter-method="filterMethod"></d-editable-select>
</template>
<script>
import { defineComponent, ref, reactive } from 'vue';

export default defineComponent({
  setup() {
    const value = ref('');

    const filterMethod = (query) => {
      if (query) {
        options.value = options.value.filter((item) => {
          return item.label.toLowerCase().indexOf(query.toLowerCase()) !== -1;
        });
      } else {
        options.value = [];
      }
    };

    let options = ref([
      {
        label: 'label0',
        value: 'label0',
      },
      {
        label: 'label1',
        value: 'label1',
      },
      {
        label: 'label2',
        value: 'label2',
      },
    ]);

    return {
      value,
      options,
      filterMethod,
    };
  },
});
</script>

:::

커스텀 템플릿 표시

개별 옵션이 어떻게 렌더링될지와, 매칭되는 데이터가 없을 때 보여줄 템플릿을 직접 정의할 수 있어요.

:::demo

<template>
  <d-editable-select v-model="value" :width="450" :options="options">
    <template #item="slotProps">
      <div>第{{ slotProps.index }}项: {{ slotProps.option.label }}</div>
    </template>
    <template>
      <div>没有匹配项</div>
    </template>
  </d-editable-select>
</template>
<script>
import { defineComponent, ref, reactive } from 'vue';

export default defineComponent({
  setup() {
    const value = ref('');
    const options = reactive([
      {
        label: 'label0',
        value: 'label0',
      },
      {
        label: 'label1',
        value: 'label1',
      },
      {
        label: 'label2',
        value: 'label2',
      },
    ]);

    return {
      value,
      options,
    };
  },
});
</script>

:::

원격 검색

입력한 키워드로 서버에서 데이터를 검색해요.

원격 검색을 활성화하려면 remote-method를 넘겨야 해요. remote-method는 Function이고, 입력값이 바뀔 때 호출되며 인자로 현재 입력값을 받아요. :::demo

<template>
  <d-editable-select
    remote
    enable-lazy-load
    v-model="value"
    :max-height="300"
    :width="450"
    :options="options"
    :loading="loading"
    :remote-method="remoteMethod"
    @load-more="loadMore"
  >
  </d-editable-select>
</template>

<script>
import { defineComponent, ref, reactive } from 'vue';

export default defineComponent({
  setup() {
    const value = ref('');
    const search = ref('');
    const options = ref([]);
    const loading = ref(false);
    let index = 0;

    let timer = null;
    const fetch = () => {
      loading.value = true;
      return new Promise((resolve) => {
        const data = [];
        if (timer) {
          clearTimeout(timer);
          timer = null;
        }
        timer = setTimeout(() => {
          for (let i = 0; i < 15; i++) {
            data.push({
              label: `label${i + index}`,
              value: i + index,
            });
          }
          loading.value = false;
          resolve(data);
        }, 2000);
      });
    };

    const remoteMethod = async (query) => {
      search.value = query;
      let list = await fetch();
      if (query) {
        options.value = list.filter((item) => {
          return item.label.toLowerCase().includes(query.toLowerCase());
        });
      } else {
        options.value.splice(0, options.value.length);
      }
    };

    const loadMore = async () => {
      index += 15;
      let list = await fetch();
      options.value = options.value.concat(
        list.filter((item) => {
          return item.label.toLowerCase().includes(search.value.toLowerCase());
        })
      );
    };

    return {
      value,
      options,
      loading,
      loadMore,
      remoteMethod,
    };
  },
});
</script>

:::

EditableSelect 파라미터

파라미터 타입 기본값 설명 Demo 링크
model-value / v-model string | number '' 선택, 선택 항목 바인딩 값 기본 사용법
options Options [] 선택, 데이터 리스트 기본 사용법
allow-clear boolean false 선택, 옵션 비우기 가능 여부 기본 사용법
size string 'md' 선택, 입력창 크기. 'lg', 'md', 'sm' 세 가지 크기
placeholder string 'Select' 선택, 입력창 기본 힌트 텍스트 기본 사용법
width number -- 선택, 입력창 너비 기본 사용법
max-height number -- 선택, 드롭다운 최대 높이 기본 사용법
disabled boolean false 선택, 선택기 자체 비활성화 여부 선택기 자체 비활성화
disabled-key string '' 선택, 비활성화 옵션의 Key 값 설정 옵션 비활성화
enable-lazy-load boolean false 선택, 지연 로딩 허용 여부 원격 검색
filter-method (inputValue:string)=>Array<Options> -- 선택, 필터 메서드 커스텀 커스텀 매칭 메서드
remote-method (inputValue:string)=>Array<Options> -- 선택, 원격 검색 메서드 커스텀 원격 검색
show-glow-style boolean true 선택, 호버 발광 효과 표시 여부
max-length number -- 선택, 입력창 최대 입력 길이

EditableSelect 이벤트

이벤트명 콜백 파라미터 설명 Demo 링크
load-more (inputvalue:string)=>void 선택, 지연 로딩 트리거 이벤트 원격 검색
focus (e: FocusEvent)=>void 선택, input 포커스 획득 시 트리거
blur (e: FocusEvent)->void 선택, input 포커스 상실 시 트리거
change (value:string|number)=>void 선택, 선택 값 변경 시 트리거
visible-change (visible:boolean)=>void 선택, 드롭다운 표시/숨김 시 트리거
input-change (inputvalue:string)=>void 선택, 입력창 입력 시 트리거 옵션 비우기

EditableSelect 슬롯

슬롯명 설명 Demo 링크
item 선택, 드롭다운 메뉴 항목 템플릿 커스텀 템플릿 표시
noResultItem 선택, 드롭다운 메뉴 항목 검색 후 결과가 없을 때의 템플릿 커스텀 템플릿 표시

EditableSelect 타입 정의

Options

export type Option = {
  label: string;
  value: string | number;
  disabled?: boolean;
  [key: string]: unknown;
};

export type Options = Array<Option>;

더 알아보기 (Learn more)

입력과 선택을 동시에 지원하는 컴포넌트로, filter-method와 remote-method로 검색 동작을 직접 정의할 수 있어요. #item 슬롯으로 옵션 렌더링을 커스텀하고, enable-lazy-load로 스크롤 시 추가 데이터를 불러올 수도 있어요.