处理tree数据返回目标节点及其父节点祖节点附加节点间上下移动

文章介绍了如何在Vue应用中使用递归函数findSubtreeById在树形数据结构中查找指定节点,以及实现节点的上下移动、删除、添加和编辑功能的示例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 function findSubtreeById(arr, targetId) {
    function findNode(node) {
      if (node.id === targetId) {
        return { ...node } // 创建一个新对象存储目标节点
      }
      // console.log({ ...node }, 789)
      if (node.children && node.children.length > 0) {
        for (const childNode of node.children) {
          const result = findNode(childNode) // 递归查找子节点

          if (result) {
            return { ...node, children: [result] } // 创建一个新对象,保留父节点和目标节点
          }
        }
      }

      return null
    }

    for (const node of arr) {
      const result = findNode(node)
      if (result) {
        return result // 返回包含目标节点的新对象
      }
    }

    return null
  }

  const targetId = handleTreeDataList.value.id
  const result = findSubtreeById(dataSourcing.value, targetId)
dataSourcing.value是tree全部数据dataSourcing.value是目标节点id

 实现节点间上下移动

// 存放上下移动,删除,编辑,添加显示状态
const showMoveUp = (data, node) => {
  const siblings =
    node.parent.data.children === undefined ? dataSource.value : node.parent.data.children
  const currentIndex = siblings.findIndex((item) => item === data)
  return currentIndex > 0
}
const showMoveDown = (data, node) => {
  const siblings =
    node.parent.data.children === undefined ? dataSource.value : node.parent.data.children
  const currentIndex = siblings.findIndex((item) => item === data)
  return currentIndex < siblings.length - 1
}

const showDelete = (data) => {
  return !data.children || data.children.length === 0
}
const showAddChild = (data) => {
  return data.layer < 5
}
const showEdit = (data) => {
  return data.isEditing
}


const handleNodeClicks = () => {
  Catalogue(1, null)
  getCatalogue()
  ElMessage({
    message: '添加成功',
    type: 'success'
  })
  AddSuccess(1)
  // router.push({
  //   name: 'home'
  // })
}
const defaultProps = {
  children: 'children',
  name: 'name'
}

/**
 * 添加子目录
 * **/
const append = async (data: any, node: any) => {
  if (data.layer > 4) {
    ElMessage({
      message: '已达到最大层级,不允许再添加子节点',
      type: 'warning'
    })

    return
  }

  const newChild = {
    id: 0,
    sort: 0,
    floor: 0,
    name: '子目录',
    pid: data.pid,
    layer: data.layer + 1,
    children: [],
    label: false
  }
  if (!data.children) {
    data.children = []
  }
  data.children.push(newChild)
  dataAddition.value = data.children
  dataSource.value = [...dataSource.value]

  editNode.value = newChild

  nextTick(() => {
    Catalogued(1, data)
    // 初始化数据
    // getCatalogue()
  })
}
/**
 * 新建父目录
 * **/
const appedEnter = async (data: any) => {
  if (input1.value === '') {
    return // 不允许空目录名称
  }
  const newFather = {
    id: 0,
    sort: 1,
    floor: 0,
    name: input1.value,
    pid: 0,
    layer: 0,
    children: [],
    label: false
  }
  // 检查同级目录是否有相同名称
  const siblings = dataSource.value
  const isNameDuplicate = siblings.some((sibling) => sibling.name === input1.value)

  if (isNameDuplicate) {
    ElMessage({
      message: '名字已存在!',
      type: 'warning'
    })

    return
  }

  dataSource.value = [...dataSource.value]
  dataSource.value.push(newFather)

  editNode.value = newFather

  input1.value = '' // 清空输入框
  nextTick(async () => {
    Catalogue(1, null)
    await new Promise((resolve) => setTimeout(resolve, 300)) // 延迟 300 毫秒
    getCatalogue()
  })
}

/**
 *删除功能
 **/
const remove = (node: Node, data: any) => {
  if (data.label) {
    // ElMessage({
    //   message: '此目录下已上传标注文件, 无法删除!',
    //   type: 'warning'
    // })
    centerDialogVisible.value = true
    return
  }
  const parent = node.parent
  const children: any = parent.data.children || parent.data
  const index = children.findIndex((d) => d.id === data.id)
  children.splice(index, 1)
  dataSource.value = [...dataSource.value]
  editNodeData.value = node.parent.data.children || node.parent.data
  editNode.value = data
  // const parentNode = node.parent.data.length > 2 ? null : node.parent.data
  // console.log(parentNode)
  // Catalogue(2, null)

  Catalogueing(2, node.parent.data.length > 2 ? null : node.parent.data)
}

/**
 * 编辑功能
 * **/
const startEdit = (data) => {
  data.isEditing = true
}

const saveEdit = (data, node) => {
  if (dataSource.value) {
    const siblings = data.layer <= 1 ? dataSource.value : node.parent.data.children
    const isNameDuplicate = siblings.some(
      (sibling) => sibling !== data && sibling.name === data.name
    )

    if (isNameDuplicate) {
      ElMessage({
        message: '同级目录中存在相同名称',
        type: 'warning'
      })

      return
    }

    if (data.layer <= 1) {
      editNodeData.value = dataSource.value
      editNode.value = data
    } else {
      editNodeData.value = node.parent.data.children
      editNode.value = data
    }
    data.isEditing = false

    // 可以在这里提交修改后的数据到后端
    Catalogueing(4, node.parent.data.length > 2 ? null : node.parent.data) // 调用保存数据的方法
    // getCatalogue()
  }
}
// 交换两个位置的数据
const swapPositions = (array, index1, index2) => {
  const temp = array[index1]

  array[index1] = array[index2]

  array[index2] = temp
}

const move = (data, direction, node) => {
  const children =
    node.parent.data.children === undefined ? dataSource.value : node.parent.data.children

  const currentIndex = children.findIndex((item) => item.id === data.id)

  if (direction === 'up' && currentIndex > 0) {
    swapPositions(children, currentIndex, currentIndex - 1)
  } else if (direction === 'down' && currentIndex < children.length - 1) {
    swapPositions(children, currentIndex, currentIndex + 1)
  } else {
    ElMessage({
      message: '到头了呢~',
      type: 'success'
    })
    return
  }

  // 更新数据源后触发重新渲染
  dataSource.value = [...dataSource.value]

  // 更新编辑节点的数据
  editNodeData.value = children || node.parent.data
  editNode.value = data

  // 调用保存数据的方法
  Catalogueing(3, children.length > 2 ? null : node.parent.data)
}

  <!-- 编辑 -->
                      <div class="catalogue-tree-icon1" @click="startEdit(data)"></div>
                      <!--添加 -->
                      <div
                        v-show="showAddChild(data)"
                        class="catalogue-tree-icon2"
                        @click="
                          () => {
                            nextTick(() => append(data, node))
                          }
                        "
                      ></div>
                      <!-- 删除 -->
                      <div
                        v-show="showDelete(data)"
                        class="catalogue-tree-icon3"
                        @click="remove(node, data)"
                      ></div>
                      <!-- 向上移动 -->
                      <div
                        class="catalogue-tree-icon4"
                        v-show="showMoveUp(data, node)"
                        @click="move(data, 'up', node)"
                      ></div>
                      <!-- 向下移动 -->
                      <div
                        class="catalogue-tree-icon5"
                        v-show="showMoveDown(data, node)"
                        @click="move(data, 'down', node)"
                      ></div>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值