在项目中,权限管理中需要使用到多个checkbox,每一行都需要单独的实现全选功能,如果是单独的一行数据,相信大家都会,非常简单,但是这是在多行数据里面,实现起来就有点麻烦,话不多说,先看最终实现效果。
首先定义state
const state = reactive({
isShow: false, // dialog是否显示
systemrouter: [], // 系统所有路由
selectedrouter: [], // 选中的路由
routerSearch: '', // 搜索路由
checkAll: [], // 每一行是否全选
ID: '' // 角色ID
})
其中systemrouter返回的数组数据大致如此:
"data": [
{
"model": "user",
"methods": [
"post",
"delete",
"put",
"get"
],
"des": "管理用户"
},
{
"model": "catalog",
"methods": [
"post",
"delete",
"put",
"get"
],
"des": "文章目录"
}
]
而selectedrouter是最终提交给服务器的数据,数据所需要的数据格式大致如此,与systemrouter就是少了des属性:
"routerList":[
{
"model": "user",
"methods": [
"post",
"delete",
"put",
"get"
]
},
{
"model": "catalog",
"methods": [
"post",
"delete",
"put"
]
}]
}
之后看一下vue代码,vue代码相对比较简单,核心就在于功能这一列。
scope.$index可以获得当前的行号,然后使用el-checkbox-group组件,其中v-model指定selectedrouter[scope.$index].methods这一行,即可以绑定selectedrouter当前行的数据,子组件el-checkbox展示systemrouter当前行methods数组中所有属性。
而全选的checkbox,需要绑定自定义的一个数据checkAll的当前行。
<el-table :data="systemrouter.filter(data => !routerSearch
|| data.model.toLowerCase().includes(routerSearch.toLowerCase())
|| data.des.toLowerCase().includes(routerSearch.toLowerCase()))" lazy ref="refRouter" stripe border>
<el-table-column width="120" prop="model" label="模块">
<template v-slot="scope">
{{scope.row.model}}
</template>
</el-table-column>
<el-table-column prop="des" label="描述" width="100px">
</el-table-column>
<el-table-column align="right" label="功能">
<template #default="scope">
<el-checkbox-group class="group" @change="handleCheckedRouterChange(scope.$index)"
v-model="selectedrouter[scope.$index].methods">
<el-checkbox class="checkbox" :label="method" v-for="method in scope.row.methods"
:key="method+Math.random()">
{{getMethodsName(method)}}
</el-checkbox>
</el-checkbox-group>
<el-checkbox v-model="checkAll[scope.$index]"
@change="val=>handleCheckAllChange(val,scope.$index) ">全选
</el-checkbox>
</template>
</el-table-column>
</el-table>
当数据首次展示时候,首先服务器获得systemrouter数据,然后循环该数据,将model和methods属性push到selectedrouter中,其中methods初始为空。
之后再从服务器或许routerlist数据,即选中的数据,然后再次循环该数组,如果有methods数据,则重新赋值。
最后判断methds是否包括全部,如果是则对应的checkAll的该行数据赋值true,代码如下:
const show = (id) => {
state.isShow = true
state.ID = id
AJGetSystemRouter().then(res => {
state.systemrouter = res.data
// 循环所有系统router,赋值给selectedrouter并且默认methods为空
for (let route of state.systemrouter) {
state.selectedrouter.push({
model: route.model,
methods: []
})
// 默认全选是false
state.checkAll.push(false)
}
AJGetRoleByID(id).then((res) => {
const routerList = res.data.routerList
// 循环该角色拥有的router,使selectedrouter中有此model的记录,赋值methods
for (let i = 0; i < routerList.length; i++) {
state.selectedrouter.find(route => {
return route.model === routerList[i].model
}).methods = routerList[i].methods
// 如果routerList中的methods包括全部,则全选按钮为true
if (routerList[i].methods.length === state.systemrouter[i].methods
.length) {
state.checkAll[i] = true
}
}
})
})
}
以下是el-checkbox-group的change事件,传入当前行的index,判断全选按钮是否选中。
// 当改变某一行选择时,如果长度是最大值,则全选按钮为true,否则为false
const handleCheckedRouterChange = (index) => {
state.checkAll[index] = (state.systemrouter[index].methods.length === state.selectedrouter[
index].methods.length)
}
以下是权限el-checkbox的changge事件
// 点击全选按钮后,使得当前行的selectedrouter等于当前行的systemrouter的methods
const handleCheckAllChange = (val, index) => {
state.selectedrouter[index].methods = val ? state.systemrouter[index].methods : []
}
最后提交时,需要过滤一下selectedrouter数据,因为此数据中包含很多methods为空的行,但是服务器不允许这样的数据。
const handleDialogOK = () => {
// 过滤掉selectedrouter中methods为空的数据
const list = state.selectedrouter.filter(item => {
return item.methods.length != 0
})
// 使用list提交到服务器
}
至此功能全部实现。