组件使用方式
<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>