接上文,封装了个人Vue组件库的第一个组件——Input,源码附在了文章末尾,如下是文档使用说明
Select 选择器
当选项过多时,使用下拉菜单展示并选择内容。
基础用法
适用广泛的基础单选

v-model 的值为当前被选中的el-option 的 value 属性值
<template>
<fl-Select v-model = "value" :dataSource = "selectData"></fl-Select>
</template>
<script>
export default {
data() {
return {
dataSource:
[
{
label: 1,
value: "双皮奶",
},
{
label: 2,
value: "黄金糕",
},
{
label: 3,
value: "双黄蛋",
},
{
label: 4,
value: "鸡米花",
},
{
label: 5,
value: "双肉肠",
},
],
};
},
};
</script>
## 有禁用选项

在`dataSource`中设定`disabled`值为 true,即可禁用该选项。
数据改变视图。
```javascript
<template>
<fl-Select v-model = "value" :dataSource = "selectData"></fl-Select>
</template>
<script>
export default {
data() {
return {
dataSource:
[
{
label: 1,
value: "双皮奶",
},
{
label: 2,
value: "黄金糕",
disabled: true,
},
{
label: 3,
value: "双黄蛋",
},
{
label: 4,
value: "鸡米花",
disabled: true,
},
{
label: 5,
value: "双肉肠",
},
],
};
},
};
</script>
禁用状态
选择器不可用状态 
为fl-Select 设置disabled 属性,则整个选择器不可用
<template>
<fl-Select v-model = "value" :dataSource = "selectData" disabled></fl-Select>
</template>
<script>
export default {
data() {
return {
dataSource:
[
{
label: 1,
value: "双皮奶",
},
{
label: 2,
value: "黄金糕",
disabled: true,
},
{
label: 3,
value: "双黄蛋",
},
{
label: 4,
value: "鸡米花",
disabled: true,
},
{
label: 5,
value: "双肉肠",
},
],
};
},
};
</script>
可清空单选 / 多选
包含清空按钮,可将所有类型选择器都清空为初始状态

<template>
<fl-Select v-model = "value" :dataSource = "selectData" clearable></fl-Select>
</template>
<script>
export default {
data() {
return {
dataSource:
[
{
label: 1,
value: "双皮奶",
},
{
label: 2,
value: "黄金糕",
disabled: true,
},
{
label: 3,
value: "双黄蛋",
},
{
label: 4,
value: "鸡米花",
disabled: true,
},
{
label: 5,
value: "双肉肠",
},
],
};
},
};
</script>
基础多选
适用性较广的基础多选,用 Tag 展示已选项

为fl-Select 设置isCheckSelect 属性即可启用多选,此时v-model 绑定的将是使用’ , '所分割的多个选项值。
<template>
<fl-Select v-model = "value" :dataSource = "selectData" isCheckSelect></fl-Select>
</template>
<script>
export default {
data() {
return {
dataSource:
[
{
label: 1,
value: "双皮奶",
},
{
label: 2,
value: "黄金糕",
disabled: true,
},
{
label: 3,
value: "双黄蛋",
},
{
label: 4,
value: "鸡米花",
disabled: true,
},
{
label: 5,
value: "双肉肠",
},
],
};
},
};
</script>
自定义模板
可以展示第二个子选项备注在下拉列表的右侧。

你只需要做的是改造dataSource ,给每个选项对象添加title 属性即可。
<template>
<fl-Select v-model = "value" :dataSource = "selectData" isCheckSelect></fl-Select>
</template>
<script>
export default {
data() {
return {
dataSource:
[
{
label: 1,
value: "双皮奶",
},
{
label: 2,
value: "黄金糕",
title: "垃圾食品",
disabled: true,
},
{
label: 3,
value: "双黄蛋",
title: "垃圾食品",
},
{
label: 4,
value: "鸡米花",
disabled: true,
title: "油炸食品",
},
{
label: 5,
value: "双肉肠",
title: "民间小吃",
},
],
};
},
};
</script>
分组
多种分类进行分组展示

对fl-Select 配置optionGroup 后只需要对dataSource 进行改造即可实现分组效果。
<template>
<fl-Select v-model = "value" :dataSource = "selectData" isCheckSelect></fl-Select>
</template>
<script>
export default {
data() {
return {
selectData: [
{
menu: "食物",
data: [
{
label: 1,
value: "双皮奶",
title: "垃圾食品",
},
{
label: 2,
value: "黄金糕",
title: "垃圾食品",
disabled: true,
},
{
label: 3,
value: "大汉堡",
title: "垃圾食品",
},
{
label: 4,
value: "鸡米花",
title: "健康食品",
},
{
label: 5,
value: "大肉包",
},
{
label: 6,
value: "爆米花",
},
],
},
{
menu: "城市",
data: [
{
label: 1,
value: "苏州",
title: "人上人",
},
{
label: 2,
value: "南京",
title: "人上人",
disabled: true,
},
{
label: 3,
value: "上海",
title: "苏城后花园",
},
{
label: 4,
value: "新疆",
title: "人间天堂",
},
],
},
],
};
},
};
</script>
## 可搜索
可以利用搜索功能快速查找选项,仅在单选`select`中支持。

为`fl-Select`设置`avaSearch`属性即可启用搜索。
```javascript
<template>
<fl-Select v-model = "value" :dataSource = "selectData" avaSearch></fl-Select>
</template>
<script>
export default {
data() {
return {
dataSource:
[
{
label: 1,
value: "双皮奶",
},
{
label: 2,
value: "黄金糕",
title: "垃圾食品",
disabled: true,
},
{
label: 3,
value: "双黄蛋",
title: "垃圾食品",
},
{
label: 4,
value: "鸡米花",
disabled: true,
title: "油炸食品",
},
{
label: 5,
value: "双肉肠",
title: "民间小吃",
},
],
};
},
};
</script>
Attributes
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|
v-model | 绑定值 | string | —— | —— | dataSource | select数据源 | Array | 多选型/单选型 | —— | disabled | 禁用选项 | boolean | true/false | false | clearable | 可清空选中项 | boolean | true/false | false | isCheckSelect | 开启多选 | boolean | true/false | false | optionGroup | 开启分组 | boolean | true/false | false | avaSearch | 开启搜索 | boolean | true/false | false | handleClick | 选中选项后的回调,获取选中项值 | event | —— | —— |
源码:
<template>
<div>
<div class = "selectBox">
<!-- 基础单选select菜单 -->
<div class = "selectPar" @click = "toggleOption" v-if = "!isCheckSelect">
<input type = "text"
class = "select"
placeholder="请选择"
v-model = "selectedValue"
:style = "fontStyle"
:disabled = "$attrs.disabled == '' ? true : false"
:readonly = "$attrs.avaSearch == '' ? false : true"
@keyup="searchIng($event)">
<i class = "el-icon-arrow-down" :style = "iconStyle" v-if="!canClear"></i>
<i class = "el-icon-close" v-else @click = "clearOption"></i>
</div>
<!-- 多选select菜单 -->
<div class = "selectPar" @click = "toggleOption" v-if = "isCheckSelect">
<div class = "select" :style = "fontStyle">
<span v-if = "selectedValueGroup.length == 0">请选择</span>
<div class = "checkSelect" v-for = "item in selectedValueGroup" :key = "item">
{{item}}
<span @click.stop = "removeSelect(item)">x</span>
</div>
</div>
<i class = "el-icon-arrow-down" :style = "iconStyle" v-if="!canClear"></i>
<i class = "el-icon-close" v-else @click = "clearOption"></i>
</div>
<!-- 普通option下拉项 -->
<ul class = "optionList" ref = "optionList" :style = "selectStyle" v-if = "!isGroupSelect">
<li class = "option" v-for = "item in optionDataSource" :key = "item.label" @click = "isCheckSelect ? checkedOption(item) : selectedOption(item)" :style = "optionStyle(item)" :disabled = "item.disabled">
<span class = "value">{{item.value}}</span>
<span class = "title">{{item.title}}</span>
</li>
</ul>
<!-- 分组option下拉项 -->
<ul class = "optionList" ref = "optionList" :style = "selectStyle" v-if = "isGroupSelect">
<div class = "menuGroup" v-for = "item in optionDataSource" :key = "item.menu">
<span class = "title">{{item.menu}}</span>
<li class = "option" v-for = "item2 in item.data" :key = "item2.label" @click = "isCheckSelect ? checkedOption(item2) : selectedOption(item2)" :style = "optionStyle(item2)" :disabled = "item2.disabled">
<span class = "value">{{item2.value}}</span>
<span class = "title">{{item2.title}}</span>
</li>
</div>
</ul>
</div>
</div>
</template>
<script>
export default {
name:'fl-Select',
props: {
value: {
type: String,
},
dataSource: {
type: Array
}
},
data() {
return {
selectedValue:'',
selectedValueGroup:[],
isUp: false,
searchText:'',
}
},
methods: {
toggleOption() {
if(this.$attrs.disabled == '') return
this.isUp = !this.isUp
this.$refs.optionList.style.height = this.isUp ? "500px" : "0px"
this.$refs.optionList.style.opacity = this.isUp ? "1" : "0"
},
selectedOption(item){
this.selectedValue = item.value
this.$emit('input',this.selectedValue)
this.isUp = false
this.$emit('handleClick',this.selectedValue)
},
checkedOption(item){
if(item.disabled){
return
}
if(this.selectedValueGroup.indexOf(item.value) !== -1){
this.selectedValueGroup.splice(this.selectedValueGroup.indexOf(item.value),1)
}else{
this.selectedValueGroup.push(item.value)
}
this.$emit('input',this.selectedValueGroup.join(','))
this.$emit('handleClick',this.selectedValueGroup.join(','))
},
removeSelect(item){
var index = this.selectedValueGroup.indexOf(item)
this.selectedValueGroup.splice(index,1)
this.$emit('input',this.selectedValueGroup.join(','))
},
clearOption(){
if(this.isCheckSelect){
this.selectedValueGroup = []
}else{
this.selectedValue = ""
}
this.$emit('input','')
},
searchIng(e){
this.selectedValue = e.target.value
console.log(e.target.value)
}
},
computed: {
selectStyle() {
return this.isUp ? "height:500px;opacity:1;" : "height:0px;opacity:0;"
},
fontStyle(){
if(this.$attrs.disabled == ''){
return "color:#ccc;cursor:no-drop;background:rgb(236, 237, 241);"
}
if(this.isCheckSelect){
return this.selectedValueGroup.length > 0 ? "color:black" : "color:#ccc"
}
return this.selectedValue == "" ? "color:#ccc" : "color:black"
},
optionStyle(){
return (item) =>{
var returnStyle = ''
returnStyle = item.disabled ? "cursor:no-drop;color:#ccc;" : ""
if(returnStyle){
return returnStyle
}
if(this.isCheckSelect){
return this.selectedValueGroup.indexOf(item.value) !== -1 ? "color:rgb(52, 52, 236);background:rgb(236, 237, 241);font-weight:bold;" : "color:black"
}else{
return item.value == this.selectedValue ? "color:rgb(52, 52, 236);background:rgb(236, 237, 241);font-weight:bold;" : "color:black"
}
}
},
iconStyle(){
return this.isUp ? "transform: rotate(180deg)" : "transform: rotate(0deg)"
},
canClear(){
return (this.$attrs.clearable == '' && this.selectedValue !== "") || this.selectedValueGroup.length > 0
},
isGroupSelect(){
return this.$attrs.optionGroup == '' ? true : false
},
isCheckSelect(){
return this.$attrs.isCheckSelect == '' ? true : false
},
optionDataSource(){
if(this.$attrs.avaSearch == ''){
if(this.selectedValue == "请选择") return this.dataSource
if(this.$attrs.optionGroup == ''){
var newArr = [];
this.dataSource.forEach(item=>{
var arr = item.data.filter(item2=>{
return item2.value.includes(this.selectedValue)
})
if(arr.length !== 0){
newArr.push(
{
menu:item.menu,
data:arr
}
)
}
})
return newArr
}else{
return this.dataSource.filter(item=>{
return item.value.includes(this.selectedValue)
})
}
}
}
},
}
</script>
<style scoped>
.selectBox{
width:237px;
margin:30px 0 0 30px;
display:flex;
flex-direction: column;
}
.selectPar{
width:237px;
position: relative;
cursor: pointer;
}
.selectPar .select{
width:220px;
min-height:30px;
outline: none;
border:1px solid #ccc;
font-size:12px;
line-height:30px;
padding:5px 0 5px 15px;
border-radius: 5px;
transition:0.2s linear;
cursor: pointer;
user-select:none;
}
.checkSelect{
display: inline-block;
height:30px;
background: rgb(218, 218, 218);
color:rgb(151, 150, 150);
text-align: center;
margin-right:10px;
padding:0 5px;
margin-top:2px;
}
.checkSelect span{
display: inline-block;
border-radius: 50%;
background: rgb(54, 54, 54);
width:15px;
height:15px;
line-height: 12px;
color:#fff;
}
.selectPar i{
position: absolute;
right:10px;
top:10px;
transition:0.2s linear;
}
.select:hover{
border:1px solid black;
transform: rotate();
}
.select:focus{
border:1px solid rgb(52, 52, 236);
}
.optionList{
width:235px;
height:0px;
transition: 0.2s linear;
box-shadow:rgb(214, 214, 214) 2px 2px 2px;
border: 1px solid #ccc;
margin-top:5px;
border-radius: 5px;
overflow: auto;
overflow-x: hidden;
overflow-y:hidden;
}
.optionList:hover{
overflow-y:scroll;
}
.menuGroup .title{
margin-left:15px;
font-size:12px;
color:#ccc;
}
.menuGroup{
border-bottom:1px solid #ccc;
padding-bottom:15px;
margin:15px 10px;
box-sizing: border-box;
margin-top:10px;
}
.option{
width:200px;
height:30px;
line-height:30px;
padding:5px 10px 5px 15px;
cursor: pointer;
display: flex;
justify-content: space-between;
}
.option .title{
font-size:14px;
color:rgb(184, 184, 184);
margin-right:15px;
}
.option .value{
font-size:15px;
}
.option:hover{
background: rgb(236, 237, 241);
}
</style>
|