内容简介:当选项过多时,使用下拉菜单展示并选择内容。代码实例地址: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> 复制代码
实例地址:Select 实例
代码地址: Github UI-Library
2. 原理
Select组件的基本结构如下
主要可分为两个部分:
- 显示框:用来展示已经选中项,包含取消按钮;
- 下拉框:包含已选中的高亮项,禁用项,默认选择选项等,具备点击选中,再次点击取消的操作;
- 确保每个下拉项唯一,即使存在相同 label 的情况。
fat-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 ,也可自定义。
fat-option 下拉框:
利用插槽将下拉框插入 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); } 复制代码
同时watch 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 } ]; 复制代码
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 从零实现Vue的组件库(二)-Slider组件实现
- Vue自定义组件(简单实现一个自定义组件)
- 实现一个沙漏⏳组件
- angular 实现下拉列表组件
- 从零实现Vue的组件库(五)- Breadcrumb 实现
- 从零实现Vue的组件库(十二)- Table 实现
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Nature of Code
Daniel Shiffman / The Nature of Code / 2012-12-13 / GBP 19.95
How can we capture the unpredictable evolutionary and emergent properties of nature in software? How can understanding the mathematical principles behind our physical world help us to create digital w......一起来看看 《The Nature of Code》 这本书的介绍吧!