Основные возможности компонента Select:Если вариантов слишком много, используйте раскрывающееся меню для отображения и выбора содержимого.
- Двусторонняя привязка данных, как отображать выбранный элемент при изменении выпадающего списка;
- Различие между одиночным и множественным выбором и соответствующей обработкой.
1. Примеры
код
<fat-select v-model="inputValue">
<fat-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
>{{ item.label }}</fat-option>
</fat-select>
Адрес экземпляра:Выберите экземпляр
Кодовый адрес:Github UI-Library
2. Принцип
SelectБазовая структура компонента выглядит следующим образом
В основном его можно разделить на две части:
- Окно отображения: используется для отображения выбранных элементов, включая кнопку отмены;
- Раскрывающийся список: содержит выбранные выделенные элементы, отключенные элементы, параметры выбора по умолчанию и т. д., с операцией щелчка для выбора и повторного щелчка для отмены.
Поле дисплея с толстым выбором:
<template>
<div
:class="['select-wrapper', { 'is-disabled': disabled }]"
tabindex="0"
@click.stop="isOpen = !disabled && !isOpen"
@blur="handleBlur"
>
<div class="select-top-part">
<template v-if="!selectItems.length">
<span class="placeholder">{{ placeholder }}</span>
</template>
<template v-else>
<div>{{ selectItems[0].label }}</div>
</template>
</div>
<!-- 下拉框 -->
<div class="select-bottom-part" v-show="isOpen">
<slot></slot>
</div>
</div>
</template>
<script>
export default {
props: {
placeholder: { type: String, default: "请选择" },
optionKey: { type: String, default: "value" },
value: { type: [String, Object, Number, Array] }
},
model: {
prop: "value",
event: "input"
},
data() {
return {
isOpen: false,
selectValue: [],
selectItems: []
};
},
provide() {
return {
fatSelect: this
};
},
watch: {
value: {
handler(value) {
const { multiple } = this;
const init = value ? value : multiple ? [] : "";
this.selectValue = multiple ? [...init] : init;
},
immediate: true
},
selectValue: {
handler(value) {
this.selectItems = [];
}
}
},
methods: {
handleDelete(item) {
const { value } = item;
this.selectValue = this.selectValue.filter(item => item !== value);
this.$emit("input", this.selectValue);
this.$emit("change", this.selectValue);
},
handleBlur(event) {
this.isOpen = false;
this.$emit('blur', event);
}
...
}
};
</script>
использоватьtabIndexатрибут делает внешнийdivспособный вызватьblurсобытие и сворачивает раскрывающийся список, если он не в фокусе.
<div
:class="['select-wrapper', { 'is-disabled': disabled }]"
tabindex="0"
@click.stop="isOpen = !disabled && !isOpen"
@blur="handleBlur"
>
...
<!-- 下拉框 -->
<div class="select-bottom-part" v-show="isOpen">
<slot></slot>
</div>
</div>
handleBlur(event) {
this.isOpen = false;
this.$emit('blur', event);
}
Компонент реализует двустороннюю привязку данных, когдаv-modelПри изменении соответствующего значенияSelectЗначение компонента также изменяется, но выбранный элемент отображается в поле отображения.labelсвойство, поэтому значение будет выбраноselectValueи выбранные элементыselectItemsдифференцировать.
Настроить заодноv-modelсвязанные свойства во время мониторингаwatchСвязанныйvalueдетали следующим образом
model: {
prop: "value",
event: "input"
},
watch: {
value: {
handler(value) {
const { multiple } = this;
const init = value ? value : multiple ? [] : "";
this.selectValue = multiple ? [...init] : init;
},
immediate: true
}
}
использовать одновременноprovideВнедрите зависимость во все его раскрывающиеся списки для доступаselectValueа такжеselectItemsЖдатьpropа такжеdata.
provide() {
return {
fatSelect: this
};
}
По умолчаниюoptionKey: { type: String, default: "value" }В качестве уникального идентификатора раскрывающегося элемента используется значение по умолчанию value , которое также можно настроить.
раскрывающийся список толстых опций:
Используйте слот, чтобы вставить раскрывающийся списокSelectВ компоненте его конкретное определение выглядит следующим образом
<template>
<div
:class="['select-option-wrapper', { 'is-selected': isSelect }, { 'is-disabled': disabled }]"
@click.stop="handleClick"
>
<slot></slot>
</div>
</template>
<script>
export default {
props: {
value: { type: [Object, String, Number], required: true },
label: { type: String },
disabled: { type: Boolean, defa: false }
},
inject: ["fatSelect"],
computed: {
isSelect() {
const {
fatSelect: { optionKey, selectItems }
} = this;
const key = this[optionKey] || this.$attrs[optionKey];
return selectItems.find(item => item.key === key);
}
},
watch: {
["fatSelect.selectValue"]: {
handler(newValue) {
const {
value,
label,
fatSelect: { optionKey, multiple, selectValue }
} = this;
const key = this[optionKey] || this.$attrs[optionKey];
if (
newValue === value ||
(Array.isArray(newValue) && newValue.find(item => item === value))
) {
if (!multiple) {
this.fatSelect.selectItems = [
{
key,
label,
value
}
];
} else {
this.fatSelect.selectItems.push({
key,
label,
value
});
}
}
},
immediate: true
}
},
methods: {
...
}
};
</script>
использоватьinject: ["fatSelect"]поставить вышеprovideизSelectкомпонент вводится в текущую опцию,
пройти черезthis.fatSelectдля доступа к родительскому компонентуselectItemsчтобы определить, выбран ли текущий параметр.
isSelect() {
const {
fatSelect: { optionKey, selectItems }
} = this;
const key = this[optionKey] || this.$attrs[optionKey];
return selectItems.find(item => item.key === key);
}
При этом смотретьfatSelect.selectValueТо есть выбранное значение.Как было сказано ранее, этот компонент реализует двустороннюю привязку данных.Selectкомпонентыv-modelКогда связанное значение изменяется, его необходимо синхронизировать с раскрывающимся элементом.
["fatSelect.selectValue"]: {
handler(newValue) {
const {
value,
label,
fatSelect: { optionKey, multiple, selectValue }
} = this;
const key = this[optionKey] || this.$attrs[optionKey];
if (
newValue === value ||
(Array.isArray(newValue) && newValue.find(item => item === value))
) {
if (!multiple) {
this.fatSelect.selectItems = [
{
key,
label,
value
}
];
} else {
this.fatSelect.selectItems.push({
key,
label,
value
});
}
}
},
immediate: true
}
если соответствующийfatSelect.selectValueПри изменении необходимо судить о текущем вариантеoptionKeyВы вselectValue, если он существует, то будет
this.fatSelect.selectItems = [
{
key,
label,
value
}
];
3. Заключение
игнорируетсяSelectНекоторые детали компонента, такие как логика множественного выбора и одиночного выбора, сосредоточены на логике проектирования компонента и реализации привязки данных, а также обобщают некоторые проблемы, возникающие в реальном бизнесе.
Оригинальное заявление: Данная статья является оригинальной, при перепечатке просьба указывать источник.