Vue+ts 自定义select组件,返回选中的元素

Vue+ts 自定义select组件,返回选中的元素

自定义子组件selecTemp

// SelectTemp.Data 参数类型
export interface SelectData {
    selectOption: any[], // 下拉框选项
    type: string, // select类型,主要用来区分不同样式
    labelTxt?: string, // 是否显示左侧的label
    defaultValue?: number | null // 默认值
}

在这里插入图片描述
这种样式的select,type为‘label’,labelText为显示的label内容
{ type: 'label', labelTxt: '所属管廊' }
在这里插入图片描述
这种样式的select,type为‘label’,labelText为空
{ type: 'border', labelTxt: '所属管廊' }
在这里插入图片描述
这种样式的select,type为‘label’,labelText为空
{ type: 'solid', labelTxt: '所属管廊' }

<template>
    <div class="SelectTemp-wrap" :type="data.type">
        <div class="select-wrap" :class="[data.type === 'solid' ? 'solid-select' : data.type === 'border' ? 'border-select' : 'label-selct']">
        	<!-- 只有当type为label的时候,才显示 -->
            <div class="label-wrap" v-show="data.type === 'label'">{{data.labelTxt}}</div>
            <div class="value-wrap">
                <input class="choosed-li" v-model="value" readonly @click="isShowUL = !isShowUL"/>
                <!-- 下拉列表展开收起动画  -->
                <transition name="draw">
                    <ul class="ul-box" v-if="isShowUL">
                        <li v-if="isShowUL" class="li-box" v-for="(item, index) in data.selectOption" :key="index" @click="choosedLi(item)">{{item.name}}</li>
                    </ul>
                </transition>
            </div>
            <div class="icon" @click="this.isShowUL = !this.isShowUL">
                <div class="triangle"></div>
            </div>
        </div>
    </div>
</template>
<script lang="ts">
    import { Component, Vue, Prop, Emit, Watch } from "vue-property-decorator";
    import { SelectData } from '@/types/components/selectTemp.interface'

    @Component({})
    export default class About extends Vue {
        // prop
        @Prop({
            required: false,
            default: {}
        }) data!: SelectData

        isShowUL: boolean = false

        value: any = ''

        choosedItem: any = ''

        @Watch('data.selectOption')
        watchData(newVal: any, oldVal: any) {
            if (newVal.length !== 0) {
                if ((this.data as SelectData).defaultValue !== undefined) {
                    newVal.forEach((item: any) => {
                        if(item.id === this.data.defaultValue){
                            this.choosedLi(item)
                        }
                    })
                }
            }
        }
		// 将选中的option传给父组件
        @Emit('on-change')
        send(choosedItem: any) {}

        mounted() {
        	// 是否显示默认值
            if (this.data.defaultValue !== undefined) {
                this.data.selectOption.forEach((option: any) => {
                    if (option.id === this.data.defaultValue) {
                        this.choosedLi(option)
                    }
                })
            }
            // 点击非select区域,隐藏下拉框
            document.body.addEventListener('click', (e) => {
                if ((e.target as any).className !== 'choosed-li' && 
                    (e.target as any).className !== 'triangle' &&
                    (e.target as any).className !== 'icon'
                ) {
                    this.isShowUL = false
                }
            })
        }
		// 选择option、
        choosedLi(item: any) {
            this.isShowUL = false
            this.value = item.name
            this.choosedItem = item
            
            this.send(this.choosedItem)
        }
    }
</script>
<style lang="less">
    .SelectTemp-wrap {
        position: absolute;
        z-index: 9;
        .select-wrap {
            .choosed-li,
            .icon {
                display: inline-block;
                vertical-align: top;

                :hover {
                    cursor: pointer;
                }
            }
            .value-wrap {
                display: inline-block;
                vertical-align: top;
            }

            .choosed-li {
                min-width: 120px;
                background-color: #474747;
                outline: none;
                padding: 4px 7px;
                border-radius: 0;
                border-top-left-radius: 4px;
                border-bottom-left-radius: 4px;
                border: none;
                height: 20px;
                color: @base-black-color5;
                width: 120px;
                text-align: center;
            }
            .choosed-li:hover {
                border: none;
                cursor: pointer;
            }
            .choosed-li:focus {
                outline: none;
                border: none;
                box-shadow: 0 0 0 2px transparent;
            }

            .icon {
                width: 20px;
                height: 20px;
                background: #474747;
                margin-left: 5px;
                border-top-right-radius: 4px;
                border-bottom-right-radius: 4px;
                display: inline-block;

                .triangle {
                    width: 0;
                    height: 0;
                    border-width: 7px;
                    border-color: @base-black-color5 transparent transparent transparent;
                    border-style: solid dashed dashed dashed;
                    border-radius: 4px;
                    margin-top: 6px;
                    margin-left: 2px;
                }
            }

            .ul-box {
                z-index: 999999;
                background: #474747;
                margin-top: 3px;
                width: 120px;
                border-radius: 4px;
                max-height: 200px;
                overflow-y: hidden;
                .li-box {
                    line-height: 1.5;
                    padding: 2px 7px;
                    cursor: pointer;
                }
            }

            .draw-enter-active, .draw-leave-active {
                transition: max-height .4s ease;
            }
            .draw-enter, .draw-leave-to {
                max-height: 0;
            }

            .ul-box::-webkit-scrollbar {
                width: 4px;
                height: 4px;
                overflow-x: hidden;
                overflow-y: auto;
            }

            .ul-box::-webkit-scrollbar-thumb {
                border-radius: 5px;
                box-shadow: inset 0 0 5px rgb(27, 102, 207);
                background: rgba(0, 0, 0, 0.2)
            }

            .ul-box::-webkit-scrollbar-track {
                border-radius: 4px;
                box-shadow: inset 0 0 5px rgb(235, 227, 235);
                background: rgba(0, 0, 0, 0.1)
            }
        }

        .border-select.select-wrap {
            .choosed-li {
                border: 1px solid #797979;
            }
            .icon {
                border: 1px solid #797979;
            }
        }

        .label-selct.select-wrap {
            .label-wrap {
                background: #323A43;
                border-top-left-radius: 6px;
                border-bottom-left-radius: 6px;
                display: inline-block;
                padding: 7px 14px;
                margin-right: 5px;
            }
            .choosed-li {
                border-radius: 0;
                background-color: #323A43;
                height: 32px;
            }

            .icon {
                background-color: #323A43;
                height: 32px;
                width: 32px;
                border-top-right-radius: 4px;
                border-bottom-right-radius: 4px;

                .triangle {
                    border-width: 8px;
                    border-color: @base-black-color5 transparent transparent transparent;
                    border-style: solid dashed dashed dashed;
                    border-radius: 4px;
                    margin-top: 13px;
                    margin-left: 8px;
                }
            }

            .ul-box {
                background-color: #323A43;
            }
        }
    }
</style>

父组件使用select

<template>
	<!--  getTunneld 不可以加写成getTunneld() -->
	<SelectTemp class="select-temp-wrap" :data="tunnelSelect" @on-change="getTunnelId"/>
</template>

import { Component, Vue } from 'vue-property-decorator'
import SelectTemp from '@/components/common/selectTemp/selectTemp.vue'
import { SelectData } from '@/types/components/selectTemp.interface'

@Component({
    components: { SelectTemp }
})
export default class About extends Vue {
	tunnelSelect: SelectData = {
        selectOption: [
        	{ id: 1, name: '古城大街' },
        	{ id: 2, name: '实验路' },
        	{ id: 3, name: '经二路' },
        	{ id: 4, name: '经三路' },
        	{ id: 5, name: '纬三路' }
        ],
        type: 'label',
        labelTxt: '管廊',
        defaultValue: 0
    }
	// choosedItem由子组件传给父组件
	getTunnelId(choosedItem: any) {
        this.conditions.tunnelId = choosedItem.id
    }
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值