React新闻发布系统 角色列表篇
好久没写了 项目写到一半才想起来写这个(汗)
一 基础页面搭建
角色列表页面的结构与之前编写的权限列表基本一致,仅在部分功能上有所差异。我们可以参考权限列表的实现方式快速搭建角色列表页面。
其中:
- dataSource 用于渲染角色数据
- rightList 存储权限数据
- 这两个数据都通过axios请求获取
import React from 'react'
import {Table ,Tree,Modal} from 'antd';
import { useState,useEffect} from 'react';
import axios from 'axios';
import {Button,Popconfirm,Popover} from 'antd';
import{ DeleteOutlined,UnorderedListOutlined
}from '@ant-design/icons'
export default function RoleList() {const [dataSource,setDataSource]=useState([]);const [rightList,setRightList]=useState([]);useEffect(()=>{const getDataSource=async()=>{const res=await axios.get('http://localhost:3000/roles')const right=await axios.get('http://localhost:3000/rights?_embed=children')setDataSource(res.data);setRightList(right.data)}getDataSource();},[])const columns=[{title:'ID',dataIndex:'id',key:'id'},{title:'角色名称',dataIndex:'roleName',key:'roleName'},{title:'操作',render:(item)=>{return<><Popconfirm title="确定删除吗?" okText="确定" cancelText="取消" onConfirm={()=>{confirmDelete(item)}}><Button icon={<DeleteOutlined/>} shape='circle' danger></Button></Popconfirm><Button icon={<UnorderedListOutlined />} shape='circle' color='blue' onClick={()=>showModal(item)}></Button></>}}]return (<div>{/*rowKey 如果数据中没有key这个属性,那就使用这个方法来赋值 表格行 key 的取值,可以是字符串或一个函数 */}<Table dataSource={dataSource} columns={columns} pagination={{pageSize:5}} rowKey={(item)=>item.id}/></div>)
}
然后就能得到一个和权限列表相似的界面了(不好看 但也不是很丑哈哈)
二 操作栏样式编写与函数方法实现
(1) antd组件认识
我们现在来关注一下操作栏 先来看看点击编辑的时候弹出的效果
点击编辑按钮会弹出树形权限结构图,通过勾选相应节点即可为角色分配权限。该功能实现主要依赖antd的Tree组件(树形控件)。编辑
除此之外还行要一个模态框 用来包裹住他
(2)代码编写
然后在代码中我们分别写好模态框与树形控件:
1.所需状态与函数方法定义
创建用于控制状态的定义和相关函数:
confirmDelete
:处理删除按钮点击后的确认操作,在弹窗中执行删除逻辑showModal
:控制树形控件模态框的显示/隐藏状态handleOk
:在树形控件中修改数据后点击确定按钮时触发,负责前后端数据交互onCheck
:处理树形控件节点勾选事件,checkKeys
返回被选权限组成的数组并保存该权限数据
const [isModalOpen, setIsModalOpen] = useState(false);const [currentRight,setCurrentRight]=useState({})const [currentID,setCurrentID]=useState(0)const confirmDelete=(item)=>{}const showModal = (item) => {};const handleOK=(currentID)=>{}const onCheck=(checkedKeys)=>{}
2.html部分写法
<div>{/*rowKey 如果数据中没有key这个属性,那就使用这个方法来赋值 表格行 key 的取值,可以是字符串或一个函数 */}<Table dataSource={dataSource} columns={columns} pagination={{pageSize:5}} rowKey={(item)=>item.id}/><ModalonOk={()=>handleOK(currentID)}onCancel={() => setIsModalOpen(false)}title="权限分配"open={isModalOpen}><Treecheckable// defaultCheckeys是一个非受控的组件 意思是这个组件只会显示默认选中的节点,不会受后续的修改 后续修改后也会不刷新组件//在antd中一般加上default属性都是非受控的checkedKeys={currentRight} //受控组件 但是表单里面的节点只能通过状态来控制onCheck={onCheck} //可以修改状态 来改变受控组件的结果treeData={rightList}// 可能是版本问题 如果不添加自定义属性 所有的数据都会被占位符代替 可能是因为我的数据和tree遍历的方法有冲突checkStrictly={true}// 不进行父子关联(父项勾选 子项全都被勾选) fieldNames={{title: 'label',key: 'key'}}/></Modal></div>
3.前后端交互函数的编写
item的解释
很多函数中都有item,这个item其实是渲染函数render的参数 我们点击那一项 item就是这一项的对象
render:(item)=>{return<><Popconfirm title="确定删除吗?" okText="确定" cancelText="取消" onConfirm={()=>{confirmDelete(item)}}><Button icon={<DeleteOutlined/>} shape='circle' danger></Button></Popconfirm><Button icon={<UnorderedListOutlined />} shape='circle' color='blue' onClick={()=>showModal(item)}></Button></>}
1.confirDelete函数
这个函数的作用是用来删除当前角色的 逻辑很简单 通过filter方法将当前所选的角色筛出渲染数据 ,然后通过axios向后端发送delete请求就可以
const confirmDelete=(item)=>{//前端删除逻辑setDataSource(dataSource.filter(data=>data.id!==item.id))//后端删除逻辑axios.delete(`http://localhost:3000/roles/${item.id}`).then((err)=>{if(err){console.log(err);}})}
2.showModal函数
作用是用来控制当前的模态框显示的 并在显示的时候将当前没有操作的数据保存起来 并且记录当前操作的角色id
const showModal = (item) => {setIsModalOpen(true);//将当前未操作的权限保存起来setCurrentRight(item.rights)//记录当前操作的角色idsetCurrentID(item.id)};
3.onCheck函数
是树形控件的自带的函数 用来记录当前操作完成后返回的权限数组
const onCheck=(checkedKeys)=>{//每次点击完一个节点之后 会返回一个新的节点数组console.log(checkedKeys);//将当前操作完的权限保存起来setCurrentRight(checkedKeys.checked)}
4.handleOk函数
该函数用于处理树形控件操作后的提交确认流程:首先关闭模态框,随后遍历项目列表,查找与先前保存的操作角色ID匹配的条目。找到对应角色后,通过展开运算符将其权限更新为操作后返回的权限数组(currentRight)。
const handleOK=(currentID)=>{setIsModalOpen(false)//同步datasourcesetDataSource(dataSource.map(item=>item.id===currentID?{...item,rights:currentRight}:item))//同步后端axios.patch(`http://localhost:3000/roles/${currentID}`,{rights:currentRight})}
三 完整代码展示:
import React from 'react'
import {Table ,Tree,Modal} from 'antd';
import { useState,useEffect} from 'react';
import axios from 'axios';
import {Button,Popconfirm,Popover} from 'antd';
import{ DeleteOutlined,UnorderedListOutlined
}from '@ant-design/icons'
export default function RoleList() {const [dataSource,setDataSource]=useState([]);const [rightList,setRightList]=useState([]);const [isModalOpen, setIsModalOpen] = useState(false);const [currentRight,setCurrentRight]=useState({})const [currentID,setCurrentID]=useState(0)useEffect(()=>{const getDataSource=async()=>{const res=await axios.get('http://localhost:3000/roles')const right=await axios.get('http://localhost:3000/rights?_embed=children')setDataSource(res.data);setRightList(right.data)}getDataSource();},[])const columns=[{title:'ID',dataIndex:'id',key:'id'},{title:'角色名称',dataIndex:'roleName',key:'roleName'},{title:'操作',render:(item)=>{return<><Popconfirm title="确定删除吗?" okText="确定" cancelText="取消" onConfirm={()=>{confirmDelete(item)}}><Button icon={<DeleteOutlined/>} shape='circle' danger></Button></Popconfirm><Button icon={<UnorderedListOutlined />} shape='circle' color='blue' onClick={()=>showModal(item)}></Button></>}}]const confirmDelete=(item)=>{//前端删除逻辑setDataSource(dataSource.filter(data=>data.id!==item.id))//后端删除逻辑axios.delete(`http://localhost:3000/roles/${item.id}`).then((err)=>{if(err){console.log(err);}})}const showModal = (item) => {setIsModalOpen(true);//将当前未操作的权限保存起来setCurrentRight(item.rights)//记录当前操作的角色idsetCurrentID(item.id)};const handleOK=(currentID)=>{setIsModalOpen(false)//同步datasourcesetDataSource(dataSource.map(item=>item.id===currentID?{...item,rights:currentRight}:item))//同步后端axios.patch(`http://localhost:3000/roles/${currentID}`,{rights:currentRight})}const onCheck=(checkedKeys)=>{//每次点击完一个节点之后 会返回一个新的节点数组console.log(checkedKeys);//将当前操作完的权限保存起来setCurrentRight(checkedKeys.checked)}return (<div>{/*rowKey 如果数据中没有key这个属性,那就使用这个方法来赋值 表格行 key 的取值,可以是字符串或一个函数 */}<Table dataSource={dataSource} columns={columns} pagination={{pageSize:5}} rowKey={(item)=>item.id}/><ModalonOk={()=>handleOK(currentID)}onCancel={() => setIsModalOpen(false)}title="权限分配"open={isModalOpen}><Treecheckable// defaultCheckeys是一个非受控的组件 意思是这个组件只会显示默认选中的节点,不会受后续的修改 后续修改后也会不刷新组件//在antd中一般加上default属性都是非受控的checkedKeys={currentRight} //受控组件 但是表单里面的节点只能通过状态来控制onCheck={onCheck} //可以修改状态 来改变受控组件的结果treeData={rightList}// 可能是版本问题 如果不添加自定义属性 所有的数据都会被占位符代替 可能是因为我的数据和tree遍历的方法有冲突checkStrictly={true}// 不进行父子关联(父项勾选 子项全都被勾选) fieldNames={{title: 'label',key: 'key'}}/></Modal></div>)
}