ElementUI的el-tree樹形組件實現分配權限注意的點


 前言

隨着Vue的爆火(很大部分是我們國內開發者功勞),自開源以來,在GitHub上已經斬獲176k票star,位居前三,所以餓了么推出的基於Vue的前端框架ElementUI以簡潔的UI與實用的組件等普及度越來越高。

下面是一個完整的el-tree實例,包含了我所遇到的坑。

Template代碼

        <el-tree style="height:100%;" :data="data" @check="handleCheckChange" show-checkbox node-key="menuid" ref="authTree"
          highlight-current :props="defaultProps">
        </el-tree>
  • data:樹結構綁定的數據源,后台借口傳過來的數據
  • check函數:當復選框被點擊的時候觸發
  • show-checkbox:顯示選項的多選框
  • node-key="menuid":什么意思呢,官網很模糊只是說一些功能都必須要提供這個屬性(比如選中等等),它其實就是我們數據源中的唯一標識,比如數據庫中你的權限表主鍵為id,這里就是填id
  • ref=""authTree":創建引用到此組件的類似指針的功能
  • :props:"defaultProps":這個屬性就是定義你要綁定的子節點和展示標題相關,官網有四個屬性可選值,比較常用的就這兩個,其他的可以移步官網
  •   label:定義你要綁定的標簽屬性
  •   children:定義子樹的屬性值

script代碼

只用語言是描述不了的,我直接在代碼中解釋:

    data: function() {
      return {
        page: 1,//分頁
        rows: 10,//行數
        total: 0,//總記錄數
        data: [],//我們后台接口訪問到的展示數據
        defaultProps: {//這里就是props屬性綁定的值
          children: 'permissions', //填寫你的數據格式里面的子集,我這里是permissions
          label: 'menuname' //填寫你要展示的標題名稱,我這是menuname
        },
        //權限Tree選中的節點
        moduleids: [],
        //獲取table當前選中行row對象
        curRow: null
      };
    },

我后台的數據結構:

這個結構看懂了關系就一目了然,node-key屬性就是我們選中節點的值,我們將這個值發送到后端進行操作,后台只需要根據逗號分割就可以得到所有選中的權限節點,也就能夠理解為什么官方說這個屬性是必須要指定的。

然后是方法部分的代碼,比較重要的參數傳遞和綁值的問題:

        let params = {
          roleId: this.curRow.roleId,
          sysPermission: this.moduleids.toString()//傳遞參數時直接toString也更省事,后台只需切割一下。
        }

巨坑(查詢角色的權限后父節點的子節點全部選中了)

明明查詢到的是很正常的數組,但是父節點的所有子節點都被選中了,這時候只能用一個方法 setChecked() ,另外兩個方法( setCheckedKeys()  setCheckedNodes() )會造成子節點選中的情況。
例如:A 是 父節點, B C D 分別是 子節點,勾選了 B節點,checkedId僅包含B,沒有問題,如果checkedId包含了A和B,A節點下的節點都被選中。
后台必須返回節點的id數組,利用循環綁定node-key。

返回一個id數組:

查詢角色對應權限並且綁定選擇框:

 queryRoleModuleId: function(roleId) {
        //先清空,再查權限
        this.$refs['authTree'].setCheckedKeys([]);
        var url = this.axios.urls.PERMISSION_QUERYPERMISSIONBYROLEID;
        this.axios.post(url, {
          roleId: roleId
        }).then(resp => {
          this.moduleids = resp.data.data;
          console.log(this.moduleids);
          if (this.moduleids) {
            this.$nextTick(() => {
              this.moduleids.forEach(value=>{//真的大坑,我自己摸索好久!!!
                this.$refs.authTree.setChecked(value, true,false) //給樹節點賦值
              });
              this.checkStrictly = false //重點: 賦值完成后 設置為false
            })
          }

        }).catch();
      },

獲取選中節點的坑

默認的選中是不包含父節點的,所以我們需要拼接半選中的節點:

      handleCheckChange: function(data, checked) {
        //checked.checkedKeys  選中的節點id數組z
        //checked.halfCheckedKeys 半選中節點id數組
        this.moduleids = checked.halfCheckedKeys.concat(checked.checkedKeys); //選中節點和半選中節點所有的id
      }

整個組件源碼

<template>
  <el-container class="auth-container">
    <el-header style="width:100%;margin:5px 0px;padding:0px 15px;">
      <el-form :inline="true">
        <el-form-item>
          <el-input v-model="roleName" size="small" placeholder="角色名稱"></el-input>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" style="background-color: #42B983;" size="small" @click="query(1)"><i class="el-icon-search"></i>搜索</el-button>
        </el-form-item>
        <el-form-item>
          <el-button size="small" @click="refresh()"><i class="el-icon-refresh"></i>刷新</el-button>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" size="small" icon="el-icon-edit-outline" @click="saveAuth">保存角色權限</el-button>
        </el-form-item>
      </el-form>
    </el-header>
    <el-container class="auth-container">
      <el-aside class="auth-aside">
        <el-tree style="height:100%;" :data="data" :check-strictly="checkStrictly" @check="handleCheckChange"
          show-checkbox node-key="menuid" ref="authTree" highlight-current :props="defaultProps">
        </el-tree>
      </el-aside>
      <el-main class="auth-main">
        <!--數據表格-->
        <el-table size="medium" :loading="true" :header-cell-style="{background:'#eef1f6',color:'#606266'}" ref="singleTable"
          :highlight-current-row="true" @row-click="rowClick" :data="result" style="width: 100%">
          <el-table-column type="index" label="序號" width="50" align="center" :index="indexMethod"></el-table-column>
          </el-table-column>
          <el-table-column prop="roleName" label="角色名稱" align="center">
            <template slot-scope="scope">
              <el-button type="text" @click="queryRoleModuleId(scope.row.roleId)">{{scope.row.roleName}}</el-button>
            </template>
          </el-table-column>
          <el-table-column prop="roleTime" label="上次更新時間" :formatter="formatter" align="center">
          </el-table-column>
        </el-table>

        <!--分頁組件-->
        <div class="paginationClass">
          <el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="page"
            :page-sizes="[10, 20, 30, 40]" :page-size="rows" layout="total, sizes, prev, pager, next, jumper" :total="total">
          </el-pagination>
        </div>

      </el-main>
    </el-container>
  </el-container>
</template>
<script>
  import date from '../../api/date.js'
  export default {
    name: 'BookList',
    data: function() {
      return {
        result: [],
        roleName: '',
        page: 1,
        rows: 10,
        total: 0,
        data: [],
        checkStrictly: false,
        defaultProps: {
          children: 'permissions', //填寫你的數據格式里面的子集
          label: 'menuname' //填寫你要展示的標題名稱
        },
        //權限Tree選中的節點
        moduleids: [],
        //獲取table當前選中行row對象
        curRow: null
      };
    },
    methods: {
      refresh() {
        this.roleName = '';
        this.page = 1;
        this.rows = 10;
        this.curRow = null;
        this.$refs.authTree.setCheckedKeys([]);
        //折疊
        let nodes = this.$refs.authTree.store._getAllNodes();
        for (let i = 0; i < nodes.length; i++) {
          nodes[i].expanded = false
        }
        this.$forceUpdate();
        this.query(1);
      },
      formatter(row, column) {
        return date(row.roleTime);
      },
      //自定義索引
      indexMethod: function(index) {
        return (this.page - 1) * this.rows + (index + 1);
      },
      //分頁
      handleSizeChange: function(rows) {
        this.page = 1;
        this.rows = rows;
        this.query(1);
      },
      handleCurrentChange: function(page) {
        this.page = page;
        this.query(page);
      },
      //數據查詢
      query: function(num) {
        var params = {
          roleName: this.roleName,
          page: num !== null ? num : this.page,
          rows: this.rows,
        }
        var url = this.axios.urls.ROLE_QUERYROLEPAGER;
        this.axios.post(url, params).then(resp => {
          this.result = resp.data.data;
          this.total = resp.data.total;
        }).catch();
      },
      //表格行的單擊事件
      rowClick: function(row, column, event) {
        this.curRow = row;
      },
      //保存權限
      saveAuth: function() {
        if (this.moduleids.length <= 0) {
          this.$message({
            showClose: true,
            message: '請選擇權限分配給指定角色!',
            type: 'error'
          });
          return false;
        }
        if (null == this.curRow) {
          this.$message({
            showClose: true,
            message: '請選中你要分配權限的角色!',
            type: 'error'
          });
          return false;
        }
        if (this.curRow.roleId == 1) {
          return this.$message({
            type: 'error',
            message: '管理員不允許操作哦!'
          });
        }
        let params = {
          roleId: this.curRow.roleId,
          sysPermission: this.moduleids.toString() //傳遞參數時直接toString也更省事,后台只需切割一下。
        }
        //保存角色權限
        var url = this.axios.urls.PERMISSION_SAVEATUTH;
        this.axios.post(url, params).then(resp => {
          this.$message({
            showClose: true,
            message: resp.status == 200 ? resp.data.msg : '授予權限失敗!',
            type: resp.status == 200 ? 'success' : 'error'
          });
          //保存成功,刷新列表和清空數據信息
          this.curRow = null;
          this.moduleids = [];
          this.query(1);
          this.$refs['authTree'].setCheckedKeys([]);
        }).catch();
      },
      queryRoleModuleId: function(roleId) {
        //先清空,再查權限
        this.$refs['authTree'].setCheckedKeys([]);
        var url = this.axios.urls.PERMISSION_QUERYPERMISSIONBYROLEID;
        this.axios.post(url, {
          roleId: roleId
        }).then(resp => {
          this.moduleids = resp.data.data;
          console.log(this.moduleids);
          if (this.moduleids) {
            this.$nextTick(() => {
              this.moduleids.forEach(value=>{//真的大坑,我自己摸索好久!!!
                this.$refs.authTree.setChecked(value, true,false) //給樹節點賦值
              });
              this.checkStrictly = false //重點: 賦值完成后 設置為false
            })
          }

        }).catch();
      },
      handleCheckChange: function(data, checked) {
        //checked.checkedKeys  選中的節點id數組z
        //checked.halfCheckedKeys 半選中節點id數組
        this.moduleids = checked.halfCheckedKeys.concat(checked.checkedKeys); //選中節點和半選中節點所有的id
      },
    },
    created: function() {
      //加載權限樹
      if (this.$store.getters.getTreeList.length <= 0) {
        this.axios.post(this.axios.urls.PERMISSION_QUERYPERMISSIONPAGER, {
          pagination: false
        }).then(res => {
          this.$store.commit('setTreeList', res.data.data);
        }).catch(err => console.log(err));
      }
      //得到所有節點
      this.query(1);
      this.data = this.$store.getters.getTreeList;
    }
  }
</script>
<style scoped>
  .paginationClass {
    margin-top: 15px;
    bottom: 0;
    right: 0;
    float: right;
  }

  .auth-container {
    height: 100%;
    width: 100%;
    display: flex;
    object-fit: fill;

  }

  .auth-aside {
    width: 200px !important;
    padding: 0px 10px;
    height: 100%;
    object-fit: fill;
    margin-left: 5px;
  }

  .auth-main {
    padding: 0px;
    height: 100%;
    margin-right: 15px;
  }

  .el-row-bg {
    padding-top: 10px;
    padding-left: 10px;
    color: #000000;
    font-weight: bold;
    height: 60px;
    background: #f4f4f5;
  }
</style>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM