封装的下拉框不显示id对应的label值
点击编辑,修改页面获取到id值,并且与下拉框对应的id值相同
<el-form-item label="适用烟:" style="width:300px;">
<tree-select
v-model="comboSchemeOrder.tobaccoTypeId"
:checkOnClickNode="false"
:options="brandList"
width="150"
/>
</el-form-item>
created() {
pubApi.brandListTree().then(res => {
this.brandList = res.data;
});
},
于是查看是否是封装的treeSelect问题
分别在父组件打印brandlist,在子组件的created中打印接收的options
输出的顺序是options,brandlist,并且options为空。
所以要在获取options值之后再执行查找id对应label操作,即
子组件监听数据渲染完后执行某函数、watch监听prop中的属性有值后再执行、prop中属性值不为空
nextTick:在下次 DOM 更新循环结束之后执行延迟回调
watch:用于观察Vue实例上的数据变动。对应一个对象,键是观察表达式,值是对应回调。
子组件修改如下
watch: {
options() {
// 子组件监听数据渲染完后执行
this.setLabel();
},
methods: {
setLabel() {
this.$nextTick(()=>{
// 检测输入框原有值并显示对应 label
if (this.value) {
this.valueModel = this.value;
this.labelModel = this.queryTree(this.data, this.value);
}
})
},
}
树形下拉框组件完整代码如下:
<!--
树形下拉选择插件,
defaultExpandedKeys:默认展开的节点
defaultExpandedLevel:默认展开层级
defaultExpandedKeys更高
-->
<!--禁止搜索-->
<!--:readonly="!filterable"-->
<!-- 树状选择器 -->
<template>
<el-dropdown trigger="click" class="tree-select" @visible-change="onVisibleChange">
<el-input
ref="input"
v-model="labelModel"
:placeholder="placeholder"
:clearable="!filterable"
:disabled="disabled"
suffix-icon="el-icon-arrow-down"
:class="{ 'rotate': showStatus }"
:style="`width:${width || 200}px`"
@input="onFilter"
@clear="clear()"
@blur="UpdateTaskName($event)"
/>
<el-dropdown-menu slot="dropdown">
<el-tree
v-show="!disabled"
ref="tree"
:style="`min-width: ${treeWidth}; max-height:${treeHeight}`"
:props="props"
:node-key="props.key"
:data="data"
:show-checkbox="showCheckbox"
:default-expanded-keys="expandedKeys"
:default-checked-keys="checkedKeys"
:filter-node-method="filterNode"
@node-click="onClickNode"
@check="onCheckChange"
:check-on-click-node="checkOnClickNode"
:expand-on-click-node="expandOnClickNode"
></el-tree>
</el-dropdown-menu>
</el-dropdown>
</template>
<script>
export default {
name: "TreeSelect",
// 设置绑定参数
model: {
prop: "value",
event: "selected"
},
props: {
// 接收绑定参数,默认选中值
value: String,
// 输入框宽度
width: String,
// 选项数据
options: {
type: Array,
required: true,
default: () => []
},
// 输入框占位符
placeholder: {
type: String,
required: false,
default: "请选择"
},
// 树节点配置选项
props: {
type: Object,
required: false,
default: () => ({
label: "label",
children: "children",
key: "key",
parentKey: "parentKey"
})
},
// 显示复选框?
showCheckbox: {
type: Boolean,
default: false
},
// 是否禁用
disabled: {
type: Boolean,
default: false
},
// 可筛选?
filterable: {
type: Boolean,
default: false
},
// 是否在点击节点的时候选中节点
checkOnClickNode: {
type: Boolean,
default: true
},
// 是否在点击节点的时候展开或者收缩节点, 默认值为 false,只有点箭头图标的时候才会展开或者收缩节点。
expandOnClickNode: {
type: Boolean,
default: false
},
// 默认展开的结点
defaultExpandedKeys: {
type: Array,
required: false,
default: () => []
},
// 默认展开层级
defaultExpandedLevel: {
type: Number,
default: 1
}
},
data() {
return {
// 树状菜单显示状态
showStatus: false,
// 树宽度
treeWidth: "auto",
// 树高度
treeHeight: "auto",
// 输入框显示值
labelModel: "",
// 实际请求传值
valueModel: ""
};
},
computed: {
// 是否为树状结构数据
dataType() {
const jsonStr = JSON.stringify(this.options);
return jsonStr.indexOf(this.props.children) !== -1;
},
// 若非树状结构,则转化为树状结构数据
data() {
return this.dataType ? this.options : this.switchTree();
},
// 默认展开的结点
expandedKeys() {
if (this.defaultExpandedKeys.length !== 0) {
return this.defaultExpandedKeys;
}
// 最小展开层级为1,最大展开层级为3
const level = Math.min(Math.max(1, this.defaultExpandedLevel), 3);
// 递归遍历data数组,返回层级 <= level的节点key值数组
const fa = (list, currentLevel) => {
const temp = [];
list.forEach(item => {
if (currentLevel <= level) {
temp.push(item[this.props.key]);
}
if (item[this.props.children] && item[this.props.children].length) {
fa(item.children, currentLevel + 1);
}
});
return temp;
};
return fa(this.data, 1);
},
// 选中的结点
checkedKeys() {
return this.value ? this.value.split(",") : "".split(",");
}
},
watch: {
options() {
// 子组件监听数据渲染完后执行
this.setLabel();
},
labelModel(val) {
if (!val) {
this.valueModel = "";
}
// this.$refs.tree.filter(val)
},
value(val) {
this.valueModel = this.value;
this.labelModel = this.queryTree(this.data, val);
}
},
created() {
// 获取输入框宽度同步至树状菜单宽度
this.$nextTick(() => {
this.treeWidth = `${this.width ||
this.$refs.input.$refs.input.clientWidth}px`;
});
},
methods: {
setLabel() {
this.$nextTick(()=>{
// 检测输入框原有值并显示对应 label
if (this.value) {
this.valueModel = this.value;
this.labelModel = this.queryTree(this.data, this.value);
}
})
},
// 单击节点
onClickNode(node) {
if (!this.showCheckbox) {
this.labelModel = node[this.props.label];
this.valueModel = node[this.props.key];
this.$emit("selected", this.valueModel);
this.$emit("getNode", node);
}
},
// 获取默认值
getTobaValue(date, treeDate) {
this.options = treeDate;
var dataArry = this.dataType ? this.options : this.switchTree();
this.labelModel = this.queryTree(dataArry, date);
},
// 复选框change时触发
onCheckChange(node, checkedData) {
// this.labelModel = this.$refs.tree.getCheckedNodes(false, true).map(item => item[this.props.label])
// this.valueModel = this.$refs.tree.getCheckedKeys(true) // 仅叶子节点
this.labelModel = checkedData.checkedNodes
.map(item => item[this.props.label])
.join(",");
this.valueModel = checkedData.checkedKeys.join(",");
this.$emit("selected", this.valueModel);
this.$emit("getNode", node);
},
onFilter(val) {
this.$refs.tree.filter(val);
},
UpdateTaskName(e) {
this.$emit("selected", this.valueModel);
},
clear() {
this.$refs.tree.setCheckedKeys([]);
this.$emit("selected", "");
},
// 下拉框显示、隐藏时触发
onVisibleChange(show) {
if (show) {
this.showStatus = true;
this.$refs.tree.filter(false);
} else {
this.showStatus = false;
this.$refs.input.blur();
this.$emit("selected_chage", this.valueModel);
}
},
// 扁平数组转化为树状层级结构
switchTree() {
return this.cleanChildren(this.buildTree(this.options));
},
// 树节点过滤方法
filterNode(query, data) {
if (!query) return true;
return data[this.props.label].indexOf(query) !== -1;
},
// 搜索树状数据中的 ID
queryTree(tree, id) {
const labels = [];
const ids = id ? (id + "").split(",") : [];
let stark = [];
stark = stark.concat(tree);
while (stark.length) {
const temp = stark.shift();
if (temp[this.props.children]) {
stark = stark.concat(temp[this.props.children]);
}
if (ids.indexOf(temp[this.props.key]) >= 0) {
labels.push(temp[this.props.label]);
}
}
if (this.$refs.tree) {
this.$refs.tree.setCheckedKeys(ids);
}
return labels.join(",");
},
// 将一维的扁平数组转换为多层级对象
buildTree(data) {
// shallow copy
const items = JSON.parse(JSON.stringify(this.options));
// 构造对象,方便查找
let keyData = {};
items.forEach(item => {
keyData[item[this.props.key]] = item;
});
// 构造树
const tree = [];
const parentKey = this.props.parentKey;
const childrenKey = this.props.children;
for (let item of items) {
const parentId = item[parentKey];
if (
parentId !== item[this.props.key] && // 元素的key不能与自身的parentKey相等
keyData.hasOwnProperty(parentId)
) {
if (keyData[parentId][childrenKey]) {
keyData[parentId][childrenKey].push(item);
} else {
keyData[parentId][childrenKey] = [item];
}
} else {
tree.push(item);
}
}
return tree;
},
// 清除空 children 项
cleanChildren(data) {
const childrenKey = this.props.children;
const fa = list => {
list.map(e => {
if (e[childrenKey] && e[childrenKey].length) {
fa(e[childrenKey]);
} else {
delete e[childrenKey];
}
return e;
});
return list;
};
return fa(data);
}
}
};
</script>
<style lang="scss" scoped>
.el-tree {
max-height: 350px;
max-width: 170px;
overflow-y: auto;
}
.tree-select .el-input.el-input--suffix {
cursor: pointer;
}
.tree-select .el-input.el-input--suffix.rotate .el-input__suffix {
transform: rotate(180deg);
}
.el-tree-node__content .el-checkbox {
margin-right: 8px;
}
</style>