VUE3 cascader级联 组件 黑白皮肤

本组件适用于公司项目,提供组件代码为开发者提供思路进而可进行开发 Tree 树形控件 等递归组件

案例:

 代码部分: index.vue

<template>
    <div v-clickoutside="clickOutside" class="cascader-box" :class="`cascader-${props.theme}  cascader-${props.size}`">
        <div  ref="headerSelectRef" class="header-box">
            <div class="header-type-one" :class="{'active': isShowList}" :style="{'width':width,'height':inputHeight,'padding-left': selectDataTitle.length>0 && !isAllCheackboxed ? '6px' : ''}" @click="showCascaderList">
                <div class="content-flex-shink">
                    <template v-if="selectType == '0'">
                        <span v-if="selectDataTitle.length<=0" class="title">{{ placeholder }}</span>
                        <span v-else-if="!isAllCheackboxed" class="select-title">
                            <span ref="selectName" class="select-name">
                                <span>{{selectDataTitle[0][label]}}</span>
                            </span>
                            <span v-show="selectDataTitle.length - 1 > 0" ref="selectNumber" class="select-number">
                                <span class="add-font">+</span><span>{{selectDataTitle.length - 1}}</span>
                            </span>
                        </span>
                        <span v-else class="select-title">
                            <span>{{props.defaultAllName}}</span>
                        </span>
                    </template>
                    <template v-if="selectType == '1'">
                        <span v-if="selectDataTitle.length<=0" class="title">{{ placeholder }}</span>
                        <span v-else-if="!isAllCheackboxed" class="select-title">
                            <span class="select-name-2">
                                <span class="show-str-content">{{ selectTypeDataType1 }}</span>
                                <span class="clear-icon-type1" @click.stop="clearSelect"></span>
                            </span>
                        </span>
                        <span v-else class="select-title">
                            <span>{{props.defaultAllName}}</span>
                        </span>
                    </template>
                   
                </div>
                <div class="cascader-select-arrow" :class="{'activeList': isShowList}"></div>
            </div>
        </div>
        <div v-show="isShowList" ref="emListPopper" class="list-select-box">
            <cascaderNode
               ref="cascaderNodeRef"
               :nodes="nodes"
               :props="props"
               :child-name="childName"
               :label="label"
               :level="0"
               :changefunction="changeCheackBox"
            ></cascaderNode>
        </div>
    </div>
</template>

<script setup  lang="ts"> 
import vClickoutside from '../../../directives/clickoutside'
import _ from 'lodash';
import {ref,watch,nextTick} from 'vue';
import { createPopper, PositioningStrategy } from '@popperjs/core';
import cascaderNode from './cascader-node.vue';
const EMSetting = {
     debounce:(
          function () {
               let t:any = null;
               return  (fn:Function, delay:number)=>{
               if (t !== null) {
                    clearTimeout(t)
               }
               t = setTimeout(() => {
                    fn()
               }, delay);
               }
          }
     )()
}
interface item {
  [key: string]: string | boolean | any;
}
interface IProps {
    theme?:string;
    dataType?: string;
    strategy?: string,
    selectType?: string;
    width?: string;
    inputHeight?: string;
    height?:string;
    liWidth?:string;
    size?:string;
    nodes?: item[];
    isCheckAll?: boolean;
    field?: string;
    childName?: string;
    label?: string;
    defaultAllName?: string;
    placeholder?: string;
    hoverTitle?: boolean;
    isShowAllRow?: boolean;
    asyncRequestFunction?:Function;
    isResSelected?: boolean;
    onlyShowLastNode?: boolean;
    isCloseSubmit?: boolean;
}
let props = withDefaults(defineProps<IProps>(), {
    theme:'white', // white 白色(默认) black黑色
    dataType:'all', // 传入数据类型 all 全部数据(默认值) async异步数据
    strategy: 'absolute', // popper定位
    selectType: '1', // 0 名字 剩余显示 + n(默认0) 1 名字累加
    width: '130px', // 选择框宽度
    inputHeight: '', // 选择框高度度
    height: '200px', // 选项高度  大屏默认 200px  小屏 180px 超出加滚动条
    liWidth:'130px', // 级联内容选项列宽
    size: 'large', //  large  small
    nodes: () => { return [];}, // 数据
    isCheckAll: false, // 是否勾选所有
    field: '', // 返回数据code key
    childName: 'children', // 子级节点名字
    label: 'name', // 显示字段key
    defaultAllName:'全部', // 选项全部,和选择结果全部 更改名字
    placeholder: '请选择', // 选择框默认显示 默认显示
    hoverTitle: true, // 移动上去是否显示提示
    isShowAllRow: true ,// 是否(显示勾选项中 全部 )
    asyncRequestFunction: undefined,  // 异步请求节点 传入回调方法
    isResSelected: false, // 是否返回处理之后的勾选的结果  以二维数组进行返回
    isCloseSubmit: true,  // 是否关闭提交数据
    onlyShowLastNode: false  // 是否只返回最后一层数据
})
const emitEvent = defineEmits(['submitCascader','emitClearSelect'])   //  submitCascader 通知数据  emitClearSelect 清空时候通知
let isShowList = ref<boolean>(false)  // 下拉项显示状态
let cheackboxedArray = ref<any[]>([]) // 选中的数据
let isAllCheackboxed = ref<boolean>(false) // 全部选中  状态值
let selectDataTitle = ref<any[]>([])  // 选择框展示的勾选数据
let selectTypeDataType1 = ref<string>('')  // selectType 展示类型为1情况下
let cascaderNodeRef = ref()  // 组件 ref
let popperInstance = ref()   // popper 实例

let headerSelectRef = ref<HTMLElement | null>(null);
let emListPopper = ref<HTMLElement | null>(null);
const popperEvent = ()=>{
    popperInstance.value = createPopper(headerSelectRef.value as HTMLElement, emListPopper.value as HTMLElement, {
        //位置:从下面开始
        placement: 'bottom-start',
        modifiers: [
            {
                name: 'offset',
                options: {
                    // xy为左右和上下的offset
                    offset: [0, 8]
                }
            },
            {
                name: 'preventOverflow',
                options: {
                    mainAxis: false
                }
            }
        ],
        strategy: props.strategy as PositioningStrategy

    });
}
// 勾选改变触发 进行勾选项实时显示
const changeCheackBox = (isEmit:boolean)=>{
    EMSetting.debounce(()=>{
        cheackboxedArray.value = []
        for (let i = 0; i < props.nodes.length; i++) {
            let currentData = props.nodes[i];
            if(!cheackboxedArray.value[0]){
                cheackboxedArray.value[0] = []
            }
            if (['1','2'].includes(currentData.selectType)) {
                if(currentData.selectType == '2') {
                    if(props.onlyShowLastNode) {
                        if(props.dataType == 'async') {
                            if(!currentData.isShowMore) {
                                cheackboxedArray.value[0].push(currentData)
                            }
                        }else if(!currentData[props.childName] || currentData[props.childName].length <= 0 ) {
                            cheackboxedArray.value[0].push(currentData)
                        }
                    }else{
                        cheackboxedArray.value[0].push(currentData)
                    }
                    
                }
                if(currentData[props.childName] && currentData[props.childName].length > 0) {
                    findCheackBoxed(currentData[props.childName],1)
                }
            }

            
        }

        if(props.nodes.length == cheackboxedArray.value[0].length) {
            isAllCheackboxed.value = true
        }else{
            isAllCheackboxed.value = false
        }
        selectDataTitle.value = _.cloneDeep(cheackboxedArray.value.flat())
        handleDataEvent(isEmit)
    },200)
    
}
interface SendData {
    [key: string]: string | boolean | any;
}
let sendData = ref<SendData>(
    {
        data: [], // 勾选数据
        isAll: isAllCheackboxed.value  // 是否全部勾选
    }
)
// 显示下拉项 更新下拉项位置
const showCascaderList = ()=>{
    isShowList.value = true
    nextTick(()=>{
        popperEvent()
    })
}
// 点击其它区域关闭下拉项
const clickOutside = ()=>{
    isShowList.value = false
    if(props.isCloseSubmit) {
       emitEvent('submitCascader',sendData.value)
    }
}
// 处理勾选数据,得到勾选项
const handleDataEvent = (isEmit:boolean)=>{
    if(props.isResSelected) {
        if(props.onlyShowLastNode) {
            if(props.field) {
                let flatArray =  cheackboxedArray.value.flat().map(item=>{
                    return item[props.field]
                })
                sendData.value.data = flatArray
            }else{
                let flatArray =  cheackboxedArray.value.flat()
                sendData.value.data = flatArray
            }
        }else{
            if(props.field) {
                for (let i = 0; i < cheackboxedArray.value.length; i++) {
                        for (let j = 0; j < cheackboxedArray.value[i].length; j++) {
                            if(!sendData.value.data[i]) {
                                sendData.value.data[i] = []
                            }
                            sendData.value.data[i].push(cheackboxedArray.value[i][j][props.field])
                        }
                }
            }else{
                sendData.value.data = cheackboxedArray.value
            } 
        }
    }else{
        sendData.value.data = props.nodes
    }

    if(!props.isCloseSubmit || isEmit) {
       emitEvent('submitCascader',sendData.value)
    }
}
const findCheackBoxed = (data:any,index:number)=>{
    if(!cheackboxedArray.value[index]){
        cheackboxedArray.value[index] = []
    }
    for (let i = 0; i < data.length; i++) {
        let currentData = data[i];
        if (['1','2'].includes(currentData.selectType)) {
            if(currentData.selectType == '2') {
                if(props.onlyShowLastNode) {
                    if(props.dataType == 'async') {
                        if(!currentData.isShowMore) {
                            cheackboxedArray.value[index].push(currentData)
                        }
                    }else if(!currentData[props.childName] || currentData[props.childName].length <= 0 ) {
                        cheackboxedArray.value[index].push(currentData)
                    }
                }else{
                    cheackboxedArray.value[index].push(currentData)
                }
            }

            if(currentData[props.childName] && currentData[props.childName].length > 0) {
                findCheackBoxed(currentData[props.childName],index+1)
            }
        }
        
        
    }
}

// 清空勾选
const clearSelect = ()=>{
    updataListState('0')
    emitEvent('emitClearSelect')
}
// 全部选中
const checkAllFunction = ()=>{
    updataListState('2')
}
// 更新勾选状态
const updataListState = (state:string)=>{
    if(cascaderNodeRef.value) {
        cascaderNodeRef.value.cheackAllEvent(state)
    }
}
// 设置初始勾选  用于外部调用初始化勾选项
const setInitCheckState = ()=>{
    //  true 用于传入初始化勾选时候通知勾选数据
    changeCheackBox(true)
}
// 监听结果展示选中展示项
let selectName = ref()
let selectNumber = ref()
watch(selectDataTitle,()=>{
    if(props.selectType == '0' && selectDataTitle.value.length > 0 && !isAllCheackboxed.value) {
        nextTick(()=>{
            let widthVal =  selectNumber.value?.clientWidth
            selectName.value.style.width = `calc(100% - ${widthVal}px - 18px)`
        })
       
    }

    if(props.selectType == '1' && selectDataTitle.value.length > 0 && !isAllCheackboxed.value) {
        nextTick(()=>{
            let nameArray:string[] = []
            selectDataTitle.value.map(item=>{
                nameArray.push(item[props.label]) 
            })
            selectTypeDataType1.value = nameArray.join(',')
        })
    }
})

watch(()=>props.isCheckAll,()=>{
    if(props.isCheckAll) {
        nextTick(()=>{
            checkAllFunction()
        })
    }
},{
   immediate: true 
})
// 监听配置改变更新 popper
watch([
    ()=>props.width,
    ()=>props.inputHeight,
    ()=>props.height,
    ()=>props.liWidth,
    ()=>props.size
],()=>{
    nextTick(()=>{
        if(isShowList.value) {
            popperEvent()
        }
    })
})
defineExpose({
    clearSelect, // 清空所有
    checkAllFunction, // 选中所有
    setInitCheckState  // s设置初始值
})
</script>

<style lang="scss" scoped>
    @import "../style/index.scss";
</style>

递归子级代码:

<template>
    <div  class="cascader-node" :style="{'width':props.props.liWidth}"  :class="[level == 0 ? '':'otherDom']">
        <div class="content-box" :style="{'height':props.props.height}">
            <!--active 点击选择  -->
            <div v-if="level == 0 && props.props.isShowAllRow" class="list-box" :class="{'allCheackBox': isCheackBoxAll}" @click="cheackAllEvent('')">
                <div class="left-content">
                    <div class="cheackbox" :class="{'active': isCheackBoxAll}"></div>
                    <div class="name" >{{ props.props.defaultAllName }}</div>
                </div>
            </div>
            <div v-for="(child,index) in nodes" :key="index" class="list-box" :class="{'active': activeIndex == index && child.isShowChild}">
                <div class="left-content" @click.stop="getSelectVal(child,index)">
                    <!-- active1 半选  active全选 -->
                    <div class="cheackbox" :class="getCurrentActiveName(child)" @click.stop="cheackboxEvent(child)"></div>
                    <div class="name" :title="props.props.hoverTitle ? child[props.label] : ''" :class="getCurrentFontColor(child,level)">{{child[props.label]}}</div>
                </div>
                <div v-if="(child[childName] && child[childName].length>0) || child.isShowMore" class="more" @click.stop="getSelectVal(child,index)"></div>
            </div>
        </div>
        <div v-if="activeIndex != null &&  nodes[activeIndex].isShowChild && nodes[activeIndex][childName] && nodes[activeIndex][childName].length > 0" class="children">
            <cascaderNode
                ref="cascaderNode"
                :nodes="nodes[activeIndex][childName]"
                :child-name="childName"
                :label="label"
                :level="level+1"
                :props="props.props"
                :changefunction="props.changefunction"
                @updataCheackBox="updataCheackBoxEvent"
            ></cascaderNode>
        </div>
        
    </div>
</template>

<script setup lang="ts">
import {computed, ref,nextTick} from 'vue';
interface item {
  [key: string]: string | boolean | any;
}
interface IProps {
    nodes?: item[];
    level?: number;
    childName?: string;
    label?: string,
    props?: any,
    changefunction?:Function
}
let props = withDefaults(defineProps<IProps>(), {
    nodes:() => {
        return [];
    },
    level:0,
    childName: 'children',
    label: 'name',
    props: ()=>{return {}},
    changefunction: ()=>{
        return ()=>{}
    }
})
const emitEvent = defineEmits(['updataCheackBox'])
let activeIndex = ref<number|null>(null)

// 选项点击事件
const getSelectVal = async (item:any,index:number)=>{
    if(props.props.dataType == 'async' && item.isShowMore && (!item[props.childName] || item[props.childName].length <= 0)) {
        // 异步数据,没有请求过情况
        let getCurrentChildrenNodes = await props.props.asyncRequestFunction(item)
        item[props.childName] = getCurrentChildrenNodes
        item.selectType = item.selectType ? item.selectType : '0'
        cheackboxEvent(item,item.selectType)
    }

    if((!item[props.childName] || item[props.childName].length <= 0) || !item.isShowMore) {
        cheackboxEvent(item)
    }
    activeIndex.value = index
    item.isShowChild = true
    for (let i = 0; i < props.nodes.length; i++) {
        if(props.nodes[i].isShowChild && i != index) {
            // eslint-disable-next-line vue/no-mutating-props
            props.nodes[i].isShowChild = false
            childStatus(props.nodes[i])
        }
        
    }
    nextTick(()=>{
        let boxEle = document.querySelector('.list-select-box') as HTMLElement 
        let widthVal = parseFloat(props.props.liWidth)
        if(boxEle.querySelectorAll('.children') && boxEle.querySelectorAll('.children').length > 0) {
            let lengthVal = boxEle.querySelectorAll('.children').length
            boxEle.style.width = (lengthVal+1)*widthVal + 'px'
        }else{
            boxEle.style.width = widthVal + 'px'
        }
    })
    
}
const childStatus = (item:any)=>{
    if(!item[props.childName] || item[props.childName] <= 0) {
        return 
    }

    for (let i = 0; i < item[props.childName].length; i++) {
        let itemChild = item[props.childName][i]
        if(itemChild.isShowChild) {
            itemChild.isShowChild = false
            childStatus(itemChild)
            break
        }

        
    }
}

// 选中  半选 不选 图标 class
const getCurrentActiveName = (item:any)=>{
    let classActiveName:String = ''
    switch (item.selectType) {
        case '0':
            classActiveName = ''
            break;
        case '1':
            classActiveName = 'active1'
            break;
        case '2':
            classActiveName = 'active'
            break;
        default:
            break;
    }
    return classActiveName
}
// 处理最后一层 选中 时候 文字高亮
const getCurrentFontColor = (item:any,level:number)=>{
    if(level>0 && (!item[props.childName] || item[props.childName].length<=0) && item.selectType == '2') {
        return 'activeName'
    }
}
// 勾选事件
const cheackboxEvent = (item:any,setSelectType?:string)=>{
    if(setSelectType) {
        item.selectType = setSelectType
    }else{

        item.selectType = item.selectType == '2' ? '0' : '2'
    }
    // 通知子级
    if(item[props.childName] && item[props.childName].length > 0) {
        for (let i = 0; i < item[props.childName].length; i++) {
            item[props.childName][i].selectType =  item.selectType
            mapActiveSate(item)
            break
        }
    }

    // 通知父级

    emitEvent('updataCheackBox',props.nodes)

    // 通知勾选触发了
    nextTick(()=>{
        // 勾选后通知改变,异步请求时候非勾选情况下需要通知,因 可能节点勾选 子节点需要进行勾选上
        if(!setSelectType || setSelectType != '0') {
            props.changefunction()
        }
        
    })
}
const mapActiveSate = (item:any)=>{
    if(item[props.childName] && item[props.childName].length > 0) {
        for (let i = 0; i < item[props.childName].length; i++) {
            item[props.childName][i].selectType =  item.selectType
            mapActiveSate(item[props.childName][i])
        }
    }
    
}

const updataCheackBoxEvent = (data:any)=>{
    let isChildrenAllActive = data.every((v:any)=>{
       return  v.selectType == '2'
    })
    let isChildrenSomeActive = data.some((v:any)=>{
       return  v.selectType == '2' || v.selectType == '1'
    })
    if(activeIndex.value != null) {
        if(isChildrenAllActive) {
            // eslint-disable-next-line vue/no-mutating-props
            props.nodes[activeIndex.value].selectType = '2'
        }else{
            if(isChildrenSomeActive) {
                // eslint-disable-next-line vue/no-mutating-props
                props.nodes[activeIndex.value].selectType = '1'
            }else{
                // eslint-disable-next-line vue/no-mutating-props
                props.nodes[activeIndex.value].selectType = '0'
            }
        }
    }

    emitEvent('updataCheackBox',props.nodes)

}

// 全部功能
let isCheackBoxAll = computed(()=>{
    let isAllCheack = false
    if(props.level == 0) {
      isAllCheack =  props.nodes.every((item:any)=>{
            return item.selectType == '2'
        })
    }
    return isAllCheack
})
// 全部 点击事件
const cheackAllEvent = (state?:string)=>{
    let cheackBoxType;
    if(state) {
        cheackBoxType = state
    }else{
        cheackBoxType = isCheackBoxAll.value ? '0' : '2'
    }

    for (let i = 0; i < props.nodes.length; i++) {
        let currentVal = props.nodes[i]
        currentVal.selectType = cheackBoxType
        closeChildCheack(currentVal,cheackBoxType)
        
    }

    nextTick(()=>{
        props.changefunction()
    })
}
const closeChildCheack = (item:any,state:string)=>{
    if(!item[props.childName] || item[props.childName].length <= 0) {
        item.selectType = state
        return
    }else{
        for (let i = 0; i < item[props.childName].length; i++) {
            let itemChild = item[props.childName][i]
            itemChild.selectType = state
            closeChildCheack(itemChild,state)
        }
    }
}
defineExpose({
    cheackAllEvent
})
</script>

<style lang="scss" scoped>
    @import "../style/index.scss";
</style>

scss:  组件图片使用时候可自己替换几个图片保证能组件能使用

.cascader-large {

    --font-size: 14px;

    --header-type-one-width: 130px;

    --header-type-one-height: 32px;

    --header-type-one-padding: 0px 8px 0px 12px;

    --list-box-padding: 0px 12px;

    --list-box-height: 28px;

    --cheackbox-width: 14px;

    --cheackbox-after-width: 6px;

    --cheackbox-after-height: 9px;

    --more-width:7px;

    --more-height:7px;

    --name-width: calc(100% - 14px);

    --select-name-height: 24px;

    --select-name-padding: 6px;

    --select-number-margin-left: 6px;

    --select-number-padding: 6px;

    --select-number-add-font: 0px;

    --select-number-add-font-width: 18px;

    --select-name-2-width: calc(100% - 12px);

    --clear-icon: 14px; // 删除按钮大小

    --selsect-clear-icon-position: 4px 50%; // 删除按钮位置

    --clear-icon-type1-min-width: 18px;

    --scrollbar-width: 8px;

    --scrollbar-height: 8px;

}



.cascader-small {

    --font-size: 12px;

    --header-type-one-width: 105px;

    --header-type-one-height: 24px;

    --header-type-one-padding: 0px 8px 0px 8px;

    --list-box-padding: 0px 8px;

    --list-box-height: 24px;

    --cheackbox-width: 12px;

    --cheackbox-after-width: 5px;

    --cheackbox-after-height: 8px;

    --more-width: 6px;

    --more-height: 6px;

    --name-width: calc(100% - 12px);

    --select-name-height: 18px;

    --select-name-padding: 4px;

    --select-number-margin-left: 4px;

    --select-number-padding: 4px;

    --select-number-add-font: -2px;

    --select-number-add-font-width: 15px;

    --select-name-2-width: calc(100% - 18px);

    --clear-icon: 10px;

    --selsect-clear-icon-position: 4px 50%;

    --clear-icon-type1-min-width: 14px;

    --scrollbar-width: 6px;

    --scrollbar-height: 6px;

}

.cascader-white {

    --header-type-one-bg: #f8f8f8;

    --content-flex-shink-title-color: #999999;

    --cascader-select-arrow-color: transparent #222 #222 transparent;

    --cascader-select-hover-border-color: #ff6600;

    --cascader-select-active-border-color: #ff6600;

    --cascader-select-active-bg: #ffffff;

    --cascader-node-bg: #ffffff;

    --cheackbox-bg: #ffffff;

    --cheackbox-border-color: #e1e1e1;

    --cheackbox-hover-color: #ff6600;

    --cheackbox-active-bg-color: #ff6600;

    --cheackbox-active-after-border-color: #ff6600;

    --cheackbox-active1-bg-color: #ff6600;

    --more-before-border-color: #222 #222 transparent transparent;

    --content-box-hover-bg: #fff6f0;

    --content-box-active-bg: #fff6f0;

    --content-box-active-name: #ff6600;

    --content-box-active-more: #ff6600 #ff6600 transparent transparent;

    --allCheackBox-name: #ff6600;

    --allCheackBox-more-before: #ff6600 #ff6600 transparent transparent;

    --otherDom-border-color: #e1e1e1;

    --left-content-name-color: #222222;

    --left-content-active-name-color: #ff6600;

    --scroll-bar-bg: #e1e1e1; // 滚动条颜色

    --clear-icon-url: url("../../images/white-clear-normal.svg") no-repeat; // 清除图标

    --clear-icon-hover-url: url("../../images/white-clear-hover.svg") no-repeat; // 清除图标hover

    --select-name-2-bg: #ececec;

    --select-name-2-border-color: #e1e1e1;

    --select-name-2-font-color: #222222;

}



.cascader-black {

    --header-type-one-bg: #3b3d41;

    --content-flex-shink-title-color: #999999;

    --cascader-select-arrow-color: transparent #fff #fff transparent;

    --cascader-select-hover-border-color: #00a0e9;

    --cascader-select-active-border-color: #00a0e9;

    --cascader-select-active-bg: #27282c;

    --cascader-node-bg: #3b3d41;

    --cheackbox-bg: #3b3d41;

    --cheackbox-border-color: #65686d;

    --cheackbox-hover-color: #00a0e9;

    --cheackbox-active-bg-color: #00a0e9;

    --cheackbox-active-after-border-color: #00a0e9;

    --cheackbox-active1-bg-color: #00a0e9;

    --more-before-border-color: #fff #fff transparent transparent;

    --content-box-hover-bg: #46484d;

    --content-box-active-bg: #46484d;

    --content-box-active-name: #00a0e9;

    --content-box-active-more: #00a0e9 #00a0e9 transparent transparent;

    --allCheackBox-name: #00a0e9;

    --allCheackBox-more-before: #00a0e9 #00a0e9 transparent transparent;

    --otherDom-border-color: #4c4e52;

    --left-content-name-color: #ffffff;

    --left-content-active-name-color: #00a0e9;

    --scroll-bar-bg: #595a5c; // 滚动条颜色

    --clear-icon-url: url("../../images/black-clear-normal.svg") no-repeat; // 清除图标

    --clear-icon-hover-url: url("../../images/black-clear-hover.svg") no-repeat; // 清除图标hover

    --select-name-2-bg: #4d4d4d;

    --select-name-2-border-color: #4d4d4d;

    --select-name-2-font-color: #ffffff;



}



.cascader-box {

    // 头部筛选框

    width: fit-content;



    .header-box {

        width: fit-content;



        .header-type-one {

            width: var(--header-type-one-width);

            height: var(--header-type-one-height);

            background-color: var(--header-type-one-bg);

            border-radius: 4px;

            display: flex;

            align-items: center;

            justify-content: space-between;

            padding: var(--header-type-one-padding);

            box-sizing: border-box;

            border: 1px solid var(--header-type-one-bg);



            .content-flex-shink {

                height: 100%;

                width: 100%;

                overflow: hidden;

                .title {

                    height: 100%;

                    display: flex;

                    align-items: center;

                    font-size: var(--font-size);

                    color: var(--content-flex-shink-title-color);

                }

                .select-title{

                    width: 100%;

                    height: 100%;

                    display: inline-block;

                    box-sizing: border-box;

                    display: flex;

                    align-items: center;

                    .select-name{

                        display: inline-block;

                        width: fit-content;

                        height: var(--select-name-height);

                        display: inline-block;

                        background-color: #ececec;

                        box-sizing: border-box;

                        border-radius: 4px;

                        border: solid 1px #e1e1e1;



                        padding: var(--select-name-padding);

                        display: flex;

                        align-items: center;

                        span {

                            width: 100%;

                            word-break: break-all;

                            white-space: nowrap;

                            overflow: hidden;

                            text-overflow: ellipsis;

                            font-size: var(--font-size);

                        }

                    }

                    .select-number{

                        display: inline-block;

                        margin-left: var(--select-number-margin-left);

                        min-width: 40px;

                        width: fit-content;

                        height: var(--select-name-height);

                        padding: var(--select-number-padding);

                        background-color: #ececec;

                        border-radius: 4px;

                        border: solid 1px #e1e1e1;

                        box-sizing: border-box;

                        display: flex;

                        align-items: center;

                        justify-content: center;

                        span{

                            width: 100%;

                            word-break: break-all;

                            white-space: nowrap;

                            overflow: hidden;

                            text-overflow: ellipsis;

                            font-size: var(--font-size);

                        }

                        .add-font{

                            width:var(--select-number-add-font-width);

                            font-size: var(--font-size);

                            margin-top: var(--select-number-add-font);

                        }

                    }

                    .select-name-2{

                        display: inline-block;

                        width: var(--select-name-2-width);

                        height: var(--select-name-height);

                        display: inline-block;

                        background-color: var(--select-name-2-bg);

                        box-sizing: border-box;

                        border-radius: 4px;

                        border: solid 1px var(--select-name-2-border-color);

                        padding: var(--select-name-padding);

                        display: flex;

                        align-items: center;

                        .show-str-content {

                            width: 100%;

                            word-break: break-all;

                            white-space: nowrap;

                            overflow: hidden;

                            text-overflow: ellipsis;

                            font-size: var(--font-size);

                            color: var(--select-name-2-font-color);

                        }

                        .clear-icon-type1{

                                width: 8%;

                                min-width: var(--clear-icon-type1-min-width);

                                height: inherit;

                                display: flex;

                                justify-content: center;

                                align-items: center;

                                padding: 0px 4px 0px 4px;

                                background: var(--clear-icon-url);

                                background-size: var(--clear-icon);

                                background-position: var(--selsect-clear-icon-position);

                           

                                &:hover {

                                    background: var(--clear-icon-hover-url);

                                    background-size: var(--clear-icon);

                                    background-position: var(--selsect-clear-icon-position);

                                }

                        }

                    }

                }

            }



            .cascader-select-arrow {

                position: relative;

                &::before {

                    content: "";

                    position: absolute;

                    width: 6px;

                    height: 6px;

                    right: 0;

                    top: 50%;

                    border-color: var(--cascader-select-arrow-color);

                    border-style: solid;

                    border-width: 1px;

                    -webkit-transform: rotate(45deg);

                    transform: rotate(45deg);

                    margin-top: -5px;

                    -webkit-transition: all .4s;

                    transition: all .4s;

                }



                &.activeList::before {

                    margin-top: -1px;

                    transform: rotate(-135deg);

                }

            }



            &:hover {

                cursor: pointer;

                border: solid 1px var(--cascader-select-hover-border-color);

            }



            &.active {

                border: solid 1px var(--cascader-select-active-border-color);

                background: var(--cascader-select-active-bg);

            }

        }

    }



    .list-select-box {

        position: relative;

        box-shadow: 0px 1px 12px 0px rgba(0, 0, 0, 0.1);

        z-index: 100;

        .cascader-node {

            display: flex;

            height: 100%;

            background-color: var(--cascader-node-bg);

            border-radius: 4px 0px 0px 4px;

            box-sizing: border-box;

            .content-box {

                width: 100%;

                height: 100%;

                flex-shrink: 0;

                padding: 4px 0px;

                overflow-y: auto;

           

                &::-webkit-scrollbar {

                    width: var(--scrollbar-width);

                    height: var(--scrollbar-height);

                }

           

                &::-webkit-scrollbar-thumb {

                    background: var(--scroll-bar-bg);

                    border-radius: 4px;

                }

           

                &::-webkit-scrollbar-track-piece {

                    background: transparent;

                }

                .list-box {

                    display: flex;

                    padding: var(--list-box-padding);

                    box-sizing: border-box;

                    height: var(--list-box-height);

                    align-items: center;

                    justify-content: space-between;



                    .left-content {

                        display: flex;

                        align-items: center;

                        width: calc(100% - 8px);



                        .cheackbox {

                            width: var(--cheackbox-width);

                            height: var(--cheackbox-width);

                            background-color: var(--cheackbox-bg);

                            border-radius: 2px;

                            border: solid 1px var(--cheackbox-border-color);



                            &:hover {

                                border: solid 1px var(--cheackbox-hover-color);

                            }



                            &.active {

                                position: relative;

                                border: solid 1px var(--cheackbox-hover-color);

                                background: var(--cheackbox-active-bg-color);



                                &::after {

                                    content: "";

                                    position: absolute;

                                    left: 50%;

                                    top: 0;

                                    width: var(--cheackbox-after-width);

                                    height: var(--cheackbox-after-height);

                                    border: solid 2px var(--cheackbox-active-after-border-color);

                                    border-bottom-color: #ffffff;

                                    border-right-color: #ffffff;

                                    -webkit-transform: translate(-50%, 0%) rotate(45deg);

                                    transform: translate(-50%, 0%) rotate(45deg);

                                }

                            }



                            &.active1 {

                                position: relative;



                                &::after {

                                    content: "";

                                    position: absolute;

                                    left: 50%;

                                    top: 50%;

                                    width: 7px;

                                    height: 6px;

                                    background-color: var(--cheackbox-active1-bg-color);

                                    border-radius: 1px;

                                    transform: translate(-50%, -50%);

                                    box-sizing: border-box;

                                }

                            }

                        }



                        .name {

                            padding-left: 4px;

                            white-space: nowrap;

                            overflow: hidden;

                            text-overflow: ellipsis;

                            width: var(--name-width);

                            font-size: var(--font-size);

                            color: var(--left-content-name-color);

                        }

                        .activeName{

                            color: var(--left-content-active-name-color);

                        }

                    }



                    .more {

                        position: relative;



                        &::before {

                            content: "";

                            position: absolute;

                            right: 8px;

                            top: 50%;

                            width: var(--more-width);

                            height: var(--more-height);

                            border-color: var(--more-before-border-color);

                            border-style: solid;

                            border-width: 1.5px;

                            box-sizing: border-box;

                            -webkit-transform: translate(50%, -50%) rotate(45deg);

                            transform: translate(50%, -50%) rotate(45deg);

                            z-index: 2;

                        }

                    }



                    &:hover {

                        background-color: var(--content-box-hover-bg);

                    }



                    &.active {

                        background-color: var(--content-box-active-bg);



                        .name {

                            color: var(--content-box-active-name);

                        }



                        .more {

                            &::before {

                                border-color: var(--content-box-active-more);

                            }

                        }

                    }

                }



                .allCheackBox {

                    .name {

                        color: var(--allCheackBox-name);

                        font-size: var(--font-size);

                    }



                    .more {

                        &::before {

                            border-color: var(--allCheackBox-more-before);

                        }

                    }

                }

            }



        }



        .otherDom {

            height: 100%;

            margin-top: 0px;

            border-radius: 0px;

            border-left: 1px solid var(--otherDom-border-color);

            box-sizing: border-box;

        }

    }

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值