Как посчитать глубину дочерних элементов массива — Vue.js

Я хотел бы, чтобы метод расчета глубины правильно вычислил глубину, и вместо этого он выполняет расчет в обратном порядке, присваивая первому элементу глубину 2, второму - глубину 1 и третьему - глубину 0, возможно, мне нужно создать новый метод, где он получает RevisionData, а затем просмотрите элемент за элементом. И не рассчитывает по каким-либо причинам глубину больше 2.

<template>
      <acc-data-table-v2
            :data = "revisionData"
            :columns = "columns"
            primaryColumn = "id"
            treeRowKey = "id"
            row-key = "id"
            :treeProps = "{children: 'children'}"
            :row-class-name = "tableRowClassName"
            >

            <template v-slot:subflowsRevisionsDescriptionTemplate = "slotProps">
                <div>
                        <div :style = "{ marginLeft: calculateMarginLeft(calculateDepth(slotProps.scope.row)) }">
                            <div v-if = "slotProps.scope.row.step_id">
                                {{ slotProps.scope.row.step.description }} 
                            </div>
                            <div v-if = "!slotProps.scope.row.step_id">
                                {{ slotProps.scope.row.description }} 
                            </div>
                        </div>
                </div>
            </template>
      </acc-data-table-v2>
</template>


<script>
export default {
  data() {
    return {
      revisionData: [
        {
          id: 1, //depth: 0
          name: 'Parent 1',
          children: [
            {
              id: 11, //depth: 1
              name: 'Child 1.1',
              children: [
                {
                  id: 111, //depth: 2
                  name: 'Grandchild 1.1.1'
                },
              ]
            },
            {
              id: 12, //depth: 1
              name: 'Child 1.2'
            }
          ]
        },
        {
          id: 2, //depth:0
          name: 'Parent 2',
          children: [
            {
              id: 21, //depth: 1
              name: 'Child 2.1'
            }
          ]
        }
      ]
    };
  },
  methods: {
        calculateMarginLeft(depth) {
            const marginLeft = depth * 12 + 'px';
            return marginLeft;
        },
        calculateDepth(item) {
            let depth = 0;
            let parent = item;
            while (parent.children && parent.children.length > 0) {
                depth++;
                parent = parent.children[0];
            }
            return depth;
        },
  }
};
</script>

Разве id: 111 не должно быть depth: 2?

kissu 10.05.2024 13:03

@kissu да, и оно там

GuyPeace 10.05.2024 13:04

Извините, если я неправильно понял, но в чем здесь проблема? Кстати, это похоже на то, что вы пытаетесь сделать: vuejs.org/examples/#tree

kissu 10.05.2024 13:06

@kissu проблема в том, что глубина вычисляется неправильно

GuyPeace 10.05.2024 13:10

О, потому что this.calculateDepth(this.revisionData[0].children[0].childre‌​n[0]) дает 0, находясь на глубине 2? Это имеет смысл, потому что там ничего нет, когда вы находитесь у подножия дерева. Вы всегда можете получить максимум от данного дерева, а затем сделать maximum - currentDepthLevel, чтобы получить 2 - 0 = 2 за свою 111 ценность. Или вы можете сделать наоборот и попытаться получить родительский элемент , когда-то глубоко вложенный. Таким образом, у 1 будет 0 родителей, а у 111 будет 2 родителя. Нвм это невозможно хаха.

kissu 10.05.2024 13:16

@kissu Я не хочу, чтобы у него был максимум, я хочу, чтобы он был рекурсивным

GuyPeace 10.05.2024 13:27

Оба не связаны между собой. Вычисление максимума может быть итеративным или рекурсивным. Рекурсивные функции не так эффективны в JS, но в данном случае они, по крайней мере, подходят.

kissu 10.05.2024 13:29

Давайте продолжим обсуждение в чате.

GuyPeace 10.05.2024 13:34
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
2
8
80
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Хорошо, вы можете попробовать немного изменить код.

calculateDepth(item) {
  let depth = 0;
  let parent = item;
  // if there is no parent or any parent doesnt have child elemen`
  while (parent && parent.children && parent.children.length > 0) {
    depth++;
    parent = parent.children[0]; //  first child
  }
  return depth;
}

и после этого также рассчитайте оставшийся запас на основе коэффициента глубины

calculateMarginLeft(depth) {
  const marginLeft = depth * 12 + 'px';
  return marginLeft;
}

Я думаю, это должно сработать!

Что, если у родителя более одного дочернего элемента и, например, второй дочерний элемент имеет более глубокую вложенность, чем первый?

derpirscher 10.05.2024 14:07

Это довольно простая рекурсивная функция:

Переберите массив и присвойте каждому элементу текущую глубину. Если у элемента есть дочерние элементы, вызовите функцию рекурсивно с увеличенной глубиной. Максимальная глубина — это максимальная глубина любого из дочерних элементов.

function calcDepth(array, d) {
  let maxDepth = d;
  for (let elem of array) {
    elem.depth = d;
    if (elem.children?.length)
      maxDepth = Math.max(maxDepth, calcDepth(elem.children, d + 1));
  }
  return maxDepth;
}

let test = [ 
  { 
    id: "1", 
    children: [
      { 
        id: "1.1", 
        children: []
       }
    ]
  },
{ 
    id: "2", 
    children: [
      { 
        id: "2.1", 
        children: [
          {
            id: "2.1.1",
            children: [
              {
                id: "2.1.1.1"
              }
            ]
          }
        ]
       }
    ]
  }  
];

let max = calcDepth(test,0);
console.info(test);
console.info("MaxDepth: ", max);
Ответ принят как подходящий

Это классическая проблема глубины дерева.

Обновите свой код следующим образом:

  • создайте вычисленное значение revisionDataWithDepth, которое является копией revisionData с дополнительным полем depth
  • передай это revisionDataWithDepth своему :data
  • чтобы получить левое маржинальное требование calculateMarginLeft(slotProps.scope.row.depth)
<template>
      <acc-data-table-v2
            :data = "revisionDataWithDepth"
            :columns = "columns"
            primaryColumn = "id"
            treeRowKey = "id"
            row-key = "id"
            :treeProps = "{children: 'children'}"
            :row-class-name = "tableRowClassName"
            >

            <template v-slot:subflowsRevisionsDescriptionTemplate = "slotProps">
                <div>
                        <div :style = "{ marginLeft: calculateMarginLeft(slotProps.scope.row.depth) }">
                            <div v-if = "slotProps.scope.row.step_id">
                                {{ slotProps.scope.row.step.description }} 
                            </div>
                            <div v-if = "!slotProps.scope.row.step_id">
                                {{ slotProps.scope.row.description }} 
                            </div>
                        </div>
                </div>
            </template>
      </acc-data-table-v2>
</template>


<script>
export default {
  data() {
    return {
      revisionData: [
        {
          id: 1, //depth: 0
          name: 'Parent 1',
          children: [
            {
              id: 11, //depth: 1
              name: 'Child 1.1',
              children: [
                {
                  id: 111, //depth: 2
                  name: 'Grandchild 1.1.1'
                },
              ]
            },
            {
              id: 12, //depth: 1
              name: 'Child 1.2'
            }
          ]
        },
        {
          id: 2, //depth:0
          name: 'Parent 2',
          children: [
            {
              id: 21, //depth: 1
              name: 'Child 2.1'
            }
          ]
        }
      ]
    };
  },
  computed: {
    revisionDataWithDepth: function() {
      // create local function that creates a copy of revisionData with depth included
      function withDepth(revisions, currentDepth) {
        if (!revisions || !revisions.length) {
          return [] // or return undefined
        }
    
        const revisionsWithDepth = [];
        for (const revision of revisions) {
          const revWithDepth = { ...revision };
          revWithDepth.depth = currentDepth;
          revWithDepth.children = withDepth(revision.children, currentDepth + 1);
          revisionsWithDepth.push(revWithDepth);
        }
        return revisionsWithDepth;
      }
      return withDepth(this.revisionData, 0);
    }
  }
  methods: {
        calculateMarginLeft(depth) {
            const marginLeft = depth * 12 + 'px';
            return marginLeft;
        },
  }
};
</script>

Совет: вы даже можете использовать однострочник для withDepth:

function withDepth(revisions, depth) {
  return (revisions ?? []).map(revision => ({ ...revision, depth, children: withDepth(revision.children, depth + 1) }))
}

Другие вопросы по теме