Ant-design 的 a-tree-select 使用
需求:
-
树形结构中的children 和 labels 需要同时展示在页面
递归处理数据,将labels 合并进入children
-
展示labels时需要在前面加一个标记○
// 需求1 需求2 /** * @description 获取标签分类的树形结构 */ getData(data, dataIndex) { const list = data.map((item, index) => { if (item.children && item.children.length > 0) { item.children = item.children.map((child) => { return { ...child, type: 'children', // 添加标识符,判断是否为children/labels 给需求4使用 label: child.name, // a-tree-select 中为选中子节点的内容和展示字节点内容做区分 } }) this.getData(item.children, dataIndex + '-' + index) } else { item.children = [] } if (item.labels && item.labels.length > 0) { item.children = item.children .map((child) => { return { ...child, type: 'children', label: child.name, } }) .concat( item.labels.map((label) => { return { ...label, type: 'label', label: label.name, name: `○ ${label.name}`, // 需求2 } }) ) } return { ...item, label: item.name, key: dataIndex + '-' + index, } }) return list },
-
选中label时需要去除标记
注意事项:
- 可以自定义下拉框中的title,展示icon,但是选中时,icon也会出现在输入框中,而且必须在treeData的每一项中加入scopedSlots:{title:‘custom’},使用时slot=‘custom’
- 选中后输入框中显示值可以用 treeNodeLabelProp=“label” 进行显示设置,目前选项有 title/label/id/key,默认选项是title
<a-tree-select
v-model="searchParams.labelIds"
tree-checkable
:tree-data="treeData"
:show-checked-strategy="SHOW_PARENT"
:replaceFields="{
title: 'name', // == 下拉框显示值 ==
children: 'children',
value: 'id'
}"
search-placeholder="请选择"
class="color-select"
style="min-width: 400px"
:dropdownStyle="{ width: '400px' }"
:dropdownMatchSelectWidth="false"
treeNodeLabelProp="label" // == 选中后输入框中显示值 ==
>
<!-- 自定义下拉框中title的内容,配合treeData中加入scopedSlots -->
<!--
<span slot="custom" slot-scope="{key, value}">
<a-icon type="close-circle" />
{{value}}
</span>
-->
</a-tree-select>
- 选中父节点时,需要将父节点中的labels全部过滤给后端
新建一个 new Map(),接收一个 Id1:[labelId1, labelId2]…
选中某个父节点时,直接在Map的get方法获取下面所有的labels
// 使用时的代码
let labels = []
this.searchParams.labelIds.forEach((item) => {
if (this.treeDataValues.get(item)) {
labels = labels.concat(this.treeDataValues.get(item))
}
})
// 数据转化时的代码
/**
* @description 获取标签分类中子分类的id
*/
getLabelIds(data) {
const list = data
.map((item) => {
if (item.children && item.children.length > 0) {
// 只需要存在 label 的父元素 id
const val = item.children
.map((child) => (child.type === 'label' ? child.id : null))
.filter((i) => i)
.concat(this.getLabelIds(item.children))
// 过滤掉不存在labels
if (val.length > 0) {
if (!this.treeDataValues.has(item.id)) { // treeDataValues : new Map()
this.treeDataValues.set(item.id, val.flat(Infinity)) // 使用es6的方法,将多维数组转化为一维数据, Infinity:代表不管有多少层都转化为一维数组
}
return val
// { [item.id] : val }
}
}
})
.filter((i) => i)
return list
},
数据结构:
{
"code":200,
"traceId":"",
"message":"成功",
"data":[
{
"id":16,
"name":"驾驶行为属性",
"children":[
{
"id":137,
"name":"guyufan_test1"
},
{
"id":148,
"name":"温油"
}
],
"labels":[
{
"id":600024,
"name":"智能驾驶"
},
{
"id":600018,
"name":"test8"
}
]
},
{
"id":17,
"name":"车主使用属性",
"children":[
{
"id":18,
"name":"地图产品",
"labels":[
{
"id":600006,
"name":"年龄"
},
{
"id":600005,
"name":"销售城市"
},
{
"id":600004,
"name":"性别"
}
]
},
{
"id":19,
"name":"音乐产品",
"children":[
{
"id":20,
"name":"音乐产品行为偏好",
"labels":[
{
"id":600000,
"name":"用户30天内的驾驶习惯"
}
]
},
{
"id":21,
"name":"音乐内容偏好",
"children":[
{
"id":144,
"name":"guyufan_test1"
}
]
}
]
},
{
"id":143,
"name":"guyufan_test1"
}
]
},
{
"id":15,
"name":"车主核心属性",
"children":[
{
"id":117,
"name":"guyufan_test2"
},
{
"id":135,
"name":"guyufan_test1"
},
{
"id":153,
"name":"未命名子分类",
"children":[
{
"id":155,
"name":"未命名子分类1213"
}
]
}
]
},
{
"id":126,
"name":"guyufan_parent_test4",
"labels":[
{
"id":600023,
"name":"mark3"
}
]
},
{
"id":138,
"name":"guyufan_parent_test5"
},
{
"id":139,
"name":"guyufan_parent_test"
},
{
"id":142,
"name":"guyufan_parent_test645"
},
{
"id":150,
"name":"未命名分类",
"children":[
{
"id":152,
"name":"未命名子分类"
}
]
},
{
"id":151,
"name":"guyufan_parent_test6"
},
{
"id":159,
"name":"未命名分类111"
}
]
}