表单实战之分类多选实现

技术栈 Vue3 + ElementUI + TypeScript

简介

开发后台管理系统的过程中,会出现一些管理员配置功能的部分,比如一些开放接口权限的开通。
分析一下,“开放接口权限的开通”,会有很多的权限可以开通,那就是多选。另外,开放接口肯定会进行分类,类别唯一。按类进行多选,再加上个全选的功能。
支持多选的同时还需要分类,会有点复杂,就需要设计好数据结构,内部有具体类别的标识与选中的数据存储。
至此,需求就分析完毕了。
接下来就是实现思路:

  1. 获取多选项与相应的分类,构造合适的数据结构
  2. 页面部分渲染分类的多选项数据
  3. 监听类别全选、选项勾选事件
  4. 点击确认时合并数据

实现

数据结构

选中的选项id

checkedForm: Array<Number>

可选项list

interface optionsObj {
	openApiId: Number,
	apiName: String,
	apiType: String
}
allApiList: Array<optionsObj>

分类list

interface typeItem {
	dictLabel: String,
	dictValue: String
}
typeList: Array<typeItem>

render分类list

构造分类list是最核心的点。

interface openApiType{
	text: String,  // 类别名称
   	value: String,  // 类别值
   	subApi: Array<optionsObj>,  // 该类的可选项
   	checkedApi: Array<Number>,  // 该类已选项
   	allCheck: Boolean,  // 该类全选状态
   	isIndeterminate: Boolean // 多选不确定状态
}
openApiTypeList: Array<openApiType>
// 

页面布局

 <el-tabs tab-position="left">
      <el-tab-pane v-for="typeItem in openApiTypeList" :key="typeItem.value" :label="typeItem.text">
        <el-checkbox
          :indeterminate="typeItem.isIndeterminate"
          v-model="typeItem.allCheck"
          @change="changeOpenApiAllCheck(typeItem)"
          >全选</el-checkbox
        >
        <el-checkbox-group v-model="typeItem.checkedApi" @change="handleCheckedApiChange(typeItem)">
          <el-checkbox
            v-for="(item, index) in typeItem.subApi"
            :label="item.openApiId"
            :key="index"
            >{{ item.apiName }}</el-checkbox
          >
        </el-checkbox-group>
      </el-tab-pane>
    </el-tabs>
    <br/>
    <el-button type="" @click="submitChange">确认</el-button>

逻辑

import { ref, reactive } from 'vue'

const checkedForm = ref()
let openApiTypeList = reactive()

/**
* 获取选项数据与选项类别
*/
const handleOptionsData = async () => {
  const checkedListRes = await getCheckedList() // 选中的选项id list
  const typeListRes = await getTypeList(); // 分类list
  const allApiListRes = await getAllApiList(); // 可选项list
  checkedForm.value = checkedListRes.data
  // 类别
  openApiTypeList = reactive(typeListRes.data.map((item) => {
    return {
      text: item.dictLabel, // 类别名称
      value: item.dictValue, // 类别值
      subApi: [], // 该类的可选项
      checkedApi: [], // 该类已选项
      allCheck: false, // 该类全选状态
      isIndeterminate: true // 多选不确定状态
    }
  }))
  if (allApiListRes.data.length) {
    allApiListRes.data.forEach((apiItem) => {
      openApiTypeList.forEach((typeItem) => {
        if (apiItem.apiType === Number(typeItem.value)) {
          // 类别字段一致
          typeItem.subApi.push(apiItem)
          if (checkedForm.value.includes(apiItem.openApiId))
            // 该类别的某个接口是否被选中
            typeItem.checkedApi.push(apiItem.openApiId)
        }
      })
    })
  }
},

/** 该类接口全选状态变更 */
const changeOpenApiAllCheck = (typeItem) => {
  typeItem.checkedApi = typeItem.allCheck ? typeItem.subApi.map((api) => api.openApiId) : []
  typeItem.isIndeterminate = false
}

/** 具体接口勾选状态更改 */
const handleCheckedApiChange = (typeItem) => {
  let checkedCount = typeItem.checkedApi.length
  typeItem.allCheck = checkedCount === typeItem.subApi.length
  typeItem.isIndeterminate = checkedCount > 0 && checkedCount < typeItem.subApi.length
}

/**
 * 提交修改
 */
const submitChange = () => {
  let combineApi = []
  // 合并
  openApiTypeList.forEach((apiType) => {
    combineApi = [...combineApi, ...apiType.checkedApi]
  })
  checkedForm.value = combineApi // 最终所有所选的id
  console.log(checkedForm.value)
}

应用

测试数据

// 选中的选项id list
const checkedListRes = { data: [11, 33, 77, 22, 99] } 

// 分类list
const typeListRes = {
  data: [
    { dictLabel: '分类1', dictValue: '1' },
    { dictLabel: '分类2', dictValue: '2' },
    { dictLabel: '分类3', dictValue: '3' },
    { dictLabel: '分类4', dictValue: '4' },
  ]
} 

// 可选项list
const allApiListRes = {
  data: [
    { openApiId: 11, apiName: '选项1', apiType: 1 },
    { openApiId: 22, apiName: '选项2', apiType: 1 },
    { openApiId: 33, apiName: '选项3', apiType: 2 },
    { openApiId: 44, apiName: '选项4', apiType: 3 },
    { openApiId: 55, apiName: '选项5', apiType: 1 },
    { openApiId: 66, apiName: '选项6', apiType: 1 },
    { openApiId: 77, apiName: '选项7', apiType: 3 },
    { openApiId: 88, apiName: '选项8', apiType: 3 },
    { openApiId: 99, apiName: '选项9', apiType: 1 },
    { openApiId: 100, apiName: '选项10', apiType: 2 },
    { openApiId: 101, apiName: '选项11', apiType: 4 },
  ]
} 

效果

  1. 初始页面效果 分类1
    初始页面效果 分类1
  2. 初始页面效果 分类3
    初始页面效果 分类3
  3. 分类1全选后,点击确认效果
    分类1全选后,点击确认效果
  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值