目前所能完善到这样子了,待遇到bug再来解决
感谢 蔚莱先森 提供的思路
<template>
<el-form>
<el-form-item>
<select-tree v-model="value1" :options="options" />
el-form-item>
<el-form-item>
<select-tree lazy v-model="value2" url="api/tree" :props="defaultProps" />
el-form-item>
el-form>
template>
<script>
import SelectTree from '@/components/widget/SelectTree.vue';
export default {
components: {
SelectTree,
},
data() {
return {
// 默认选中值
value1: 'A',
value2: 'A',
// 数据默认字段
defaultProps: {
parent: 'parentId', // 父级唯一标识
value: 'id', // 唯一标识
label: 'label', // 标签显示
children: 'children', // 子级
},
// 数据列表
options: [
{
parentId: '0',
id: 'A',
label: 'label-A',
children: [
{
parentId: 'A',
id: 'A-1',
label: 'label-A-1',
},
],
},
{
parentId: '0',
value: 'B',
label: 'label-B',
},
],
};
},
};
script>
<template>
<el-select
ref="select"
popper-class="mod-select-tree"
:value="labelModel"
:filterable="filterable"
:disabled="disabledSelected"
:filter-method="filterMethod"
:clearable="filterable || lazy"
@clear="clearHandler"
@visible-change="visibleChange">
<el-option :value="valueModel" :label="labelModel">
<el-tree
ref="tree"
empty-text="无数据"
:expand-on-click-node="false"
:accordion="accordion"
:data="options"
:props="propsMerge"
:lazy="lazy"
:load="onLoadNodes"
:default-expand-all="!lazy"
:node-key="propsMerge.value"
:filter-node-method="filterNode"
:renderContent="renderContent"
@node-click="onNodeClick">
el-tree>
el-option>
el-select>
template>
<script>
import { analyzeResp } from '@/libs/util';
export default {
name: 'SelectTree',
// 设置绑定参数
model: {
prop: 'value',
event: 'selected',
},
props: {
// 接收绑定参数
value: [String, Number],
// 是否可以清空选项
clearable: Boolean,
// 根节点key值
rootKey: String,
// 懒加载是否使用地址传参方式
joint: Boolean,
// 禁用
disabled: Boolean,
// 启用搜索功能
filterable: Boolean,
// 树形控件 - 启用懒加载
lazy: Boolean,
// 树形控件 - 懒加载接口地址
url: String,
// 树形控件 - 是否每次只打开一个同级树节点展开
accordion: Boolean,
// 树形控件 - 选项数据,懒加载时无需设置
options: {
type: Array,
default: () => ([]),
},
// 树形控件 - 配置项
props: {
type: Object,
default: () => ({}),
},
// 查询参数
queryParams: {
type: Object,
default: () => ({
rows: 100000,
page: 1,
sort: 'orderNum-',
}),
},
},
data() {
return {
// eslint-disable-next-line
labelModel: '', // 输入框显示值
valueModel: '', // 实际请求传值
once: false,
};
},
computed: {
disabledSelected() {
if (this.disabled) return true;
return this.$parent.form ? this.$parent.form.disabled : false;
},
propsMerge() {
const propsTemp = Object.assign({
parent: 'parentId',
value: 'rowGuid',
label: 'label',
children: 'children',
disabled: 'disabled', // 是否禁用
isLeaf: 'isLeaf', // 是否为叶子节点
}, this.props);
return propsTemp;
},
},
watch: {
value: {
handler(val) {
this.valueModel = val;
this.initHandler();
},
immediate: true,
},
options: {
handler(val) {
if (!val || this.lazy) return;
this.initHandler();
},
immediate: true,
},
},
methods: {
// 初始化值
initHandler() {
if (!this.value) return;
this.$nextTick(() => {
const temp = this.$refs.tree.getNode(this.value);
// 初始化显示
this.labelModel = temp ? temp.label : '';
// 设置默认选中
this.$refs.tree.setCurrentKey(this.value);
});
},
// 切换选项
onNodeClick(data, node) {
if (node.disabled) {
this.$refs.tree.setCurrentKey(this.value || null);
} else {
this.labelModel = node.label;
this.valueModel = node.key;
this.$emit('selected', node.key);
this.$emit('change', node.data, node);
this.$refs.select.blur(); // 收起下拉框
this.$refs.select.focus(); // 获取焦点
// 修复懒加载下无法关闭选项问题
if (this.lazy) {
this.$set(this.$refs.select, 'visible', false);
}
}
},
// 下拉菜单显示回调
visibleChange(show) {
if (!show) return;
// 确保滚动条位置正确显示
if (show && !this.labelModel) {
this.labelModel = ' ';
this.$nextTick(() => { this.labelModel = ''; });
}
if (this.lazy && this.once) {
this.getNodeList(this.rootKey).then((data) => {
this.$refs.tree.updateKeyChildren(this.rootKey, data);
});
} else {
this.$emit('refresh');
}
this.initHandler();
this.once = true;
},
// 选择器检索过滤方法
filterMethod(query) {
// 调用树形控件的过滤
this.$refs.tree.filter(query);
// 忽略选择器本身的过滤
return true;
},
// 树节点过滤方法
filterNode(query, data) {
if (!query) return true;
return data[this.propsMerge.label].includes(query);
},
// 清空已选
clearHandler() {
this.valueModel = this.lazy ? this.rootKey : this.$enum.emptyRowGuid;
this.labelModel = this.lazy ? '' : '所有';
this.$emit('selected', '');
this.$refs.tree.filter();
this.$refs.tree.setCurrentKey(null);
},
// 加载子节点
onLoadNodes(node, resolve) {
this.getNodeList(node.data[this.propsMerge.value]).then(data => resolve(data));
},
// 获取节点列表
getNodeList(id = this.rootKey) {
const params = this.queryParams;
const paramsUrl = this.joint ? `/${id}` : '';
if (!this.joint) params.parentId = id;
return new Promise((resolve) => {
this.$http.get(`${this.url}${paramsUrl}`, { params }).then((response) => {
resolve((response.data.data || response.data) || []);
}, ({ response }) => {
analyzeResp(response);
});
});
},
// 节点渲染函数
renderContent(h, { node /* , store */ }) {
return (
<span class={`el-tree-node__label ${node.disabled ? 'is-disabled' : ''}`}>{node.label}</span>
);
},
},
};
script>
参考 https://blog.csdn.net/Mr_JavaScript/article/details/88604270