基於vue的海量數據tree組件(20w+)

寫這個組件的緣由:

  1. elementUI 裏的 tree 組件在數據量爲 1k+ 的的時候卡頓。
  2. 沒有找到基於 vue 的海量(20w+) tree 插件。

1. 爲啥卡頓。

簡單分析說下爲啥卡頓(具體查看參考文章):vue

  1. elementUI 遞歸實現 tree,dom 量大。
  2. 海量的 data 會被依賴收集,內存開銷大,會卡頓,甚至提示內存不足瀏覽器奔潰。

2. 實現方案

  1. tree 數據和 dom 結構的扁平化。
  2. 虛擬長列表控制 dom 渲染數量
  3. data 數據不被依賴收集。
  4. 多種數據結構加速響應(多點空間換時間)。

1. tree 數據和 dom 結構的扁平化、 虛擬長列表控制 dom 渲染數量

具體查看參考文章node

2. data 數據不被依賴收集、多種數據結構加速響

不經過 props 傳遞,而是經過函數傳遞。ios

// 父組件
<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. 運行截圖

參考文章

zhuanlan.zhihu.com/p/55528376git

源碼

源碼github

相關文章
相關標籤/搜索