# Custom select

Vue select кастомный компонент выбора

Компонент кастомный селект. Компонент разбит на 2 части. Родительский компонент в котором выводится дефолтное или выбранное значение, компонент списка значений. Значения передаются в виде массива. При клике на значение списка, бросается пользовательское событие, которое слушается в родительском элементе.

# Стэк технологий

  • Vue 2
  • CSS modules
  • Stylus

# Фичи

  • Пользовательские события
  • Вложенные компоненты

# Структура проекта

...
/src
	/assets
	/components
		ItemsList.vue
		Select.vue
		index.js
	App.vue
	main.js
...

# Select.vue

Родительский компонент. В него через пропсы передается массив значений. При клике с помощью директивы v-if показывается компонент списка. С помощью события @blur список скрывается при клике вне компонента.

<template>
	<div 
		:class="$style.select"
		@blur="open = false"
		:tabindex="tabindex"
	>
		<div 
			:class="{
				[$style.selected]: true,
				[$style.selectedOpen]: !open }"
			@click="open = !open">
			{{ selected || placeholder }}
		</div>
		<items-list-component
			:items="items"
			:isOpen="open"
			@changeOpen="setOpen"
			@changeSelect="setSelect"
		/>
	</div>
</template>

<script>
import ItemsListComponent from './ItemsList.vue';

export default {
	name: 'SelectComponent',
	props: {
		items: {
			type: Array,
			required: true
		},
		tabindex: {
			type: Number,
			required: false,
			default: 0
		}
	},
	data() {
		return {
			open: false,
			placeholder: 'Choose a song',
			selected: this.placeholder,
		}
	},
	components: {
		ItemsListComponent
	},
	methods: {
		setOpen(value) {
			this.open = value;
		},
		setSelect(value) {
			this.selected = value;
		}
	}
}
</script>

/src/components/Select.vue

# ItemsList.vue

Дочерний компонент списка значений. Из родительского компонента в него передается массив значений. Все элементы массива выводятся с помощью директивы v-for. При клике на одно из значений, бросается пользовательское событие с выбранным значением, которое в родительском подставляется в поле selected.

<template>
	<div 
		:class="{ 
			[$style.list]: true, 
		}"
		v-if="!isOpen"
	>
		<div 
			:class="$style.listItem"
			v-for="(item, i) of items" 
			:key="i"
			@click="changeOpen(); changeSelect($event)"
		>
			{{ item }}
		</div>
	</div>
</template>

<script>
export default {
	name: 'ItemsListComponent',
	props: {
		items: {
			type: Array,
			required: true
		},
		isOpen: {
			type: Boolean,
			default: false
		}
	},
	methods: {
		changeOpen() {
			this.$emit('changeOpen', !this.isOpen);
		},
		changeSelect(e) {
			this.$emit('changeSelect', e.target.innerText);
		}
	}
}
</script>

/src/components/ItemsList.vue

# Исходный код на GitHub

Vue Select (opens new window)