Массивный компонент дерева данных на основе Vue (20+)

JavaScript

Причина написания этого компонента:

  1. Компонент дерева в elementUI зависает, когда количество данных превышает 1k.
  2. Плагин массивного (20w+) дерева на основе vue не найден.

1. Почему застрял.

Кратко разберем, почему картон (Подробнее см. в справочной статье):

  1. elementUI рекурсивно реализует дерево с большим количеством dom.
  2. Большой объем данных будет собираться зависимостями, накладные расходы памяти будут высокими, он будет зависать, и даже браузер будет падать из-за нехватки памяти.

2. План реализации

  1. Сведение данных дерева и структуры дома.
  2. Виртуальный длинный список для контроля объема рендеринга dom
  3. data Данные не собираются зависимостями.
  4. Различные структуры данных ускоряют отклик (многоточечное пространство для времени).

1. Сведение древовидных данных и структуры домена, виртуальный длинный список для управления количеством рендеринга домена.

Подробнее см. в справочной статье

2. Данные данных не собираются по зависимостям, а множественные структуры данных ускоряют отклик

Не через пропсы, а через функции.

// 父组件
<huge-tree ref="huge-tree"></huge-tree>
 
axios.get(`/static/json/${count}.json`).then(({ data }) => {
    // 注意:这里的 data 也不要被依赖收集了,会导致卡顿。
    this.$refs['huge-tree'].setData(data);
  });
  
// 子组件
<script>
class BigData {
  _data = []; // 海量数据 tree
  list = []; // 扁平化的tree
  filterList = []; // 根据关键词过滤后的list
  listMap = {}; // this.big.list 对应的 map, 便于快速找到节点。
  filterTree = []; // 根据关键词过滤后的tree
}

export default {
    
    data() {
        this.big = null;
        return {
          count: 1, // 用于视图更新, 由于没有依赖收集,通过count 手动更新computed。
          keyword: '', // 关键词
          isSearching: false, // 搜索中
          itemHeigth: 27, // 每一项的高度
          startIndex: 0, // 渲染的开始区间
          endIndex: 70, // 渲染的结束区间
          throttleSrcoll: '', // 节流
          debounceInput: '',
          isOnlyInCheckedSearch: false,
        };
      },
      
      computed: {
        // 过滤掉 hidden 节点
        unHiddenList() {
          return this.count ? this.big.filterList.filter(i => !i.isHidden) : [];
        },
        // 虚拟高度,与隐藏的数量有关
        phantomHeight() {
          return this.unHiddenList.length * this.itemHeigth;
        },
        renderList() {
          return this.unHiddenList.slice(this.startIndex, this.endIndex);
        },
      },
  
    created() {
        this.big = new BigData();
        // 滚动时的节流
        this.throttleSrcoll = throttle(this.setRenderRange, 80);
        // 输入过滤条件的防抖
        this.debounceInput = debounce(this.init, 300);
      },

    methods: {
        setData(data) {
          this.big._data = data;
          this.init('init');
        },
        
        //init: 1. 拉平tree,2. 组织list,3. 过滤,4. 展开,5. 选中, 6. 回到顶部
        init(op) {
          // op: init, restore, showCheckedOnly
          if (this.big._data.length === 0) return;
          if (op === 'init') {
            this.flatTree(this.big._data);
            this.big.list.forEach(node => (this.big.listMap[node.id] = node));
          }
          this.initFilter(op);
          if (op === 'init' || op === 'restore') this.initExpand();
          this.setCheckedKeys(this.big.checkedKeys);
          this.backToTop();
        },
        
        //......
   }
}
</script>

3. Запускаем скриншот

4. Используйте

npm i huge-tree --save 或 yarn add huge-tree -D
// demo.vue, 
<template>
  <div>
    <btm-huge-tree></btm-huge-tree>
  </div>
</template>

<script>
import { HugeTree } from 'huge-tree'

export default {
  components: {
    'btm-huge-tree': HugeTree
  }
}
</script>

5. Работа с документацией

GitHub.com/bit main - поставь ох...

Справочная статья

zhuanlan.zhihu.com/p/55528376

исходный код

github: GitHub.com/bit main - поставь ох...