VUE開發(fā)--Element-UI--樹形表格(六十)

一、安裝組件

npm i element-ui -S

二、創(chuàng)建組件

  1. 創(chuàng)建目錄treeTable
  2. 創(chuàng)建數(shù)組轉(zhuǎn)換文件
'use strict'
import Vue from 'vue'
export default function treeToArray (data, expandAll, parent = null, level = null) {
  let tmp = []
  Array.from(data).forEach(function (record) {
    if (record._expanded === undefined) {
      Vue.set(record, '_expanded', expandAll)
    }
    let _level = 1
    if (level !== undefined && level !== null) {
      _level = level + 1
    }
    Vue.set(record, '_level', _level)
    // 如果有父元素
    if (parent) {
      Vue.set(record, 'parent', parent)
    }
    tmp.push(record)
    if (record.children && record.children.length > 0) {
      const children = treeToArray(record.children, expandAll, record, _level)
      tmp = tmp.concat(children)
    }
  })
  return tmp
}
  1. 創(chuàng)建組件
    在目錄中創(chuàng)建組件:index.vue
<template>
  <div>
    <el-table :data="formatData" :row-style="showRow" v-bind="$attrs">
      <el-table-column v-if="columns.length===0" width="150">
        <template slot-scope="scope">
          <span v-for="space in scope.row._level" class="ms-tree-space" :key="space"></span>
          <span
            class="tree-ctrl"
            v-if="iconShow(0,scope.row)"
            @click="toggleExpanded(scope.$index)"
          >
            <i v-if="!scope.row._expanded" class="el-icon-plus"></i>
            <i v-else class="el-icon-minus"></i>
          </span>
          {{scope.$index}}
        </template>
      </el-table-column>
      <el-table-column
        v-else
        v-for="(column, index) in columns"
        :key="column.value"
        :label="column.text"
        :width="column.width"
      >
        <template slot-scope="scope">
          <span
            v-if="index === 0"
            v-for="space in scope.row._level"
            class="ms-tree-space"
            :key="space"
          ></span>
          <span
            class="tree-ctrl"
            v-if="iconShow(index,scope.row)"
            @click="toggleExpanded(scope.$index)"
          >
            <i v-if="!scope.row._expanded" class="el-icon-plus"></i>
            <i v-else class="el-icon-minus"></i>
          </span>

          <el-checkbox-group
            v-if="Array.isArray(scope.row[column.value])"
            v-model="scope.row.selectchecked"
            @change="handleCheckedCitiesChange(scope.$index, scope.row,scope.row[column.option])"
          >
            <el-checkbox
              v-for="(interset) in scope.row[column.value]"
              :label="interset.id"
              :key="interset.id"
            >{{interset.description}}</el-checkbox>
          </el-checkbox-group>

          <el-checkbox
            v-else-if="scope.row.type===1"
            :indeterminate="scope.row.isIndeterminate"
            v-model="scope.row.checkAll"
            @change="handleCheckAllChange(scope.$index, scope.row,scope.row[column.option])"
          >{{scope.row[column.value]}}</el-checkbox>
          <span v-else>{{scope.row[column.value]}}</span>
          <el-checkbox
            v-if="scope.row[column.act]"
            :indeterminate="scope.row.isIndeterminate"
            v-model="scope.row.checkAll"
            @change="handleCheckAllChange1(scope.$index, scope.row,column.option)"
          >{{scope.row[column.act]}}</el-checkbox>
        </template>
      </el-table-column>
      <slot></slot>
    </el-table>
    <footer>
      <el-button @click="getAuth">確定</el-button>
    </footer>
  </div>
</template>

<script>
/**
  Auth: Lei.j1ang
  Created: 2018/1/19-13:59
*/
import treeToArray from "./eval";
export default {
  name: "treeTable",
  props: {
    data: {
      type: [Array, Object],
      required: true
    },
    columns: {
      type: Array,
      default: () => []
    },
    evalFunc: Function,
    evalArgs: Array,
    expandAll: {
      type: Boolean,
      // 默認(rèn)展開
      default: true
    }
  },
  computed: {
    // 格式化數(shù)據(jù)源
    formatData: function() {
      let tmp;
      if (!Array.isArray(this.data)) {
        tmp = [this.data];
      } else {
        tmp = this.data;
      }
      const func = this.evalFunc || treeToArray;
      const args = this.evalArgs
        ? Array.concat([tmp, this.expandAll], this.evalArgs)
        : [tmp, this.expandAll];
      return func.apply(null, args);
    }
  },
  created() {
    this.defaultSelcet();
  },
  updated() {
    // 需要在vue的updated周期函數(shù)中調(diào)用methods里的方法   否則methods里面獲取不到頁面元素
    this.expandAllClick();
  },
  methods: {
    expandAllClick() {
      // 獲取到頁面元素  模擬點擊可實現(xiàn)讓樹形表格展開
      var els = document.getElementsByClassName("el-icon-minus"); // 獲取點擊的箭頭元素
      console.log(els);
      for (let i = 0; i < els.length; i++) {
        els[i].click();
      }
    },
    showRow: function(row) {
      const show = row.row.parent
        ? row.row.parent._expanded && row.row.parent._show
        : true;
      row.row._show = show;
      return show
        ? "animation:treeTableShow 1s;-webkit-animation:treeTableShow 1s;"
        : "display:none;";
    },
    // 切換下級是否展開
    toggleExpanded: function(trIndex) {
      const record = this.formatData[trIndex];
      record._expanded = !record._expanded;
    },
    // 圖標(biāo)顯示
    iconShow(index, record) {
      return index === 0 && record.children && record.children.length > 0;
    },
    handleCheckAllChange(index, row, opt) {
      this.cc();
      if (row.selectchecked.length && row.selectchecked.length !== opt.length) {
        let arr = [];
        opt.forEach(element => {
          arr.push(element.id);
        });
        row.selectchecked = arr;
        row.checkAll = true;
        row.isIndeterminate = false;
      } else if (!row.selectchecked.length) {
        let arr = [];
        opt.forEach(element => {
          arr.push(element.id);
        });
        row.selectchecked = arr;
        row.checkAll = true;
        row.isIndeterminate = false;
      } else {
        row.selectchecked = [];
        row.checkAll = false;
        row.isIndeterminate = false;
      }
    },
    handleCheckedCitiesChange(index, row, opt) {
      row.checkAll = row.selectchecked.length === opt.length;
      row.isIndeterminate =
        row.selectchecked.length > 0 && row.selectchecked.length < opt.length;
      this.cc();
    },
    handleCheckAllChange1(index, row, opt) {
      if (row.children) {
        row.children.forEach(val => {
          let arr = [];
          if (row.checkAll) {
            val[opt].forEach(element => {
              arr.push(element.id);
            });
            val.selectchecked = arr;
            val.checkAll = true;
            val.isIndeterminate = false;
          } else {
            val.selectchecked = [];
            val.checkAll = false;
            val.isIndeterminate = false;
          }
        });
      }
      this.cc();
    },
    defaultSelcet() {
      this.data.forEach(val => {
        if (val.children) {
          val.children.forEach(el => {
            if (
              el.selectchecked.length &&
              el.selectchecked.length !== el[this.columns[0].option].length
            ) {
              el.isIndeterminate = true;
              el.checkAll = false;
            } else if (
              el.selectchecked.length &&
              el.selectchecked.length === el[this.columns[0].option].length
            ) {
              el.isIndeterminate = false;
              el.checkAll = true;
            } else {
              el.isIndeterminate = false;
              el.checkAll = false;
            }
          });
          this.cc();
        }
      });
    },
    cc() {
      this.data.forEach(val => {
        let checkAllArr = [];
        let isIndeterminateArr = [];
        if (val.children) {
          val.children.forEach(el => {
            checkAllArr.push(el.checkAll);
            isIndeterminateArr.push(el.isIndeterminate);
          });
        }
        if (new Set(checkAllArr).size === 1) {
          // && new Set(isIndeterminateArr).size !== 1
          if (checkAllArr[0] && isIndeterminateArr[0] === false) {
            val.isIndeterminate = false;
            val.checkAll = true;
          } else if (checkAllArr[0] && new Set(isIndeterminateArr).size !== 1) {
            val.isIndeterminate = false;
            val.checkAll = true;
          } else if (
            !checkAllArr[0] &&
            new Set(isIndeterminateArr).size !== 1
          ) {
            val.isIndeterminate = true;
            val.checkAll = false;
          } else if (
            !checkAllArr[0] &&
            new Set(isIndeterminateArr).size === 1
          ) {
            if (!isIndeterminateArr[0]) {
              val.isIndeterminate = false;
              val.checkAll = false;
            } else {
              val.isIndeterminate = true;
              val.checkAll = false;
            }
          } else {
            val.isIndeterminate = false;
            val.checkAll = false;
          }
        } else {
          val.isIndeterminate = true;
          val.checkAll = false;
        }
      });
    },
    getAuth() {
      this.$emit("getAuth", this.data);
    }
  }
};
</script>
<style rel="stylesheet/css">
@keyframes treeTableShow {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}
@-webkit-keyframes treeTableShow {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}
.el-table__body {
  text-align: left;
}
</style>

<style lang="scss" rel="stylesheet/scss" scoped>
footer {
  display: flex;
  justify-content: flex-end;
  margin-top: 15px;
}
$color-blue: #2196f3;
$space-width: 18px;
.ms-tree-space {
  position: relative;
  top: 1px;
  display: inline-block;
  font-style: normal;
  font-weight: 400;
  line-height: 1;
  width: $space-width;
  height: 14px;
  &::before {
    content: "";
  }
}
.processContainer {
  width: 100%;
  height: 100%;
}
table td {
  line-height: 26px;
}
.tree-ctrl {
  position: relative;
  cursor: pointer;
  color: $color-blue;
  margin-left: -$space-width;
}
</style>
  1. 使用組件TableTree.vue
<template>
  <div class="app-container">
    <tree-table :data="data" :columns="columns" border @getAuth="getAuth"></tree-table>

  </div>
</template>

<script>
/**
  Explain:根據(jù)花褲衩的表格改的,
  isIndeterminate屬性是控制多選半選中狀態(tài),
  checkAll是控制全選中狀態(tài)
  selectchecked是放置sonData1選中項
*/
import treeTable from '@/components/treeTable'
export default {
  name: 'treeTableDemo',
  components: { treeTable },
  data () {
    return {
      columns: [
        {
          text: '菜單列表',
          value: 'description',
          width: 200,
          option: 'sonData1'
        },
        {
          text: '功能權(quán)限',
          value: 'sonData1',
          option: 'sonData1',
          act: 'act'
        }
      ],
      data: [
        {
          type: 0,
          'checked': false,
          'id': '1',
          'description': '用戶管理',
          isIndeterminate: false,
          checkAll: false,
          act: '全選',
          children: [
            {
              type: 1,
              id: 6,
              'description': '用戶列表',
              'parentId': '-1',
              'checked': false,
              selectchecked: ['7'],
              checkAll: false,
              isIndeterminate: false,
              'sonData1': [
                {
                  type: 2,
                  'description': '用戶新增',
                  'parentId': '6',
                  'checked': false,
                  'id': '7'
                },
                {
                  type: 2,
                  'description': '用戶修改',
                  'parentId': '6',
                  'checked': false,
                  'id': '8'
                },
                {
                  type: 2,
                  'description': '用戶刪除',
                  'parentId': '6',
                  'checked': false,
                  'id': '9'
                }
              ]
            },
            {
              type: 1,
              id: 13,
              'description': '角色列表',
              'parentId': '-1',
              'checked': false,
              selectchecked: ['10', '11', '12'],
              checkAll: false,
              isIndeterminate: false,
              'sonData1': [
                {
                  type: 2,
                  'description': '角色授權(quán)',
                  'parentId': '6',
                  'checked': false,
                  'id': '10'
                },
                {
                  type: 2,
                  'description': '角色修改',
                  'parentId': '6',
                  'checked': false,
                  'id': '11'
                },
                {
                  type: 2,
                  'description': '角色刪除',
                  'parentId': '6',
                  'checked': false,
                  'id': '12'
                }
              ]
            }
          ]
        },
        {
          type: 0,
          'checked': false,
          'id': '2',
          'description': '設(shè)備管理',
          isIndeterminate: false,
          checkAll: false,
          act: '全選',
          children: [
            {
              type: 1,
              id: 6,
              'description': '設(shè)備列表',
              'parentId': '-1',
              'checked': false,
              selectchecked: [],
              checkAll: false,
              isIndeterminate: false,
              'sonData1': [
                {
                  type: 2,
                  'description': '設(shè)備新增',
                  'parentId': '6',
                  'checked': false,
                  'id': '17'
                },
                {
                  type: 2,
                  'description': '設(shè)備修改',
                  'parentId': '6',
                  'checked': false,
                  'id': '18'
                },
                {
                  type: 2,
                  'description': '設(shè)備刪除',
                  'parentId': '6',
                  'checked': false,
                  'id': '19'
                }
              ]
            }
          ]
        }
      ]
    }
  },
  created () {
  },
  methods: {
    getAuth (data) {
      let opt = []
      data.forEach(val => {
        opt.push(val.id)
        if (val.children) {
          val.children.forEach(el => {
            console.log(val.id)
            if (el.selectchecked.length) {
              opt.push(el.id)
              opt.push(el.selectchecked)
            }
          })
        }
      })
      console.log(data)
      opt = opt.join().split(',').filter(n => { return n })
      console.log(opt)
    }
  }
}
</script>
  1. 測試效果


    最終效果

三、使用說明

  1. columns
    列屬性,要求是一個數(shù)組
    text: 顯示在表頭的文字
    value: 對應(yīng)data的key。treeTable將顯示相應(yīng)的value
    width: 每列的寬度,為一個數(shù)字(可選)
  2. expandAll
    是否默認(rèn)全部展開,boolean值,默認(rèn)為false
  3. evalFunc
    解析函數(shù),function,非必須
    如果不提供,將使用默認(rèn)的evalFunc
  4. evalArgs
    解析函數(shù)的參數(shù),是一個數(shù)組
    請注意,自定義的解析函數(shù)參數(shù)第一個為this.data,第二個參數(shù)為, this.expandAll,你不需要在evalArgs填寫。一定記住,這兩個參數(shù)是強(qiáng)制性的,并且位置不可顛倒 this.data為需要解析的數(shù)據(jù),this.expandAll為是否默認(rèn)展開。
    如你的解析函數(shù)需要的參數(shù)為(this.data, this.expandAll,1,2,3,4),那么你只需要將[1,2,3,4]賦值給evalArgs就可以了
    如果你的解析函數(shù)參數(shù)只有(this.data, this.expandAll),那么就可以不用填寫evalArgs了。
  5. slot
    這是一個自定義列的插槽。
    默認(rèn)情況下,treeTable只有一行行展示數(shù)據(jù)的功能。但是一般情況下,我們會要給行加上一個操作按鈕或者根據(jù)當(dāng)行數(shù)據(jù)展示不同的樣式,這時我們就需要自定義列了。
    slot和columns屬性可同時存在,columns里面的數(shù)據(jù)列會在slot自定義列的左邊展示

三、樹形數(shù)據(jù)(2.11.1)

https://element.eleme.io/#/zh-CN/component/table

<template>
  <div>
    <el-table
      :data="tableData"
      style="width: 100%;margin-bottom: 20px;"
      row-key="id"
      border
      :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
    >
      <el-table-column prop="name" label="名稱" sortable width="180"></el-table-column>
    </el-table>
  </div>
</template>
<script>
export default {
  data() {
    return {
      tableData: [
        {
          children: [
            {
              name: "菜單管理",
              id: "060ac069ea5b1b1b90e200d94f7941a2"
            },
            {
              name: "字典管理",
              id: "68aa1ca036ef8e6d606651f258321f88"
            },
            {
              children: [
                {
                  name: "刪除",
                  id: "0e64c997bcec402b7a840fc18e7e4e82"
                },
                {
                  name: "查詢",
                  id: "52ae959c875c6fc521ba4ea546ee88ed"
                },
                {
                  name: "添加",
                  id: "59c86152b4e0b345636eb3a48d9ad263"
                },
                {
                  name: "導(dǎo)出",
                  id: "66d8a79be81d61d4e75feccfe2aee94e"
                },
                {
                  name: "更新",
                  id: "acc80082612d67847940985dfe53268b"
                },
                {
                  name: "導(dǎo)入",
                  id: "e5668f14d71db22cb2ad063c87f0b6d3"
                }
              ],
              name: "角色管理",
              id: "951581fdede1c585a5b7f2de16eddfe2"
            },
            {
              name: "組織機(jī)構(gòu)",
              id: "3504711eedb26cab2b9eb2f8c3433aa7"
            },
            {
              name: "用戶管理",
              id: "6221da7dac0e80af56d18f9355003438"
            }
          ],
          name: "系統(tǒng)設(shè)置",
          id: "0b423292e0e27485cdd5257be6701a9f"
        }
      ]
    };
  },
};
</script>
結(jié)果展現(xiàn)

說明:
支持樹類型的數(shù)據(jù)的顯示。當(dāng) row 中包含 children 字段時,被視為樹形數(shù)據(jù)。渲染樹形數(shù)據(jù)時,必須要指定 row-key。支持子節(jié)點數(shù)據(jù)異步加載。設(shè)置 Table 的 lazy 屬性為 true 與加載函數(shù) load 。通過指定 row 中的 hasChildren 字段來指定哪些行是包含子節(jié)點。children 與 hasChildren 都可以通過 tree-props 配置。
新版功能更簡單,更好使用。
注意:
實際測試,hasChildren 屬性不添加也可,注意id不要重復(fù),default-expand-all 屬性無需設(shè)置值,添加該屬性全部展開,不添加折疊。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容