IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> 手写Vue个人组件库———fl-Select -> 正文阅读

[JavaScript知识库]手写Vue个人组件库———fl-Select

接上文,封装了个人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>

## 有禁用选项

![在这里插入图片描述](https://img-blog.csdnimg.cn/20210714215416489.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQ2OTk1ODY0,size_16,color_FFFFFF,t_70#pic_center)



在`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`中支持。

![在这里插入图片描述](https://img-blog.csdnimg.cn/20210714220141702.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQ2OTk1ODY0,size_16,color_FFFFFF,t_70)


为`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————
dataSourceselect数据源Array多选型/单选型——
disabled禁用选项booleantrue/falsefalse
clearable可清空选中项booleantrue/falsefalse
isCheckSelect开启多选booleantrue/falsefalse
optionGroup开启分组booleantrue/falsefalse
avaSearch开启搜索booleantrue/falsefalse
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:[],      //select多选列表
                isUp: false,                //展开状态
                searchText:'',              //搜索文本
            }
        },
        methods: {
            toggleOption() {        //select展开收起切换
                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){           //选中option
                this.selectedValue = item.value
                this.$emit('input',this.selectedValue)
                this.isUp = false
                this.$emit('handleClick',this.selectedValue)
            },
            checkedOption(item){           //多选选中option
                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){         //移除多选option
                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(){        //是否为分组select
                return this.$attrs.optionGroup == '' ? true : false
            },
            isCheckSelect(){        //是否为多选select
                return this.$attrs.isCheckSelect == '' ? true : false
            },
            optionDataSource(){         //经过搜索过滤后的列表
                if(this.$attrs.avaSearch == ''){
                    if(this.selectedValue == "请选择") return this.dataSource       //请选择,默认全部展示
                    if(this.$attrs.optionGroup == ''){                  //分组select的过滤
                        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{                      //单选select的过滤
                        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>
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-07-15 16:04:45  更:2021-07-15 16:04:56 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年3日历 -2025/3/29 1:14:16-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码