基於 ElementUI 手擼穿梭樹(一)

如今,一直在忙着寫一個本身獨立承擔前端部分的項目。公司剛完成的上百個開發工程師開發了一年的大項目,用的技術棧是React。 因爲,本身主導的這個項目比較小,項目複雜度比以前的項目差遠了。因此,就選了,開發靈活性沒 React 高,但開發速度較快的 Vue,同時UI框架用的是 ElementUI。咱們以前用 React 的大項目中,就有不少的地方用到了,穿梭書組件(兩個 ElementUI Tree 左樹的數據能夠穿梭到右面,右樹的數據能夠穿梭到左面)。好多節點的穿梭書是咱們本身封裝的。但這個小項目咱們又用到了穿梭書,然而比較尷尬是,此次用的是 Vue,因此以前用 React 寫的組件就只具有程序設計上的參考意義了。同時,我參考了,Element的樹的寫法的基礎上,去是實現了基於Vue的穿梭樹。因爲,業務比較複雜,這篇文章就先之寫 Tree 實現的核心思想吧!前端

Tree 程序結構

固然這個項目中記得引入 ElementUI。 樹的每一個節點都要記住本身的當前狀態,樹閉合展開選中的操做,也經過改變當前節點狀態來改變。因此咱們就須要,去把數據進行遍歷,生成一個有狀態,同時每一個節點有改變的狀態的構造樹。vue

對數據進行遍歷

樹的 Datanode

const treeData = [
    {
      label: "一級 1",
      children: [
        {
          label: "二級 1-1",
        }
      ]
    },
    {
      label: "一級 2",
      children: [
        {
          label: "二級 2-1",
          children: [
            {
              label: "三級 2-1-1"
            }
          ]
        }
      ]
    }
]
複製代碼

在 Tree.vue 中傳入,將 treeData 傳入構造函數中TreeStore。 new TreeStore({data: treeData}) 生成了咱們想要的有狀態,還能夠經過調用內部函數改變自身節點狀態的樹形數據。element-ui

tree-store.js 代碼數組

import Node from './node.js'
export default class TreeStore {
  constructor(options) {
    for (let option in options) {
      if (options.hasOwnProperty(option)) {
        this[option] = options[option]
      }
    }
    this.root = new Node({
      data: this.data,
      store: this
    })
  }
}
複製代碼

node.js 代碼bash

import objectAssign from 'element-ui/src/utils/merge';
const getPropertyFromData = function(node, prop) {
    const data = node.data || {};
    if (typeof prop === 'string') {
        return data[prop];
    } else {
        throw new Error('label data type is not string');
    }
};
export default class Node {
    constructor(options) {
        this.level = 0;
        this.childNodes = [];
        this.expanded = true; //展開關閉狀態
        for (let option in options) {
            if (options.hasOwnProperty(option)) {
                this[option] = options[option]
            }
        }
        this.setData(this.data)
    }
    get isLeaf() {
        return !!this.childNodes.length
    }
    get label() {
        return getPropertyFromData(this, 'label');
    }
    setExpanded() { // 控制 expanded 來控制頁面中樹的閉合展開
        this.expanded = !this.expanded;
    }
    setData(data) {
        this.data = data;
        this.childNodes = []; // 子節點數組
        let children;
        if (this.level === 0 && this.data instanceof Array) {
            children = this.data;
        } else {
            children = getPropertyFromData(this, 'children') || [];
        }
        for (let i = 0; i < children.length; i++) {
            this.insertChild({ data: children[i] });
        }
    }
    insertChild(child, index, batch) {
        if (!child) throw new Error('insertChild error: child is required.');
        if (!(child instanceof Node)) {
            objectAssign(child, {
                parent: this,
                store: this.store
            });
            child = new Node(child);
        }

        child.level = this.level + 1;
        this.childNodes.push(child);
    }
}
複製代碼

將新的數據進行遍歷

生成新的數據後,咱們就能夠在 Tree.vue 中對新數據進行遍歷。將構造的數據中的文本渲染到頁面中。框架

Tree.vue 中代碼函數

<template>
  <div class="el-tree" role="tree">
    <tree-node
      v-for="(child, index) in root.childNodes"
      :key="index"
      :node="child"
     />
  </div>
</template>

<script>
import TreeStore from "./modal/tree-store.js";
import TreeNode from "./TreeNode.vue";

export default {
  name: "Tree",
  data() {
    return {
      store: null,
      root: null
    };
  },
  props: {
    data: {
      type: Array
    }
  },
  created() {
    this.store = new TreeStore({
      data: this.data
    })
    this.root = this.store.root;
  },
  components: {
    TreeNode
  }
};
</script>
複製代碼

TreeNode.vue 中代碼動畫

<template>
  <div class="tree">
    <div class="el-tree-node__content">
      <span
        :class="[ {'expanded': node.expanded}, 'el-tree-node__expand-icon' ]"
        class="el-icon-caret-right"
        @click.stop="handleExpandIconClick"
      ></span>
      <span class="el-tree-node__label">{{node.label}}</span>
    </div>
    <el-collapse-transition> <!-- 使用了 elementUI 中的動畫組件 -->
      <div
        v-show="node.expanded"
        class="el-tree-node__children"
        style="padding-left: 18px;"
      >
        <tree-node
          v-for="(item, index) in node.childNodes"
          :key="index"
          :node="item"
        />
      </div>
    </el-collapse-transition>
  </div>
</template>

<script>
export default {
  name: "TreeNode",
  props: {
    node: Object
  },
  data() {
    return {
      data: Array,
      isExpande: true
    };
  },
  methods: {
    handleExpandIconClick() {
      this.node.setExpanded();
    }
  }
};
</script>
複製代碼

好了,這個樹是我用 Vue 實現的最最基本的樹。拋去了一切業務邏輯,一切只剩最根本,很好理解很簡單。固然寫成這麼簡單,有很大一部分緣由也但願我女友可以看懂。 後面的我會把有業務複雜邏輯的加進來。ui

相關文章
相關標籤/搜索