vue3+element-puls 自定义TreeSelect 树形选择单选

 组件使用方式

<treeSelectRadio v-model="value" :options="options"></treeSelectRadio>

treeSelectRadio组件代码

<template>
    <div class="tree_box">
        <el-select class="treeSelectRadio-select" v-model="select.value" clearable filterable ref="treeSelect"
            :placeholder="placeholder || '请选择'" :filter-method="selectFilter" @clear="clearAll">
            <el-option :value="select.currentNodeKey" :label="select.currentNodeLabel" class="treeSelectRadio-option-style"
                element-loading-background="rgba(255, 255, 255, 0.5)" v-loading="data.treeLoading"
                element-loading-text="loading">
                <el-scrollbar height="260px">
                    <div class="check-box">
                        <el-button text link :type="data.state === '' ? 'primary' : ''" :icon="Grid"
                            @click.stop="handleState('')">全部</el-button>
                        <el-button text link :type="data.state === 0 ? 'primary' : ''" :icon="Avatar"
                            @click.stop="handleState(0)">在职</el-button>
                        <el-button text link :type="data.state === 1 ? 'primary' : ''" :icon="Promotion"
                            @click.stop="handleState(1)">离职</el-button>
                    </div>
                    <el-tree id="tree_v2" ref="treeRef" accordion :data="data.options" :props="props.TreeProps"
                        :current-node-key="select.currentNodeKey" @node-click="nodeClick" :expand-on-click-node="false"
                        :filter-node-method="treeFilter" node-key="id"></el-tree>
                </el-scrollbar>
            </el-option>
        </el-select>
    </div>
</template>

<script setup>
import { nextTick, onMounted, reactive, ref, watch } from 'vue'
import { Avatar, Promotion, Grid } from '@element-plus/icons-vue'
import request from "@/utils/request"
const props = defineProps({
    TreeProps: {
        type: Object,
        default() {
            return {
                value: 'id',
                label: 'name',
                children: 'children'
            }
        }
    },
    // 组件绑定的options
    options: {
        type: Array,
        default() {
            return []
        }
    },
    // 双向绑定值
    modelValue: {
        type: [String, Number],
        default: ''
    },
    // 空占位字符
    placeholder: {
        type: String,
        default: '请选择'
    }
})
const emits = defineEmits(['update:modelValue'])
watch(() => props.options, (val) => {
    data.options = val
    setCurrent()
})
const select = reactive({
    value: props.modelValue.value,
    currentNodeKey: '',
    currentNodeLabel: ''
})
const data = reactive({
    treeLoading: false, // 加载loading~
    options: props.options, // 选项数组
    state: 0 // "" -- 全部   0 -- 在职   1 -- 离职
})
const treeSelect = ref(null)
const nodeClick = (data, node) => {
    if(data.children && data.children.length > 0) {
        if(select.currentNodeKey){
            treeRef.value.setCurrentKey(select.currentNodeKey)
        }else{
            treeRef.value.setCurrentKey()
        }
        return
    }
    select.currentNodeKey = data[props.TreeProps.value]
    select.currentNodeLabel = data[props.TreeProps.label]

    select.value = data.id;
    treeSelect.value.blur()
    emits('update:modelValue', select.value)
}
// select 筛选方法 refs
const treeRef = ref(null)
const selectFilter = (query) => {
    treeRef.value.filter(query)
}
// 筛选方法
const treeFilter = (value, dataValue) => {
    if (!value) return true
    return dataValue[props.TreeProps.label].toLowerCase().indexOf(value.toLowerCase()) !== -1
}
// 直接清空选择数据
const clearAll = () => {
    select.currentNodeKey = ''
    select.currentNodeLabel = ''
    select.value = ''
    treeRef.value.setCurrentKey()
    emits('update:modelValue', '')
}
// setCurrent通过select.value 设置下拉选择tree 显示绑定的v-model值
const setCurrent = () => {
    select.currentNodeKey = select.value
    treeRef.value.setCurrentKey(select.value)
    const data = treeRef.value.getCurrentNode(select.value)
    select.currentNodeLabel = data[props.TreeProps.label]
}
// 监听外部清空数据源 清空组件数据
watch(() => props.modelValue, (v) => {
    // 动态赋值
    if (v) {
        select.value = v
        setCurrent()
    }else{
        clearAll()
    }
})
// 回显数据
onMounted(async () => {
    await nextTick()
    if (select.value) {
        setCurrent()
    }
})
// 查询在职离职业务员
const handleState = (type) => {
    data.state = type
    data.treeLoading = true
    request({ url: `/admin/dept/treeWithDeptUsers?isLeave=${type}`, method: "GET" }).then(res => {
        data.options = res.data.data
        data.treeLoading = false
    })
}
</script>
<style lang="scss" scoped>
.tree_box {
    width: 300px;
}

:deep(.el-scrollbar) {
    height: 300px;

    .el-select-dropdown__wrap {
        max-height: 300px;
        overflow: hidden;

        .el-select-dropdown__list {
            padding: 0;
        }
    }
}

.el-tree :deep(.is-current>.el-tree-node__content .el-tree-node__label) {
    color: var(--el-color-primary);
}

.treeSelectRadio-option-style {
    height: 260px !important;
    padding: 0 0 10px 0 !important;
    margin: 0;
    background-color: #fff;
}

.check-box {
    padding: 0 16px;
}</style>
    

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值