When there are too many options, use the drop-down menu to display and select the content.
- Two-way data binding: How to display the selected item when the drop-down list changes;
- Single choice, multi – choice distinction, and corresponding processing.
Example 1.
code
<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>
Copy the code
Instance address: Select instance
Github UI-Library
Principle 2.
The basic structure of the Select component is as follows
It can be divided into two parts:
- Display box: used to show the selected items, including the cancel button;
- Drop-down box: contains selected highlights, disabled items, default selection options, etc., with click selected, click again to cancel the operation.
Fat-select display box:
<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>
<! -- Drop down box -->
<div class="select-bottom-part" v-show="isOpen">
<slot></slot>
</div>
</div>
</template>
<script>
export default {
props: {
placeholder: { type: String.default: "Please select" },
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>
Copy the code
Use the tabIndex attribute to make the outermost div trigger the blur event and collapse the dropdown if out of focus.
<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> </div> handleBlur(event) {this.isopen = false; this.$emit('blur', event); }Copy the code
The component implements bidirectional data binding. When the value corresponding to the V-Model changes, the value of the Select component also changes. However, the label attribute of the selected item is displayed in the display box, so the selected value selectValue is distinguished from the selected item selectItems.
At the same time, v-model attributes are configured and watch values are monitored as follows
model: {
prop: "value".event: "input"
},
watch: {
value: {
handler(value) {
const { multiple } = this;
const init = value ? value : multiple ? [] : "";
this.selectValue = multiple ? [...init] : init;
},
immediate: true}}Copy the code
It also uses provide to inject a dependency into all of its drop-down boxes to access prop and data such as selectValue and selectItems.
provide() {
return {
fatSelect: this
};
}
Copy the code
The default optionKey: {type: String, default: “value”} is the unique identifier of the drop-down item. The default value is value and can be customized.
Fat-option drop-down box:
Insert the drop-down box into the Select component using a slot, as defined below
<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>
Copy the code
Inject the Select component provided above into the current option with inject: [“fatSelect”]
FatSelect accesses the parent component’s selectItems to determine if the current option is selected.
isSelect() {
const {
fatSelect: { optionKey, selectItems }
} = this;
const key = this[optionKey] || this.$attrs[optionKey];
return selectItems.find(item= > item.key === key);
}
Copy the code
In addition, watch FatSelect. selectValue is also the selected value. As mentioned before, this component implements bidirectional binding of data. When the value of v-model binding of Select component changes, it needs to synchronize to the drop-down item.
["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
}
Copy the code
If fatSelectValue changes, check whether the current option’s optionKey is in the selectValue. If it is, it will
this.fatSelect.selectItems = [
{
key,
label,
value
}
];
Copy the code
Conclusion 3.
Some details of the Select component are ignored, such as the logic of multiple choices and single choices. The design logic of the component is highlighted, as well as the implementation of data binding, and some problems encountered in the actual business are summarized.
Original statement: This article is an original article, please indicate the source.