vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > Vue3 ElementUI 多选框

Vue3+ElementUI 多选框中复选框和名字点击方法效果分离方法

作者:kangkang-

这篇文章主要介绍了Vue3+ElementUI 多选框中复选框和名字点击方法效果分离方法,文中补充介绍了VUE-Element组件 CheckBox多选框使用方法,需要的朋友可以参考下

Vue3+ElementUI 多选框中复选框和名字点击方法效果分离

现在的需求为

比如我点击了Option A ,触发点击Option A的方法,并且复选框不会取消勾选,分离的方法。

<el-checkbox-group v-model="mapWork.model_checkArray.value">
<div class="naipTypeDom" v-for="item in mapWork.modelList.value" :key="item.id">
  <el-checkbox :label="item.id" :disabled="!mapWork.mould_layer_isShow.value">
<span @click.prevent="flyToMould(item.id)">{{ item.modelName }}</span>
</el-checkbox>
</div>
</el-checkbox-group>

通过Vue事件处理的方法.prevent来阻止。<!-- 提交事件将不再重新加载页面 -->

VUE-Element组件 CheckBox多选框

一、用法说明:

1、el-checkbox标签内的内容,绑定点击事件,点击的时候会触发选中/不选中,如果不希望事件冒泡,可以使用

event.preventDefault();

如我:

 <el-checkbox-group v-model="codes">
                      <template v-for="(item, index) in allCodes">
                        <el-checkbox
                          :label="item.value"
                          :key="item.value"
                          @click.native="handleCheckRegion($event, item.value)"
                          >{{ item.value }}
                          <a class="detail-btn" :key="index" @click="clickToDetail($event, item.value)"
                            >详情</a
                          >
                        </el-checkbox>
                      </template>
                    </el-checkbox-group>
 clickToDetail(e, code) {
      if (e.target.tagName !== 'A') return;
      //阻止选中
      e.preventDefault();
      //你的逻辑
    }

2、在checkBox中加上按钮:

 <el-checkbox-group v-model="checkedRoleCodes" @change="handleCheckedRoleChange">
                  <template v-for="(role, index) in allRoles">
                    <el-checkbox
                      :label="role.value"
                      :key="role.value"
                      @click.native="handleCheckRole($event, role)"
                      :indeterminate="role.indeterminate"
                      >{{ role.text }}
                      <a class="detail-btn" @click="clickRoleToRegionDetail($event, role)" :key="index">详情</a>
                    </el-checkbox>
                  </template>
                </el-checkbox-group>

现在希望按钮统一排列在最有侧:给按钮加上右浮动,并修改.el-checkbox__label的display属性使按钮的浮动生效即可:

/deep/ .el-checkbox__label {
  display: inline;
  padding-left: 10px;
  line-height: 19px;
  font-size: 14px;
}
 .detail-btn {
      float: right;
    }

 二、举例

1、例1,现有通讯录,点击出现通讯录选择弹框。弹框右侧为选择的用户列表,可以点击删除,左侧默认为角色列表,可以勾选角色,也可以点击角色进入角色详情页勾选具体的用户。还可以在左侧上方搜索用户名或者账号出来用户列表来勾选。其中,角色列表复选框、搜索用户列表复选框、选中的用户列表复选框,三者的选中状态需要关联(不勾选、半选、全选)。

 代码实现:

 父组件:

<div class="user-div" @click="openSelectUserDialog">
     <template v-for="(item, index) in formValidate.sendUers">
         <span class="user-item" :title="item" :key="index">{{
              item.userName + '(' + item.userAccount + ')'
          }}</span></template
     >
 </div>
    <!--弹框-->
 <div>
     <SelectUser
      :selectUserDialogVisible="selectUserDialogVisible"
      :initUers="formValidate.sendUers"
	  v-if="selectUserDialogVisible"
      @cancelSelectUser="cancelSelectUser"
      @changeSelectUser="changeSelectUser"
    ></SelectUser>
</div>
 //选择用户弹框
    openSelectUserDialog() {
      this.selectUserDialogVisible = true;
    },
    //关闭用户选择弹框
    cancelSelectUser() {
      this.selectUserDialogVisible = false;
    },
    //选择用户
    changeSelectUser(users) {
      this.formValidate.sendUers = users;
      this.cancelSelectUser();
    },

 子组件:

<!-- @format -->
<template>
  <div>
    <el-dialog title="通讯录" :visible.sync="dialogVisible" width="60%" @close="cancel">
      <el-row class="user-row">
        <el-col :span="12" class="department-user-col scoll-col">
          <div class="header-query">
            <el-input v-model="userNameOrAccount"
              ><i class="el-icon-search" slot="suffix" @click="queryUser"></i
            ></el-input>
          </div>
          <div class="department-user">
            <!--用户列表复选框-->
            <template v-if="queryUsers && queryUsers.length > 0">
              <el-checkbox
                :indeterminate="userIsIndeterminate"
                @change="handleCheckAllUserChange"
                v-model="userCheckAll"
                >全选</el-checkbox
              >
              <el-checkbox-group v-model="checkedUserAccounts">
                <el-checkbox
                  v-for="user in queryUsers"
                  :label="user.userAccount"
                  :key="user.userAccount"
                  @click.native="clickUser($event, user)"
                  >{{ user.userName + '(' + user.userAccount + ')' }}</el-checkbox
                >
              </el-checkbox-group>
            </template>
            <!--角色复选框-->
            <template v-else>
              <el-checkbox :indeterminate="roleIsIndeterminate" @change="handleCheckAllRole" v-model="roleCheckAll"
                >全选</el-checkbox
              >
              <el-checkbox-group v-model="checkedRoleCodes" @change="handleCheckedRoleChange">
                <template v-for="(role, index) in allRoles">
                  <el-checkbox
                    :label="role.value"
                    :key="role.value"
                    @click.native="clickRole($event, role)"
                    :indeterminate="role.indeterminate"
                    >{{ role.text }}
                    <a class="detail-btn" @click="clickToRoleDetail($event, role)" :key="index">详情</a>
                  </el-checkbox>
                </template>
              </el-checkbox-group>
            </template>
          </div>
        </el-col>
        <!--右侧-->
        <el-col :span="12" class="user-col scoll-col">
          <!--选中的用户列表-->
          <div class="user-item" v-for="(user, index) in addUsers" :key="index">
            {{ user.userName + '(' + user.userAccount + ')' }}
            <a href="javascript:void(0);" rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  @click="deleteAddUser(index)" class="delete-icon">X</a>
          </div>
        </el-col>
      </el-row>
      <span slot="footer" class="dialog-footer">
        <el-button @click="cancel()">取 消</el-button>
        <el-button type="primary" @click="ok()">确 定</el-button>
      </span>
    </el-dialog>
  </div>
</template>
<script>
export default {
  props: {
    selectUserDialogVisible: {},
    //初始化的用户列表
    initUers: {}
  },
  data() {
    return {
      dialogVisible: false,
      userNameOrAccount: '',
      //本界面的用户列表
      addUsers: [],
      //勾选的用户账号列表
      checkedUserAccounts: [],
      //用户列表
      queryUsers: [], //所有可以选择的用户
      //用户多选框
      userIsIndeterminate: true,
      userCheckAll: false,
      //角色列表
      allRoles: [], //所有可以选择的角色
      //勾选的角色code
      checkedRoleCodes: [],
      //角色选择复选框
      roleIsIndeterminate: true,
      roleCheckAll: false
      //从角色列表中选择的用户
    };
  },
  created() {
    this.init();
  },
  methods: {
    init() {
      this.findRoles();
      this.addUsers = this.addUsers.concat(this.initUers);
      this.handleCheckedValue();
      this.dialogVisible = this.selectUserDialogVisible;
    },
    //从全量用户中获取勾选的账号和角色编码信息,去重
    handleCheckedValue() {
      //勾选的用户
      this.handleCheckUser();
      //勾选的角色
      this.handleCheckRoleCode();
    },
    handleCheckUser() {
      let checkedUserAccounts = this.addUsers.map(function(item) {
        return item.userAccount;
      });
      this.checkedUserAccounts = Array.from(new Set(checkedUserAccounts));
    },
    handleCheckRoleCode() {
      let checkedRoleCodes = this.addUsers.map(function(item) {
        return item.roleCode;
      });
      this.checkedRoleCodes = Array.from(new Set(checkedRoleCodes));
    },
    findRoles() {
      this.$api['role/getAllRoles']({
      }).then(data => {
        data.forEach(item => {
          item.indeterminate = false;
        });
        this.allRoles = data;
      });
    },
    cancel() {
      this.dialogVisible = false;
      this.$emit('cancelSelectUser');
    },
    ok() {
      this.dialogVisible = false;
      //发送对象 = 初始化的用户+用户列表中选择的用户+角色列表选择的用户
      this.$emit('changeSelectUser', this.addUsers);
    },
    //角色全选/全部取消,全量
    handleCheckAllRole(val) {
      if (val) {
        //全选
        this.checkedRoleCodes = this.allRoles.map(function(item) {
          return item.value;
        });
        this.getUsersByRoles(this.checkedRoleCodes).then(users => {
          this.addUsers = users;
        });
        this.handleCheckUser();
      } else {
        //取消全选
        this.addUsers = [];
        this.checkedUserAccounts = [];
        this.checkedRoleCodes = [];
      }
      this.roleIsIndeterminate = false;
    },
    //角色复选框点击事件
    clickRole(e, role) {
      // 因为原生click事件会执行两次,第一次在label标签上,第二次在input标签上,故此处理
      if (e.target.tagName === 'INPUT' || e.target.tagName === 'A') return;
      let roleCode = role.value;
      if (this.checkedRoleCodes.indexOf(roleCode) === -1) {
        //选中
        this.getUsersByRoles(new Array(roleCode)).then(users => {
          let addUsers = this.addUsers.concat(users);
          this.addUsers = this.unique(addUsers);
        });
      } else {
        //取消
        role.indeterminate = false;
        this.addUsers = this.addUsers.filter(function(item) {
          return item.roleCode !== roleCode;
        });
      }
      this.handleCheckUser();
    },
    //角色详情单击事件详情,取A标签的事件
    clickToRoleDetail(e, role) {
      if (e.target.tagName !== 'A') return;
      let roleCode = role.value;
      //阻止选中
      // this.checkedRoleCodes = this.checkedRoleCodes.filter(item => {
      //   return item !== roleCode;
      // });
      this.getUsersByRoles(new Array(roleCode)).then(users => {
        this.queryUsers = users;
        let addUsers = this.addUsers.concat(users);
        this.addUsers = this.unique(addUsers);
        this.handleCheckUser();
      });
    },
    //角色选择改变
    handleCheckedRoleChange(roleCodes) {
      let checkedCount = roleCodes.length;
      let totalCount = this.allRoles.length;
      this.roleCheckAll = checkedCount === totalCount;
      this.roleIsIndeterminate = checkedCount > 0 && checkedCount < totalCount;
    },
    async getUsersByRoles(roleCodes) {
      let roleCodeStr = roleCodes.join(',');
      let queryUsers = [];
      await this.$api['personDetail/listPersonnelDetailByPositionTypeCodes']({
        positionTypeCodeList: roleCodeStr
      }).then(data => {
        queryUsers = data;
      });
      return queryUsers;
    },
    //搜索用户
    queryUser() {
      if (this.userNameOrAccount) {
        this.$api['personDetail/listPersonnelDetailByNameOrAccount']({
          nameOrAccount: this.userNameOrAccount
        }).then(data => {
          this.queryUsers = data;
        });
      } else {
        this.queryUsers = [];
      }
    },
    //用户全选,用户是角色的子集,故用户新增/删除需要做比对
    handleCheckAllUserChange(val) {
      if (val) {
        //全选,addUsers加上queryUsers,去重
        this.addUsers = this.addUsers.concat(this.queryUsers);
      } else {
        //全部取消,addUsers去掉所有queryUsers
        let queryUserAccounts = this.queryUsers.map(function(item) {
          return item.userAccount;
        });
        this.addUsers = this.addUsers.filter(function(item) {
          return queryUserAccounts.every(function(item1) {
            return item.userAccount !== item1;
          });
        });
      }
      this.addUsers = this.unique(this.addUsers);
      //复选框勾选绑定值改变
      this.handleCheckedValue();
      this.userIsIndeterminate = false;
    },
    //用户复选框点击事件
    clickUser(e, user) {
      // 因为原生click事件会执行两次,第一次在label标签上,第二次在input标签上,故此处理
      if (e.target.tagName === 'INPUT' || e.target.tagName === 'A') return;
      let userAccount = user.userAccount;
      let roleCode = user.roleCode;
      if (this.checkedUserAccounts.indexOf(userAccount) === -1) {
        //选中
        let addUser = this.queryUsers.find(item => {
          return item.userAccount === userAccount;
        });
        this.addUsers.push(addUser);
        this.addUsers = this.unique(this.addUsers);
      } else {
        //取消
        this.addUsers = this.addUsers.filter(function(item) {
          return item.userAccount !== userAccount;
        });
      }
      //全选状态改变
      this.userAndRoleAllCheckStatusChange();
      //角色选中值变化
      this.handleCheckedValue();
      //角色复选框选中状态改变
      this.roleUserCheckStatusChange(roleCode);
    },
    //用户、角色全选框选中状态改变
    userAndRoleAllCheckStatusChange() {
      //右侧用户列表包含左侧复选框用户列表,userCheckAll为true,userIsIndeterminate为false
      let userCheckAll = true;
      this.queryUsers.forEach(item => {
        if (this.checkedUserAccounts.indexOf(item.userAccount) < 0) {
          userCheckAll = false;
          return;
        }
      });
      this.userCheckAll = userCheckAll;
      this.userIsIndeterminate = !this.userCheckAll;
      //角色
      this.handleCheckedRoleChange(this.checkedRoleCodes);
    },
    //角色复选框选中状态改变
    roleUserCheckStatusChange(roleCode) {
      this.allRoles.forEach(item => {
        if (item.value === roleCode) {
          if (this.checkedRoleCodes.indexOf(roleCode) !== -1) {
            item.indeterminate = true;
          } else {
            item.indeterminate = false;
          }
        }
      });
    },
    //去重
    unique(arr) {
      var obj = {};
      arr = arr.reduce(function(item, next) {
        obj[next.userAccount] ? '' : (obj[next.userAccount] = true && item.push(next));
        return item;
      }, []);
      return arr;
    },
    //删除本次新增的用户
    deleteAddUser(index) {
      let deleteUser = this.addUsers[index];
      let deleteUserAccount = deleteUser.userAccount;
      let roleCode = deleteUser.roleCode;
      //1、用户复选框绑定值同步删除
      this.checkedUserAccounts = this.checkedUserAccounts.filter(function(value) {
        return value !== deleteUserAccount;
      });
      //2、最后本次新增的用户删除
      this.addUsers.splice(index, 1);
      //3、角色复选框绑定值同步变化
      this.handleCheckRoleCode();
      //4、用户全选状态改变
      this.userAndRoleAllCheckStatusChange();
      //5、角色选中状态改变,设置已选且有删除用户操作的角色indeterminate为true
      this.roleUserCheckStatusChange(roleCode);
    }
  },
  watch: {
    queryUsers: {
      handler: function(val) {
        this.userAndRoleAllCheckStatusChange();
      }
    }
  }
};
</script>
<style scoped lang="less">
.user-row {
  .department-user-col {
    /deep/ .el-checkbox {
      color: #606266;
      font-weight: 500;
      font-size: 14px;
      cursor: pointer;
      user-select: none;
      margin-right: 30px;
      display: block;
    }
    .detail-btn {
      float: right;
      margin-left: 20px;
    }
  }
  .user-col {
    .user-item {
      margin-left: 10px;
    }
    .delete-icon {
      float: right;
      margin-right: 20px;
    }
  }
  //滚动条
  .scoll-col {
    max-height: 300px;
    overflow-y: auto;
  }
}
</style>

已知问题:某角色先选中,然后删除用户,该角色变为半选,如果该用户通过搜索用户列表的方式来单独勾选或者全选重新加上,该角色的状态仍为半选。因为需要全量判断,性能较差。

2、举例2:例1是从角色跳转到用户,现在再加一层关系,角色跳转到区域(固定的省份),区域再调转到用户:

父组件:这里对角色、区域、区域复选框状态做了一个缓存

<!-- @format -->
<template>
  <div>
    <div class="container">
      <el-form ref="formValidate" :model="formValidate" :rules="ruleValidate" label-position="left" label-width="100px">
        <el-form-item  :required="true">
          <div class="user-div" @click="openSelectUserDialog">
            <template v-for="(item, index) in formValidate.receiverList">
              <span class="user-item" :title="item" :key="index">{{
                item.userName + '(' + item.userAccount + ')'
              }}</span></template
            >
          </div>
        </el-form-item>
      </el-form>
    </div>
    <!--弹框-->
    <div>
      <SelectUser
        :selectUserDialogVisible="selectUserDialogVisible"
        :initUers="formValidate.receiverList"
        :cacheAllRoles="cacheAllRoles"
        :cacheAllRegions="cacheAllRegions"
        :cacheRoleRegionIndeterminateMap="cacheRoleRegionIndeterminateMap"
        v-if="selectUserDialogVisible"
        @cancelSelectUser="cancelSelectUser"
        @changeSelectUser="changeSelectUser"
      ></SelectUser>
    </div>
  </div>
</template>
<script>
import SelectUser from './children/select-user';
export default {
  data() {
    return {
      // 表单数据
      formValidate: {
        receiverList: []
      },
	  selectUserDialogVisible: false,
      //通讯录缓存的角色信息
      cacheAllRoles: [],
      //通讯录缓存的区域信息
      cacheAllRegions: [],
      //通讯录缓存的区域复选框状态
      cacheRoleRegionIndeterminateMap: {}
    };
  },
  methods: {
    //选择用户弹框
    openSelectUserDialog() {
      this.selectUserDialogVisible = true;
    },
    //关闭用户选择弹框
    cancelSelectUser() {
      this.selectUserDialogVisible = false;
    },
    //选择用户
    changeSelectUser(users, cacheAllRoles, cacheAllRegions, cacheRoleRegionIndeterminateMap) {
      this.formValidate.receiverList = users;
      this.cancelSelectUser();
      this.cacheAllRoles = cacheAllRoles;
      this.cacheAllRegions = cacheAllRegions;
      this.cacheRoleRegionIndeterminateMap = cacheRoleRegionIndeterminateMap;
    }
   }
  },
  components: {
    SelectUser
  }
};
</script>

子组件:右侧用户采用滚动加载

<!-- @format -->
<template>
  <div>
    <el-dialog title="通讯录" :visible.sync="dialogVisible" width="60%" @close="cancel">
      <el-row class="user-row">
        <el-col :span="12" class="role-region-user-col scoll-col">
          <div class="header-query">
            <el-input v-model.trim="userNameOrAccount" placeholder="输入姓名/账号" size="mini"
              ><i class="el-icon-search" slot="suffix" @click="searchUser"></i
            ></el-input>
          </div>
          <div class="role-region-user">
            <!--错误提示-->
            <template v-if="isNoDataShow">
              <p class="no-data">无搜索结果</p>
            </template>
            <!--正常数据-->
            <template v-else>
              <!--用户列表复选框-->
              <template v-if="queryUsers && queryUsers.length > 0">
                <el-row>
                  <el-col :span="20">
                    <el-checkbox
                      :indeterminate="userIsIndeterminate"
                      @change="handleCheckAllUser"
                      v-model="userCheckAll"
                      >全选</el-checkbox
                    >
                    <el-checkbox-group v-model="checkedUserAccounts">
                      <el-checkbox
                        v-for="user in queryUsers"
                        :label="user.userAccount"
                        :key="user.userAccount"
                        @click.native="handleCheckUser($event, user)"
                        @change="checkUserChange"
                        >{{ user.userName + '(' + user.userAccount + ')' }}</el-checkbox
                      >
                    </el-checkbox-group></el-col
                  >
                  <el-col :span="2" v-if="isFromClickRegion">
                    <a @click="goBackToRegion($event)" class="goback-to-role"
                      ><svg
                        t="1628844742588"
                        class="icon"
                        viewBox="0 0 1482 1024"
                        version="1.1"
                        xmlns="http://www.w3.org/2000/svg"
                        p-id="2061"
                        width="40"
                        height="40"
                      >
                        <path
                          d="M584.884104 272.714912V0L0 477.152657l584.884104 477.073906V674.817811c406.119203 0 690.568023 108.991464 893.588249 347.528417-81.271091-340.755826-324.926863-681.354149-893.588249-749.631316"
                          fill="#467CFD"
                          p-id="2062"
                        ></path></svg
                    ></a>
                  </el-col>
                </el-row>
              </template>
              <!--角色复选框-->
              <template v-else-if="!isRegionListShow">
                <el-checkbox :indeterminate="roleIsIndeterminate" @change="handleCheckAllRole" v-model="roleCheckAll"
                  >全选</el-checkbox
                >
                <el-checkbox-group v-model="checkedRoleCodes" @change="handleCheckedRoleChange">
                  <template v-for="(role, index) in allRoles">
                    <el-checkbox
                      :label="role.value"
                      :key="role.value"
                      @click.native="handleCheckRole($event, role)"
                      :indeterminate="role.indeterminate"
                      >{{ role.text }}
                      <a class="detail-btn" @click="clickRoleToRegionDetail($event, role)" :key="index">详情</a>
                    </el-checkbox>
                  </template>
                </el-checkbox-group>
              </template>
              <!--区域复选框-->
              <template v-else>
                <el-row>
                  <el-col :span="20">
                    <el-checkbox
                      :indeterminate="roleRegionAllIndeterminateMap[currentClickRoleCode]"
                      v-model="roleRegionAllCheckMap[currentClickRoleCode]"
                      @change="handleCheckAllRegion"
                      >全选</el-checkbox
                    >
                    <el-checkbox-group v-model="checkedRoleRegionsMap[currentClickRoleCode]">
                      <template v-for="(item, index) in allRegions">
                        <el-checkbox
                          :label="item.value"
                          :key="item.value"
                          :indeterminate="roleRegionIndeterminateMap[currentClickRoleCode][item.value]"
                          @click.native="handleCheckRegion($event, item.value)"
                          >{{ item.value }}
                          <a class="detail-btn" :key="index" @click="clickRegionToUserDetail($event, item.value)"
                            >详情</a
                          >
                        </el-checkbox>
                      </template>
                    </el-checkbox-group>
                  </el-col>
                  <el-col :span="2">
                    <a @click="goBackToRole($event)" class="goback-to-role"
                      ><svg
                        t="1628844742588"
                        class="icon"
                        viewBox="0 0 1482 1024"
                        version="1.1"
                        xmlns="http://www.w3.org/2000/svg"
                        p-id="2061"
                        width="40"
                        height="40"
                      >
                        <path
                          d="M584.884104 272.714912V0L0 477.152657l584.884104 477.073906V674.817811c406.119203 0 690.568023 108.991464 893.588249 347.528417-81.271091-340.755826-324.926863-681.354149-893.588249-749.631316"
                          fill="#467CFD"
                          p-id="2062"
                        ></path></svg
                    ></a>
                  </el-col>
                </el-row>
              </template>
            </template>
          </div>
        </el-col>
        <!--右侧-->
        <el-col :span="12" class="user-col">
          <!--选中的用户列表-->
          <!-- <div class="user-item" v-for="(user, index) in addUsers" :key="index">
            {{ user.userName + '(' + user.userAccount + ')' }}
            <a href="javascript:void(0);" rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  @click="deleteAddUser(index)" class="delete-icon">X</a>
          </div> -->
          <div class="infinite-list-wrapper" style="overflow:auto">
            <template>
              <p v-if="scrollUserLoading" class="load-user"><i class="el-icon-loading"></i></p>
              <ul class="infinite-list" v-infinite-scroll="scrollLoadUser" style="overflow:auto;height:300px">
                <li
                  v-for="i in scrollCount"
                  class="infinite-list-item"
                  :key="i"
                  infinite-scroll-disabled="userScrollDisabled"
                >
                  <div v-if="addUsers[i - 1]">
                    {{ addUsers[i - 1].userName + '(' + addUsers[i - 1].userAccount + ')' }}
                    <a href="javascript:void(0);" rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  @click="deleteAddUser(i - 1)" class="delete-icon">X</a>
                  </div>
                </li>
              </ul>
            </template>
          </div>
        </el-col>
      </el-row>
      <span slot="footer" class="dialog-footer">
        <el-button @click="cancel()">取 消</el-button>
        <el-button type="primary" @click="ok()">确 定</el-button>
      </span>
    </el-dialog>
  </div>
</template>
<script>
export default {
  props: {
    selectUserDialogVisible: {},
    //初始化的用户列表
    initUers: {},
    //缓存的角色列表,包含角色的半选状态
    cacheAllRoles: {},
    //缓存的区域列表
    cacheAllRegions: {},
    //缓存的区域复选框状态
    cacheRoleRegionIndeterminateMap: {}
  },
  data() {
    return {
      dialogVisible: false,
      userNameOrAccount: '',
      isNoDataShow: false,
      //右侧的用户列表
      addUsers: [],
      //用户列表复选框绑定值
      checkedUserAccounts: [],
      //左侧用户复选框列表
      queryUsers: [],
      //用户复选列表全选框状态
      userIsIndeterminate: true,
      userCheckAll: false,
      //角色列表
      allRoles: [],
      //角色列表复选框绑定值
      checkedRoleCodes: [],
      //角色复选列表全选框状态
      roleIsIndeterminate: false,
      roleCheckAll: false,
      //区域列表
      allRegions: [],
      allRegionCodes: [],
      //当前点击的角色
      currentClickRole: '',
      currentClickRoleCode: '',
      isRegionListShow: false,
      //区域复选列表全选框状态
      roleRegionAllIndeterminateMap: {},
      roleRegionAllCheckMap: {},
      //区域复选框绑定值,map:string->array,如{'管理员':['上海','北京']}
      checkedRoleRegionsMap: {},
      //区域复选框状态,map:string->map,如{'管理员':{{'上海':true},{'北京':false}}}
      roleRegionIndeterminateMap: {},
      //用户列表来自区域详情跳转标志
      isFromClickRegion: false,
      //滚动加载
      scrollCount: 0,
      scrollUserLoading: false
    };
  },
  created() {
    //获取所有角色
    this.findRoles().then(res => {
      //获取所有区域
      this.findRegions();
      //初始化数据和勾选状态
      this.init();
    });
  },
  computed: {
    scrollUserNoMore() {
      return this.scrollCount >= this.addUsers.length;
    },
    userScrollDisabled() {
      return this.scrollUserLoading || this.scrollUserNoMore;
    }
  },
  methods: {
    scrollLoadUser() {
      //一次加载20条
      let increaseCount = 20;
      let addAllCount = this.addUsers.length;
      if (this.scrollCount + increaseCount > addAllCount) {
        this.scrollCount = addAllCount;
      } else {
        this.scrollCount += increaseCount;
      }
      console.info('加载数据:' + this.scrollCount);
      this.scrollUserLoading = false;
    },
    init() {
      this.dialogVisible = this.selectUserDialogVisible;
      this.addUsers = this.addUsers.concat(this.initUers);
      this.handleCheckedValue();
      this.handleCheckedRoleChange(this.checkedRoleCodes);
      this.roleRegionIndeterminateMap = this.cacheRoleRegionIndeterminateMap || {};
    },
    //处理用户、角色、区域复选框绑定值和选择状态
    handleCheckedValue() {
      let checkedUserAccounts = [];
      let checkedRoleCodes = [];
      let checkedRoleRegionsMap = {};
      this.addUsers.forEach(user => {
        let userAccount = user.userAccount;
        let roleCode = user.roleCode;
        let regionName = user.regionName;
        checkedUserAccounts.push(userAccount);
        checkedRoleCodes.push(roleCode);
        if (!checkedRoleRegionsMap[roleCode]) {
          checkedRoleRegionsMap[roleCode] = [];
        } else if (checkedRoleRegionsMap[roleCode].indexOf(regionName) === -1) {
          checkedRoleRegionsMap[roleCode].push(regionName);
        }
      });
      //用户列表复选框勾选
      this.checkedUserAccounts = Array.from(new Set(checkedUserAccounts));
      //角色列表复选框勾选
      this.checkedRoleCodes = Array.from(new Set(checkedRoleCodes));
      //角色-区域列表复选框勾选
      this.checkedRoleRegionsMap = checkedRoleRegionsMap;
    },
    handleCheckedUser() {
      let checkedUserAccounts = this.addUsers.map(function(item) {
        return item.userAccount;
      });
      this.checkedUserAccounts = Array.from(new Set(checkedUserAccounts));
    },
    handleCheckedRoleCode() {
      let checkedRoleCodes = this.addUsers.map(function(item) {
        return item.roleCode;
      });
      this.checkedRoleCodes = Array.from(new Set(checkedRoleCodes));
    },
    //处理区域绑定值和勾选状态
    handleRegionCheckedAndStatus(deleteRegion) {
      //1、处理区域复选框绑定值与全选框状态
      //角色选中
      if (this.checkedRoleCodes.indexOf(this.currentClickRoleCode) > -1) {
        if (!this.currentClickRole.indeterminate) {
          //(1)全选状态
          this.checkedRoleRegionsMap[this.currentClickRoleCode] = this.allRegionCodes;
          this.roleRegionAllCheckMap[this.currentClickRoleCode] = true;
        } else {
          //(2)半选状态
          //获取选择的区域列表
          let checkedRegions = this.addUsers.map(user => {
            if (user.roleCode === this.currentClickRoleCode) {
              return user.regionName;
            }
          });
          if (checkedRegions.length === 0) {
            this.roleRegionAllCheckMap[this.currentClickRoleCode] = false;
            this.roleRegionAllIndeterminateMap[this.currentClickRoleCode] = false;
          } else {
            this.roleRegionAllIndeterminateMap[this.currentClickRoleCode] = true;
          }
          this.checkedRoleRegionsMap[this.currentClickRoleCode] = Array.from(new Set(checkedRegions));
        }
      } else {
        this.checkedRoleRegionsMap[this.currentClickRoleCode] = [];
        this.roleRegionAllCheckMap[this.currentClickRoleCode] = false;
        this.roleRegionAllIndeterminateMap[this.currentClickRoleCode] = false;
      }
      //(3)其他情况,赋空值,防止空指针
      if (!this.checkedRoleRegionsMap[this.currentClickRoleCode]) {
        this.checkedRoleRegionsMap[this.currentClickRoleCode] = new Array();
        this.roleRegionAllCheckMap[this.currentClickRoleCode] = false;
        this.roleRegionAllIndeterminateMap[this.currentClickRoleCode] = false;
      }
      //2、处理区域复选框状态
      let regionIndeterminateMap = {};
      this.allRegionCodes.forEach(regionCode => {
        //区域是选中状态且有删除用户操作,则状态置为半选
        if (this.checkedRoleRegionsMap[this.currentClickRoleCode].indexOf(regionCode) === -1) {
          //没有勾选,为false
          regionIndeterminateMap[regionCode] = false;
        } else if (deleteRegion && regionCode === deleteRegion) {
          //勾选且本次被删除了,为半选状态
          console.info('删除' + regionCode);
          regionIndeterminateMap[regionCode] = true;
        } else if (this.roleRegionIndeterminateMap && this.roleRegionIndeterminateMap[this.currentClickRoleCode]) {
          //使用原来的值
          regionIndeterminateMap[regionCode] = this.roleRegionIndeterminateMap[this.currentClickRoleCode][regionCode];
        } else {
          //其他情况
          regionIndeterminateMap[regionCode] = false;
        }
      });
      this.roleRegionIndeterminateMap[this.currentClickRoleCode] = regionIndeterminateMap;
    },
    //获取区域
    findRegions() {
      if (this.cacheAllRegions && this.cacheAllRegions.length > 0) {
        this.allRegions = this.cacheAllRegions;
        this.allRegionCodes = this.allRegions.map(function(item) {
          return item.value;
        });
        return;
      }
      //为空,第一次进入
      this.$api['region/getRegions']().then(data => {
        this.allRegions = data;
        this.allRegionCodes = this.allRegions.map(function(item) {
          return item.value;
        });
      });
    },
    //获取角色
    async findRoles() {
      if (this.cacheAllRoles && this.cacheAllRoles.length > 0) {
        this.allRoles = this.cacheAllRoles;
        return;
      }
      //为空,第一次进入,查询接口
      await this.$api['role/getRoles']().then(data => {
        data.forEach(item => {
          item.indeterminate = false;
        });
        this.allRoles = data;
      });
    },
    cancel() {
      this.dialogVisible = false;
      this.$emit('cancelSelectUser');
    },
    ok() {
      this.dialogVisible = false;
      //发送对象 = 初始化的用户+用户列表中选择的用户+角色列表选择的用户
      this.$emit('changeSelectUser', this.addUsers, this.allRoles, this.allRegions, this.roleRegionIndeterminateMap);
    },
    //角色全选/全部取消,全量
    handleCheckAllRole(val) {
      console.info('全选开始:' + new Date());
      if (val) {
        //全选
        this.scrollUserLoading = true;
        //1、处理角色多选
        this.checkedRoleCodes = this.allRoles.map(function(item) {
          return item.value;
        });
        this.getUsersByRoles(new Array()).then(users => {
          this.addUsers = users;
        });
        //2、处理用户多选
        this.handleCheckedUser();
        //3、处理区域多选、全选状态
        this.checkedRoleCodes.forEach(roleCode => {
          this.checkedRoleRegionsMap[roleCode] = this.allRegionCodes;
          this.roleRegionAllCheckMap[roleCode] = true;
          this.roleRegionAllIndeterminateMap[roleCode] = false;
        });
      } else {
        //取消全选
        //1、处理角色多选
        this.checkedRoleCodes = [];
        //2、处理用户多选
        this.addUsers = [];
        this.checkedUserAccounts = [];
        //3、处理区域多选、全选状态
        this.checkedRoleRegionsMap = {};
        this.roleRegionAllCheckMap = {};
        this.roleRegionAllIndeterminateMap = {};
      }
      //4、处理角色复选框状态
      this.allRoles.forEach(function(item) {
        item.indeterminate = false;
      });
      //5、处理角色全选框样式
      this.roleIsIndeterminate = false;
      console.info('全选结束:' + new Date());
    },
    //角色多选框勾选事件
    handleCheckRole(e, role) {
      // 因为原生click事件会执行两次,第一次在label标签上,第二次在input标签上,故此处理
      if (e.target.tagName === 'INPUT' || e.target.tagName === 'A') return;
      let roleCode = role.value;
      if (this.checkedRoleCodes.indexOf(roleCode) === -1) {
        //选中
        //1、处理用户多选
        this.getUsersByRoles(new Array(roleCode)).then(users => {
          let addUsers = this.addUsers.concat(users);
          this.addUsers = this.uniqueUser(addUsers);
        });
        this.handleCheckedUser();
        //2、处理区域多选
        this.checkedRoleRegionsMap[roleCode] = this.allRegionCodes;
        //3、处理角色-区域全选框状态
        this.roleRegionAllCheckMap[roleCode] = true;
        this.roleRegionAllIndeterminateMap[roleCode] = false;
      } else {
        //取消
        //1、处理用户多选
        this.addUsers = this.addUsers.filter(function(item) {
          return item.roleCode !== roleCode;
        });
        this.handleCheckedUser();
        //2、处理区域多选
        this.checkedRoleRegionsMap[roleCode] = [];
        //3、处理角色复选框状态
        role.indeterminate = false;
        //4、处理角色-区域全选框状态
        this.roleRegionAllCheckMap[roleCode] = false;
        this.roleRegionAllIndeterminateMap[roleCode] = true;
      }
    },
    //角色详情单击事件,取A标签的事件
    clickRoleToRegionDetail(e, role) {
      if (e.target.tagName !== 'A') return;
      let roleCode = role.value;
      this.currentClickRoleCode = roleCode;
      this.currentClickRole = role;
      //初始化区域勾选值与勾选状态
      this.handleRegionCheckedAndStatus();
      this.isRegionListShow = true;
    },
    //从区域列表返回到角色
    goBackToRole(e) {
      //this.currentClickRoleCode = '';
      this.isRegionListShow = false;
    },
    //区域全选/全部取消事件
    handleCheckAllRegion(val) {
      if (val) {
        //全选
        this.getUsersByRoles(new Array(this.currentClickRoleCode)).then(users => {
          //1、处理用户多选
          let addUsers = this.addUsers.concat(users);
          this.addUsers = this.uniqueUser(addUsers);
          this.handleCheckedUser();
          //2、处理角色多选
          this.handleCheckedRoleCode();
        });
        //3、处理区域全选
        this.checkedRoleRegionsMap[this.currentClickRoleCode] = this.allRegionCodes;
      } else {
        //取消全选
        //3、处理区域多选
        this.checkedRoleRegionsMap[this.currentClickRoleCode] = new Array();
        this.$forceUpdate();
        //1、处理用户多选
        let addUsers = this.addUsers.filter(user => {
          return user.roleCode !== this.currentClickRoleCode;
        });
        this.addUsers = addUsers;
        this.handleCheckedUser();
        //2、处理角色多选
        this.checkedRoleCodes = this.checkedRoleCodes.filter(roleCode => {
          return roleCode !== this.currentClickRoleCode;
        });
      }
      //4、处理角色全选框样式
      this.currentClickRole.indeterminate = false;
      this.roleIsIndeterminate = false;
    },
    //区域勾选事件
    handleCheckRegion(e, regionName) {
      // 原生click事件会执行两次,第一次在label标签上,第二次在input标签上
      if (e.target.tagName !== 'INPUT') return;
      let checkRegions = this.checkedRoleRegionsMap[this.currentClickRoleCode];
      if (checkRegions.indexOf(regionName) === -1) {
        //选中
        this.getUsersByRoles(new Array(this.currentClickRoleCode), regionName).then(users => {
          //1、处理用户多选
          let addUsers = this.addUsers.concat(users);
          this.addUsers = this.uniqueUser(addUsers);
          this.handleCheckedUser();
          //2、处理角色多选
          this.handleCheckedRoleCode();
        });
        //3、处理角色多选状态;处理区域全选状态
        if (checkRegions.length === this.allRegionCodes.length - 1) {
          //区域全部选中
          this.currentClickRole.indeterminate = false;
          this.roleRegionAllIndeterminateMap[this.currentClickRoleCode] = false;
        } else {
          this.currentClickRole.indeterminate = true;
          this.roleRegionAllIndeterminateMap[this.currentClickRoleCode] = true;
        }
      } else {
        //取消,强制改变值
        checkRegions = checkRegions.filter(item => {
          return item !== regionName;
        });
        this.checkedRoleRegionsMap[this.currentClickRoleCode] = checkRegions;
        //1、处理用户多选
        let addUsers = this.addUsers.filter(item => {
          return !(item.roleCode === this.currentClickRoleCode && item.regionName === regionName);
        });
        this.addUsers = addUsers;
        this.handleCheckedUser();
        //2、处理角色多选、多选状态;处理区域全选状态
        if (checkRegions.length === 0) {
          this.roleRegionAllIndeterminateMap[this.currentClickRoleCode] = false;
          this.checkedRoleCodes = this.checkedRoleCodes.filter(roleCode => {
            return roleCode !== this.currentClickRoleCode;
          });
        } else {
          this.currentClickRole.indeterminate = true;
          this.roleRegionAllIndeterminateMap[this.currentClickRoleCode] = true;
        }
      }
    },
    //区域详情单击事件
    clickRegionToUserDetail(e, regionName) {
      if (e.target.tagName !== 'A') return;
      //阻止选中
      e.preventDefault();
      this.isFromClickRegion = true;
      this.getUsersByRoles(new Array(this.currentClickRoleCode), regionName).then(users => {
        this.queryUsers = users;
      });
    },
    //角色选择改变
    handleCheckedRoleChange(roleCodes) {
      let checkedCount = roleCodes.length;
      let totalCount = this.allRoles.length;
      this.roleCheckAll = checkedCount === totalCount;
      this.roleIsIndeterminate = checkedCount > 0 && checkedCount < totalCount;
    },
    async getUsersByRoles(roleCodes, regionName) {
      let roleCodeStr = '';
      if (roleCodes && roleCodes.length > 0) {
        roleCodeStr = roleCodes.join(',');
      }
      let queryUsers = [];
      await this.$api['user/getUserByRoleAndRegion']({
        roleCodes: roleCodeStr,
        region: regionName
      }).then(data => {
        queryUsers = data;
      });
      return queryUsers;
    },
    //搜索用户
    searchUser() {
      if (this.userNameOrAccount) {
        this.$api['user/getByNameOrAccount']({
          nameOrAccount: this.userNameOrAccount
        }).then(data => {
          this.queryUsers = data;
          if (data.length === 0) {
            this.isNoDataShow = true;
          } else {
            this.isNoDataShow = false;
          }
        });
        this.isFromClickRegion = false;
      } else {
        this.isNoDataShow = false;
        this.queryUsers = [];
        this.isRegionListShow = false;
      }
    },
    //从用户列表返回到区域
    goBackToRegion(e) {
      this.queryUsers = [];
      this.isRegionListShow = true;
      this.handleRegionCheckedAndStatus();
    },
    //用户全选,这里选中的用户是整体用户的子集
    handleCheckAllUser(val) {
      let queryRoleCodes = this.queryUsers.map(user => {
        return user.roleCode;
      });
      if (val) {
        //全选
        //1、处理用户多选
        let addUsers = this.addUsers.concat(this.queryUsers);
        this.addUsers = this.uniqueUser(addUsers);
        this.handleCheckedUser();
        //2、处理角色多选框状态,新增的角色设为半选
        this.allRoles.forEach(role => {
          let roleCode = role.value;
          if (queryRoleCodes.indexOf(roleCode) >= 0 && this.checkedRoleCodes.indexOf(roleCode) === -1) {
            role.indeterminate = true;
          }
        });
        //3、处理角色多选
        this.handleCheckedRoleCode();
      } else {
        //全部取消
        //1、处理用户多选
        let queryUserAccounts = this.queryUsers.map(function(item) {
          return item.userAccount;
        });
        let addUsers = this.addUsers.filter(function(item) {
          return queryUserAccounts.every(function(item1) {
            return item.userAccount !== item1;
          });
        });
        this.addUsers = this.uniqueUser(addUsers);
        this.handleCheckedUser();
        //2、处理角色多选
        this.handleCheckedRoleCode();
        //3、处理角色多选框状态,取消的角色去除选择状态
        this.allRoles.forEach(role => {
          let roleCode = role.value;
          if (queryRoleCodes.indexOf(roleCode) >= 0 && this.checkedRoleCodes.indexOf(roleCode) >= 0) {
            role.indeterminate = true;
          } else {
            role.indeterminate = false;
          }
        });
      }
      //4、用户全选样式改变
      this.userIsIndeterminate = false;
      //5、点击后回到角色列表页
      if (!this.isFromClickRegion) {
        this.queryUsers = [];
        this.isRegionListShow = false;
      }
    },
    //用户复选框点击事件
    handleCheckUser(e, user) {
      // 原生click事件防止执行多次
      if (e.target.tagName !== 'SPAN') return;
      let userAccount = user.userAccount;
      let roleCode = user.roleCode;
      let regionName = user.regionName;
      if (this.checkedUserAccounts.indexOf(userAccount) === -1) {
        //选中
        //1、处理用户
        let addUser = this.queryUsers.find(item => {
          return item.userAccount === userAccount;
        });
        this.addUsers.push(addUser);
        this.addUsers = this.uniqueUser(this.addUsers);
        //2、处理角色多选、角色复选框选择状态
        this.handleCheckedRoleCode();
        this.handleCheckedRoleChange(this.checkedRoleCodes);
        //3、角色复选框选中状态改变
        this.roleCheckStatusChange(roleCode);
      } else {
        //取消
        //1、处理用户
        this.addUsers = this.addUsers.filter(function(item) {
          return item.userAccount !== userAccount;
        });
        //2、处理角色多选、角色复选框选择状态
        this.handleCheckedRoleCode();
        this.handleCheckedRoleChange(this.checkedRoleCodes);
        //3、角色复选框选中状态改变
        this.roleCheckStatusChange(roleCode);
        //4、处理区域复选框
        this.handleRegionCheckedAndStatus(regionName);
      }
      //点击后回到角色列表页
      if (!this.isFromClickRegion) {
        this.queryUsers = [];
        this.isRegionListShow = false;
      }
    },
    checkUserChange(checkedUserAccounts) {
      //右侧用户列表包含左侧复选框用户列表,userCheckAll为true,userIsIndeterminate为false
      let isUserCheckAll = true;
      let isUserCheck = false;
      //是否都选中了,有一个没选择则为false
      this.queryUsers.forEach(item => {
        if (this.checkedUserAccounts.indexOf(item.userAccount) < 0) {
          isUserCheckAll = false;
          return;
        }
      });
      //是否没选择的,有一个选择则为true
      this.queryUsers.forEach(item => {
        if (this.checkedUserAccounts.indexOf(item.userAccount) >= 0) {
          isUserCheck = true;
          return;
        }
      });
      this.userCheckAll = isUserCheckAll;
      if (isUserCheck && !isUserCheckAll) {
        //有勾选,全选才会存在半选状态
        this.userIsIndeterminate = true;
      } else {
        this.userIsIndeterminate = false;
      }
    },
    //用户、角色全选框选中状态改变
    userAndRoleAllCheckStatusChange() {
      this.checkUserChange(this.checkedUserAccounts);
      //角色复选框选中状态改变
      this.handleCheckedRoleChange(this.checkedRoleCodes);
    },
    //角色复选框选中状态改变
    roleCheckStatusChange(roleCode) {
      this.allRoles.forEach(item => {
        if (item.value === roleCode) {
          if (this.checkedRoleCodes.indexOf(roleCode) !== -1) {
            item.indeterminate = true;
          } else {
            item.indeterminate = false;
          }
        }
      });
    },
    //去重
    uniqueUser(arr) {
      var obj = {};
      arr = arr.reduce(function(item, next) {
        obj[next.userAccount] ? '' : (obj[next.userAccount] = true && item.push(next));
        return item;
      }, []);
      return arr;
    },
    //删除本次新增的用户
    deleteAddUser(index) {
      let deleteUser = this.addUsers[index];
      let deleteUserAccount = deleteUser.userAccount;
      let roleCode = deleteUser.roleCode;
      let regionName = deleteUser.regionName;
      //1、用户复选框绑定值同步删除
      this.checkedUserAccounts = this.checkedUserAccounts.filter(function(value) {
        return value !== deleteUserAccount;
      });
      //2、最后本次新增的用户删除
      this.addUsers.splice(index, 1);
      //3、角色复选框绑定值同步变化
      this.handleCheckedRoleCode();
      //4、用户全选状态改变
      this.userAndRoleAllCheckStatusChange();
      //5、角色选中状态改变,设置已选且有删除用户操作的角色indeterminate为true
      this.roleCheckStatusChange(roleCode);
      //6、区域选择情况
      this.handleRegionCheckedAndStatus(regionName);
    }
  },
  watch: {
    queryUsers: {
      handler: function(val) {
        if (val && val.length > 0) {
          this.handleCheckedValue();
          this.userAndRoleAllCheckStatusChange();
        }
      }
    },
    addUsers: {
      handler: function(val) {
        if (val && val.length > 0) {
          this.scrollLoadUser();
        }
      }
    }
  }
};
</script>
<style scoped lang="less">
.role-region-user {
  .goback-to-role {
    //margin-right: 10px;
  }
  .no-data {
    color: red;
  }
}
.user-row {
  .role-region-user-col {
    /deep/ .el-checkbox {
      color: #606266;
      font-weight: 500;
      font-size: 14px;
      cursor: pointer;
      user-select: none;
      margin-right: 30px;
      display: block;
    }
    .detail-btn {
      float: right;
      margin-left: 20px;
    }
  }
  .user-col {
    .user-item {
      margin-left: 10px;
    }
    .delete-icon {
      float: right;
      margin-right: 20px;
    }
    .load-user {
      text-align: center;
      /deep/ .el-icon-loading {
        font-size: 30px;
      }
    }
  }
  //滚动条
  .scoll-col {
    max-height: 300px;
    overflow-y: auto;
  }
}
</style>

从性能角度考虑,已知问题:

(1)左侧用户列表勾选操作,对应的角色不会由半选变为全选:如某角色先选中,再删除右侧某一人员,该角色变为半选状态,再通过左侧用户列表单独勾选或者全选的方式加上该用户,该角色的状态仍为半选;
(2)区域上方的全选框可以区分全选和半选,而每个区域的复选框不能严格区分半选和全选:
   如执行用户添加动作,对应的区域均为全选,执行用户删除操作时,所属区域状态变为半选,再次添加上删除的用户,区域仍为半选

到此这篇关于Vue3+ElementUI 多选框中复选框和名字点击方法效果分离的文章就介绍到这了,更多相关Vue3 ElementUI 多选框内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文