目录
- 修改树状对象数组的键值 返回新数组
- 将树状对象数组拍平
- 在树状对象数组中 根据条件查找某项
- 将
id
parentId
关联的一维数组,处理成树状对象数组 - 通过子节点id 查找到所有关联的父节点
- React 递归渲染嵌套路由
- 渲染树状dom
修改树状对象数组的键值 返回新数组
一般使用 map
处理数据,返回一个新数组
// @param source 源数据格式:
// [
// { id: 1, title: 'item1' },
// { id: 2, title: 'item2', children: [ { id: 21, title: 'item2-1' } ] },
// ]
// 将处理成:
// [
// { value: 1, label: 'item1' },
// { value: 2, label: 'item2', children: [ { value: 21, label: 'item2-1' } ] },
// ]
处理函数:
const generateData = (source) => {
const _loop = (data) => {
return data.map((item) => {
if (item.children && item.children.length > 0) {
return {
value: item.id,
label: item.title,
children: _loop(item.children)
}
}
return {
value: item.id,
label: item.title,
}
})
}
return _loop(source)
}
将树状对象数组拍平
// @param source 源数据格式:
// [
// { id: 1, title: 'item1' },
// { id: 2, title: 'item2', children: [ { id: 21, title: 'item2-1' } ] },
// ]
// 将处理成:
// [
// { id: 1, title: 'item1' },
// { id: 2, title: 'item2' },
// { id: 21, title: 'item2-1' },
// ]
处理函数:
const flattenData = (source) => {
let result = []
const _loop = (data) => {
data.forEach((item) => {
result.push(item)
if (item.children && item.children.length > 0) {
_loop(item.children)
}
})
}
_loop(source)
return result
}
在树状对象数组中 根据条件查找某项
使用 for of
或 for i
都可以
// @param source 源数据格式:
// [
// { id: 1, title: 'item1' },
// { id: 2, title: 'item2', children: [ { id: 21, title: 'item2-1' } ] },
// ]
// 比如这里查找到 id 匹配条件的这项
处理函数:
const findItemOfId = (source, id) => {
for (let item of source) {
if (item.id === id) {
return item
} else if (item.children && item.children.length > 0){
const result = findItemOfId(item.children, id)
if (result) return result
}
}
return null
}
将 id
parentId
关联的一维数组,处理成树状对象数组
// @param source 源数据格式:
// [
// { id: 1, parentId: 0, title: 'item1' },
// { id: 2, parentId: 0, title: 'item2' },
// { id: 21, parentId: 2, title: 'item2-1' },
// { id: 210, parentId: 21, title: 'item2-1-0' },
// ]
// 处理成:
// [
// { id: 1, parentId: 0, title: 'item1' }.
// { id: 2, parentId: 0, title: 'item2', children: [
// { value: 21, parentId: 2, title: 'item2-1', children: [
// { id: 210, parentId: 21, title: 'item2-1-0' },
// ] }
// ] },
// ]
处理函数:
const generateData = (source) => {
let result = []
const _insetChildItem = (data, curItem) => {
data.forEach((item) => {
if (item.id === curItem.parentId) {
if (!item.children) item.children = []
item.children.push({
...curItem
})
} else if (item.children && item.children.length) {
_insetChildItem(item.children, curItem)
}
})
}
source.forEach((item) => {
if (item.parentId - 0 === 0) {
result.push({
...item
})
} else {
_insetChildItem(result, item)
}
})
return result
}
通过子节点id 查找到所有关联的父节点
// @param source 源数据格式:
// [
// { id: 1, parentId: 0, title: 'item1' },
// { id: 2, parentId: 0, title: 'item2' },
// { id: 21, parentId: 2, title: 'item2-1' },
// { id: 210, parentId: 21, title: 'item2-1-0' },
// ]
// 比如这里查找 id === 211 这项和它所有的父级项 title 得到数组:[ 'item2', ‘item2-1’, 'item2-1-1' ]
处理函数:
const getStructureArr = (source, id) => {
let result: string[] = [source.find((item => item.id === id)?.title]
let child = source.find((item) => item.id === id)
while (child && child.parentId) {
result = [source.find((item) => id === child.parentId)?.title, ...result]
child = source.find((item) => id === child.parentId)
}
return result
}
React 递归渲染嵌套路由
import React, LazyExoticComponent, { ReactNode } from 'react'
import { Route, Navigate } from 'react-router-dom'
import { RouteProps } from 'react-router-dom'
// routes数据格式类型
type RouteType = RouteProps & {
name: string // 路由别名
redirect?: string // 重定向路径
component?: ReactNode | LazyExoticComponent
routes?: RouteType[] // 子路由
}
const loop = (routes: RouteType[]): ReactNode => {
const routesComp = routes.map((item) => {
if (item.routes && item.routes.length > 0) {
return (
<Route
path={item.path}
element={<item.component />}
key={item.name}
>
{loop(item.routes)}
</Route>
)
}
return (
<Route
path={item.path}
element={!item.redirect ? <item.component /> : <Navigate to={item.redirect} />}
key={item.name ?? item.redirect}
/>
)
})
// 为一组子路由添加404跳转(path="*"是相对路径)
return <>
{routesComp}
<Route path="*" element={<Navigate to={ERR_ROUTE_PATH} />} />
</>
}
渲染树状dom
html结构:
<div id="testTree"></div>
处理函数和应用:
// 将树状数据渲染到文档片段里
const createTreeDom = (source) => {
const fragment = document.createDocumentFragment()
source.forEach(({ id, parentId, name }) => {
const el = document.createElement('div')
el.classList.add('item')
el.setAttribute('data-self-id', id)
el.setAttribute('data-parent-id', parentId)
el.innerHTML = `<div class="text">${name}</div>`
if (parentId - 0 === 0) {
fragment.appendChild(el)
} else {
const _parentEl = fragment.querySelector(`[data-self-id="${parentId}"]`)
if (_parentEl) {
if (!_parentEl.querySelector('.sub-list')) _parentEl.insertAdjacentHTML('beforeend', '<div class="sub-list"></div>')
_parentEl.querySelector('.sub-list').appendChild(el)
}
}
})
return fragment
}
// 测试数据
const testData = [
{ id: 1, parentId: 0, title: 'item1' },
{ id: 11, parentId: 1, title: 'item1-1' }
{ id: 2, parentId: 0, title: 'item2' },
{ id: 21, parentId: 2, title: 'item2-1' },
{ id: 210, parentId: 21, title: 'item2-1-1' },
]
const treeDom = generateTreeDom(testData)
treeDom && document.querySelector('#testTree')?.appendChild(treeDom)