139 lines
3.6 KiB
Vue
139 lines
3.6 KiB
Vue
<template>
|
|
<div class="mb-2" :class="isRow ? 'row' : ''">
|
|
<label :for="name" class="col-md-2 col-form-label" :class="isLabel ? 'd-block' : 'd-none'">
|
|
{{ title }}
|
|
<span v-if="isEssential" class="link-danger">*</span>
|
|
</label>
|
|
<div :class="isRow ? 'col-md-10' : 'col-md-12'" class="d-flex gap-2 align-items-center">
|
|
<select class="form-select" :id="name" v-model="selectData" :disabled="disabled" :style="isColor ? { color: selected } : {}" @blur="$emit('blur')">
|
|
<option v-for="(item, i) in data" :key="i" :value="isCommon ? item.value : i" :style="isColor ? { color: item.label } : {}">
|
|
{{ isCommon ? item.label : item }}
|
|
</option>
|
|
</select>
|
|
<div v-if="isBtn" class="ms-2">
|
|
<slot name="append"></slot>
|
|
</div>
|
|
|
|
<div v-if="isColor && selected"
|
|
class="w-px-40 h-px-30"
|
|
:style="{backgroundColor: selected}">
|
|
</div>
|
|
|
|
<img v-if="isMbti && selected"
|
|
role="img"
|
|
class="w-px-30 h-px-40"
|
|
:src="`/img/mbti/${selected.toLowerCase()}.png`"
|
|
alt="MBTI image"/>
|
|
</div>
|
|
<div v-if="isAlert" class="invalid-feedback">{{ title }}을 확인해주세요.</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { computed, ref, watch } from 'vue';
|
|
|
|
const props = defineProps({
|
|
title: {
|
|
type: String,
|
|
default: '라벨',
|
|
required: true,
|
|
},
|
|
name: {
|
|
type: String,
|
|
default: 'nameplz',
|
|
required: true,
|
|
},
|
|
isEssential: {
|
|
type: Boolean,
|
|
default: false,
|
|
required: false,
|
|
},
|
|
data: {
|
|
type: Array,
|
|
default: [],
|
|
required: true,
|
|
},
|
|
value: {
|
|
type: [String, Number],
|
|
default: '0',
|
|
require: false,
|
|
},
|
|
isAlert: {
|
|
type: Boolean,
|
|
default: false,
|
|
required: false,
|
|
},
|
|
isLabel: {
|
|
type: Boolean,
|
|
default: true,
|
|
required: false,
|
|
},
|
|
isRow: {
|
|
type: Boolean,
|
|
default: true,
|
|
required: false,
|
|
},
|
|
isBtn: {
|
|
type: Boolean,
|
|
default: false,
|
|
required: false,
|
|
},
|
|
isCommon: {
|
|
type: Boolean,
|
|
default: false,
|
|
required: false,
|
|
},
|
|
disabled: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
isColor: {
|
|
type: Boolean,
|
|
default: false,
|
|
required: false,
|
|
},
|
|
isMbti: {
|
|
type: Boolean,
|
|
default: false,
|
|
required: false,
|
|
},
|
|
});
|
|
|
|
const emit = defineEmits(['update:data', 'blur']);
|
|
const selectData = ref(props.value);
|
|
|
|
// props.value의 변경을 감지하는 watch 추가
|
|
watch(() => props.value, (newValue) => {
|
|
selectData.value = newValue;
|
|
}, { immediate: true });
|
|
|
|
// data 변경 감지 수정
|
|
watch(() => props.data, (newData) => {
|
|
if (props.isCommon && newData.length > 0) {
|
|
// value prop이 '0'(기본값)일 때만 첫번째 아이템 선택
|
|
if (props.value === '0') {
|
|
selectData.value = newData[0].value;
|
|
emit('update:data', selectData.value);
|
|
|
|
if (props.isColor) {
|
|
emit('blur');
|
|
}
|
|
}
|
|
}
|
|
}, { immediate: true });
|
|
|
|
// selectData 변경 감지
|
|
watch(selectData, (newValue) => {
|
|
emit('update:data', newValue);
|
|
});
|
|
|
|
|
|
const selected = computed(() => {
|
|
const selectedItem = props.data.find(item =>
|
|
props.isCommon ? item.value === selectData.value : props.data.indexOf(item) === selectData.value
|
|
);
|
|
return selectedItem ? selectedItem.label : null;
|
|
});
|
|
|
|
</script>
|