Search Form
조건 기반 검색 기능을 제공하는 공통 폼 컴포넌트입니다.
이 컴포넌트는 내부적으로
<el-form>을 사용하고 있으며, 해당 컴포넌트의 속성들을 그대로 상속받아 활용할 수 있습니다. 자세한 속성 목록은 공식문서를 참고하세요.
props
| 이름 | 타입 | 기본값 | 설명 |
|---|---|---|---|
use-advanced | Boolean | false | 고급 검색 UI를 사용할지 여부 |
use-accordion | Boolean | false | 아코디언 UI를 사용할지 여부 |
always-expanded | Boolean | false | 고급 검색이 항상 펼쳐져 있을지 여부 |
use-tab | Boolean | false | 탭 UI 사용 여부 (고급 검색 내에 탭 구조) |
tab-position | number | 'top' | 탭 위치 top, left, right, bottom |
tab-items | Array<{ name: string; label: string }> | [] | 탭 구성 항목 (탭 이름, 라벨) |
query | Object | (required) | 화면의 검색 조건 그릇 (useQuery()). 폼이 이걸로 레지스트리를 만들어 하위 필드에 provide 한다 |
fixed | Object / null | null | 화면 고정 조건 — 초기화해도 유지된다. 고정 조건 참고 |
registry | SearchRegistry | undefined | 화면이 직접 만든 레지스트리를 쓸 때만 지정. 생략하면 폼이 만든다 |
content-style | Object | {width: '800px'} | 모달 컨텐츠 스타일 설정 |
column-size | number | 2 | 고급 검색 grid 컬럼 개수 기준 값 |
inline-min-cell-width | string | '180px' | 검색 바 필드의 최소 너비 |
inline-max-cell-width | string | '320px' | 검색 바 필드의 최대 너비. 필드가 남는 폭을 다 먹지 않도록 상한을 둔다 (초기화·검색 버튼이 필드 바로 뒤에 붙는다) |
inline-tag | boolean | true | 인라인 검색 태그를 보여줄지 여부 |
filter-tag | boolean | true | 고급 검색 모달 안에서도 검색 태그 보여줄지 여부 |
inline-reset | boolean | true | 인라인 영역에서 초기화 버튼 보여줄지 여부 |
filter-reset | boolean | true | 고급 검색 영역에서 초기화 버튼 보여줄지 여부 |
tag-type | string | 'primary' | 검색 태그 <el-tag>의 type 속성 (success, warning, info 등 사용 가능) |
tag-effect | string | 'light' | 검색 태그 <el-tag>의 effect 속성 (dark, light, plain) |
tag-color | string / undefined | undefined | 검색 태그 <el-tag>의 color (Hex나 CSS 색상 값) |
label-position | string | 'top' | Form label 위치 (top, left, right) |
label-width | string | 'auto' | 라벨 너비 설정 ('auto', '80px' 등) |
Slot
| 이름 | 설명 |
|---|---|
inline | 기본 인라인 검색 영역 |
filters | 고급 검색 필터 (탭 없음) |
item.name | 고급 검색 탭별 필터 (슬롯 동적 이름) |
footer | 고급 검색 모달 하단 |
Event
| 이름 | 발생 시점 | 설명 |
|---|---|---|
@submit | 검색 버튼, 필터 변경 후 태그 삭제 시 | 검색 조건을 반영하여 검색 수행 |
@reset | 초기화 버튼 클릭 시 | 폼이 조건을 이미 초기화한 뒤 발생한다. 핸들러는 재조회만 하면 된다 |
@cancel | 고급 검색 취소 버튼 클릭 시 | 폼이 열기 직전 조건으로 이미 되돌린 뒤 발생한다. 인자 없음 |
기본 검색
<template #inline>슬롯을 사용하여 기본적인 인라인 검색 필드를 배치합니다.nv-search-dynamic컴포넌트를 통해 키워드 검색 필드를 구현하고,nv-lv-mapper를 사용하여 검색 대상 필드 목록을 연결합니다.:query에 화면의useQuery()를 넘기면 폼이 검색 레지스트리를 만들어 하위 검색 필드에게 내려줍니다. 필드마다 필터 객체를 넘길 필요가 없습니다.@submit이벤트 핸들러 (onSearch)는 검색 버튼 클릭 시 검색 로직을 수행하도록 연결됩니다.@reset은 폼이 조건을 초기화한 뒤에 발생하므로 핸들러에서는 재조회만 하면 됩니다.
HTML
<nv-search-form
@submit="onSearch"
@reset="retrieve"
:query="query">
<template #inline>
<nv-search-dynamic nv-key="keyword" :nv-lv-mapper="codes.keyword" />
</template>
</nv-search-form>typescript
import {markRaw, nextTick, onMounted, ref} from 'vue';
import useQuery from 'components/composables/useQuery';
import {filterTool} from 'src/components/plugins/search';
const dataPerPageList = [40, 60, 100, 200];
const pagination = ref();
const query = useQuery();
const loaded = ref(false);
onMounted(async () => {
await init();
});
const init = async () => {
query.dataPerPage = dataPerPageList[0];
loaded.value = true;
await nextTick();
retrieve();
}
// ------------------------------------------------------------------------- event handler
const retrieve = () => {
pagination.value.go(1, query);
}
const onSearch = () => {
retrieve();
}
const paginated = (data) => {
list.value = data;
}고정 조건 (fixed)
- 화면이 항상 붙이는 조건(탈퇴 회원 제외, 특정 프로토콜만 등)은
:fixed로 넘깁니다. - 검색 필드가 없는 경로도 넣을 수 있고, 초기화 버튼을 눌러도 유지됩니다.
- 예전처럼
init()에서query.q['...'] = ...를 직접 대입한 뒤 스냅샷을 다시 만들 필요가 없습니다.
HTML
<nv-search-form
@submit="onSearch"
@reset="retrieve"
:query="query"
:fixed="{ 'acnt.dormant': false, 'acnt.close': false, 'acnt.deleted': false }">
<template #inline>
기본 검색폼
</template>
</nv-search-form>값이 화면 상태에 따라 바뀌면 computed 로 넘깁니다. 값이 바뀌면 조건도 따라 바뀝니다.
typescript
const fixedConditions = computed(() => ({ 'mtp.protocol': activeProtocol.value }));레지스트리 직접 조작
조건 값 자체는 화면이 소유한 query 안에 있으므로 query.q['b.name'].val 로 언제든 읽고 쓸 수 있습니다. 초기화·태그 메타처럼 레지스트리가 소유한 동작이 필요하면 폼을 템플릿 ref 로 꺼냅니다.
HTML
<nv-search-form ref="searchForm" :query="query" @submit="onSearch" @reset="retrieve">typescript
const searchForm = useTemplateRef('searchForm');
searchForm.value?.reset(); // 전체 초기화 (고정 조건은 유지)
searchForm.value?.registry.resetKey('b.name'); // 조건 하나만 초기화
searchForm.value?.registry.activeItems(); // 현재 걸려 있는 조건 목록WARNING
하나의 query 는 하나의 nv-search-form 이 소유합니다. 같은 query 를 두 폼에 넘기면 조건 키가 서로 충돌합니다.
고급검색 추가 (use-advanced)
use-advancedprop을true로 설정하면 고급 검색 버튼이 활성화됩니다.<template #filters>슬롯 내부에 다양한nv-search-*컴포넌트들을 배치하여 고급 검색 폼을 구성합니다. 텍스트 입력, 셀렉트 박스, 코드(드롭다운), 기간 선택, 토글 스위치, 체크박스 등 다양한 검색 조건을 추가할 수 있습니다.
HTML
<nv-search-form
@submit="onSearch"
@reset="retrieve"
use-advanced
:query="query">
<template #inline>
기본 검색폼
</template>
<template #filters>
고급 검색폼
</template>
</nv-search-form>아코디언 형태 변환 (use-accordion)
use-accordionprop을true로 설정하면 고급 검색 영역이 초기에는 접혀진 아코디언 형태로 표시되고, 버튼 클릭 시 펼쳐져 고급 검색 조건을 확인할 수 있습니다.- 이는 화면 공간을 효율적으로 활용하고자 할 때 유용합니다.
HTML
<nv-search-form :query="query"
use-accordion>
<template #inline>
기본 검색폼
</template>
<template #filters>
고급 검색폼
</template>
</nv-search-form>고급 검색 상시 노출 (always-expanded)
always-expandedprop을true로 설정하면 고급 검색 영역(#filters슬롯의 내용)이 초기부터 펼쳐진 상태로 사용자에게 노출됩니다.- 사용자가 고급 검색 조건을 자주 사용하거나, 주요 검색 옵션을 항상 보여주고 싶을 때 유용합니다.
HTML
<nv-search-form :query="query"
always-expanded>
<template #filters>
고급 검색폼
</template>
</nv-search-form>Tab 추가
use-tabprop을true로 설정하고tab-itemsprop을 통해 탭 목록을 정의하면, 고급 검색 영역 내에 탭 인터페이스가 생성됩니다.<template v-slot:name>형태로 각 탭에 해당하는 검색 필드들을 배치할 수 있으며,tab-items의name속성과 슬롯 이름이 정확히 일치해야 합니다.- 이는 고급 검색 조건이 많아 여러 그룹으로 나누어 표시하고 싶을 때 유용합니다.
HTML
<nv-search-form :query="query"
always-expanded
use-tab
:tab-items="tabItem">
<template #inline>
기본 검색폼
</template>
<template #test>
테스트 슬롯
</template>
<template #test2>
테스트2 슬롯
</template>
<template #test3>
테스트3 슬롯
</template>
<template #test4>
테스트4 슬롯
</template>
</nv-search-form>typescript
const tabItem = [
{name : 'test', label : '테스트'},
{name : 'test2', label : '테스트2'},
{name : 'test3', label : '테스트3'},
{name : 'test4', label : '테스트4'},
]WARNING
각 tabItem.name은 <template v-slot:[name]> 과 정확히 일치해야 합니다.
tab-position
tab-positionprop을 사용하여 고급 검색 탭의 위치를top,left,right,bottom중 하나로 변경할 수 있습니다.
HTML
<el-radio-group v-model="tabPosition" class="q-mb-md">
<el-radio value="top">top</el-radio>
<el-radio value="left">left</el-radio>
<el-radio value="right">right</el-radio>
<el-radio value="bottom">bottom</el-radio>
</el-radio-group>
<nv-search-form :query="query"
always-expanded
use-tab
:tab-items="tabItem"
:tab-position="tabPosition">
<template #inline>
기본 검색폼
</template>
<template #test>
테스트 슬롯
</template>
</nv-search-form>typescript
const tabPosition = ref('top')column-size
column-sizeprop은 고급 검색 영역(#filters슬롯) 내부에 배치되는 검색 필드들의 최대 컬럼 개수를 지정합니다.- 이는 그리드 레이아웃을 기반으로 하며, 한 줄에 표시될 수 있는 필드의 수를 조절하여 고급 검색 폼의 레이아웃을 구성하는 데 사용됩니다.
HTML
<el-input-number v-model="columnSize" :min="1" :max="5" class="q-mb-md" />
<nv-search-form
use-advanced
:query="query"
:column-size="columnSize">
<template #inline>
기본 검색폼
</template>
<template #filters>
고급 검색폼
</template>
</nv-search-form>typescript
const columnSize = ref(2)Label
label-position
label-positionprop을 사용하여 폼 전체의 라벨 위치를top,left,right중 하나로 설정할 수 있습니다.
HTML
<el-radio-group v-model="labelPosition" class="q-mb-md">
<el-radio value="top">top</el-radio>
<el-radio value="left">left</el-radio>
<el-radio value="right">right</el-radio>
</el-radio-group>
<nv-search-form
use-advanced
:query="query"
:label-position="labelPosition">
<template #inline>
기본 검색폼
</template>
<template #filters>
고급 검색폼
</template>
</nv-search-form>typescript
const labelPosition = ref('top')label-width
label-widthprop을 사용하여 폼 라벨의 너비를 명시적으로 지정합니다.'auto'로 설정하면 라벨 내용에 따라 자동으로 너비가 조정되고,'80px'과 같은 CSS width 값을 지정하여 고정 너비를 사용할 수도 있습니다.label-position이left또는right일 때,'auto'는 가장 긴 라벨을 기준으로 너비를 설정합니다.
label-position :
label-width :
label-width :
HTML
<div>
<small>label-position : </small>
<el-radio-group v-model="labelPosition2" class="q-ml-md">
<el-radio value="top">top</el-radio>
<el-radio value="left">left</el-radio>
<el-radio value="right">right</el-radio>
</el-radio-group>
<br/>
<small>label-width : </small>
<el-radio-group v-model="labelWidth" class="q-mb-md q-ml-md">
<el-radio value="auto">auto</el-radio>
<el-radio value="100px">100px</el-radio>
</el-radio-group>
</div>
<nv-search-form
use-advanced
:query="query"
:label-position="labelPosition2"
:label-width="labelWidth">
<template #inline>
기본 검색폼
</template>
<template #filters>
고급 검색폼
</template>
</nv-search-form>typescript
const labelPosition2 = ref('right')
const labelWidth = ref('auto')