不定日拱卒:分享平常開發過程當中的一些小技巧,爲更多人提供相似問題的解決方案react
假設咱們的角色是經過 role 存放在 window 對象中的後端
在無權限控制需求時,咱們實現了一個表格頁面以下markdown
import React from 'react';
import { Button, Table as AntdTable } from 'antd';
// 模擬數據
const dataSource = new Array(8).fill(null).map((item, index) => ({
id: index,
columnA: `a${index}`,
columnB: `b${index}`,
}));
IProps {}
const Table: React.FC<IProps> = () => {
const columns = [
{
dataIndex: 'id',
},
{
dataIndex: 'columnA',
},
{
dataIndex: 'columnB',
},
{
dataIndex: 'actions',
render: () => (
<React.Fragment> <Button>act1</Button> <Button>act2</Button> </React.Fragment>
),
},
];
return <AntdTable dataSource={dataSource} columns={columns} />;
};
export default Table;
複製代碼
某一天,PM 小姐姐告訴咱們,這裏的數據太敏感了,須要作權限區分:只有角色爲 admin
的用戶才能看到 columnB
這一列。antd
咱們按着原來的代碼,啃哧啃哧幾下就搞定了,只修改了 columns 的實現oop
const columns = [
{
dataIndex: 'id',
},
{
dataIndex: 'columnA'
}
];
if (window.role === 'admin') {
columns.push({ dataIndex: 'columnB' });
}
columns.push({
dataIndex: 'actions',
render: () => (
<React.Fragment> <Button>act1</Button> <Button>act2</Button> </React.Fragment>
),
});
複製代碼
日子安穩了沒幾天,PM 小姐姐又找上門來了,說 columnA
columnB
的數據都有必定的敏感度,咱們的系統三個角色包括 admin
、user
和 super
,其中優化
admin
能夠看到全部列user
能夠看到 columnA
,不能看 columnB
super
能夠看到 columnB
,不能看 columnA
沒辦法,咱們只能再對上面的實現作些修改ui
const columns = [
{
dataIndex: 'id',
},
{
dataIndex: 'columnA'
}
];
if (window.role === 'user' || window.role === 'admin') {
columns.push({ dataIndex: 'columnA' });
}
if (window.role === 'super' || window.role === 'admin') {
columns.push({ dataIndex: 'columnB' });
}
columns.push({
dataIndex: 'actions',
render: () => (
<React.Fragment> <Button>act1</Button> <Button>act2</Button> </React.Fragment>
),
});
複製代碼
一頓操做下來,代碼已經變得十分難看,最重要的是很難維護了,若是之後又多了一些角色,新的需求必然致使代碼中充斥着難以理解的判斷邏輯,咱們必須找到合適的方案去處理掉這個問題spa
咱們不妨來思考一下剛剛的實現方案問題在哪裏code
咱們要找到一種方式,讓「權限控制」和「UI 實現」解耦orm
沒有什麼是分層解決不了的
咱們經過組件,把這個頁面分紅兩層,分別實現權限控制和 UI 邏輯
對於 UI 邏輯部分,咱們不須要關注權限,因此在這一層,咱們先默認用戶擁有全部權限,把全部 UI 邏輯部分都實現完整,再經過一個屬性,來最終過濾出須要展現的列
interface IProps {
displayColumns?: string[];
}
const Table: React.FC<IProps> = ({ displayColumns }) => {
// 定義全部的列
const columns = [
{
dataIndex: 'id',
},
{
dataIndex: 'columnA',
},
{
dataIndex: 'columnB',
},
{
dataIndex: 'actions',
render: () => (
<React.Fragment> <Button>act1</Button> <Button>act2</Button> </React.Fragment>
),
},
];
const finalColumns = displayColumns
? columns.filter(item => displayColumns.join(',').includes(item.dataIndex))
: columns;
return <AntdTable dataSource={dataSource} columns={finalColumns} />;
};
複製代碼
在權限控制部分,咱們根據角色判斷須要展現的列以後,經過 props 傳遞給 UI 層
import Table from './Table';
declare global {
interface Window {
role: any;
}
}
const getDisplayColumns = () => {
if (window.role === 'user') {
return ['id', 'columnA', 'actions'];
}
if (window.role === 'super') {
return ['id', 'columnB', 'actions'];
}
if (window.role === 'admin') {
return ['id', 'columnA', 'columnB', 'actions'];
}
return [];
};
const TablePage: React.FC = () => {
return (
<Table displayColumns={getDisplayColumns()} />
);
};
export default TablePage;
複製代碼
咱們再將上面的 getDisplayColumns 方法優化一下,畢竟過多的 if 條件會讓代碼顯得很 low
const roleColumnsMap: any = {
user: ['id', 'columnA', 'actions'],
super: ['id', 'columnB', 'actions'],
admin: ['id', 'columnA', 'columnB', 'actions'],
};
const getDisplayColumns = () => roleColumnsMap[window.role] || [];
複製代碼
分層,幫咱們實現了「關注點分離」,下降了修改的「心智負擔」
又過了幾天,PM 小姐姐提出了新的需求,此次不是數據權限的問題,是操做權限的問題,即
admin
能夠看到全部操做user
能夠看到 act1
,不能看 act2
super
能夠看到 act2
,不能看 act1
一樣的,咱們徹底能夠按照上面的思路來處理
import Table from './Table';
declare global {
interface Window {
role: any;
}
}
const roleColumnsMap: any = {
user: ['id', 'columnA', 'actions'],
super: ['id', 'columnB', 'actions'],
admin: ['id', 'columnA', 'columnB', 'actions'],
};
const roleActionsMap: any = {
user: ['act1'],
super: ['act2'],
admin: ['act1', 'act2'],
};
window.role = 'admin';
const getDisplayColumns = () => roleColumnsMap[window.role] || [];
const getDisplayActions = () => roleActionsMap[window.role] || [];
const TablePage: React.FC = () => {
return (
<Table displayColumns={getDisplayColumns()} displayActions={getDisplayActions()} />
);
};
export default TablePage;
複製代碼
import React from 'react';
import { Button, Table as AntdTable } from 'antd';
interface IProps {
displayColumns?: string[];
displayActions?: string[];
}
// 模擬數據
const dataSource = new Array(8).fill(null).map((item, index) => ({
id: index,
columnA: `a${index}`,
columnB: `b${index}`,
}));
const Table: React.FC<IProps> = ({ displayColumns, displayActions }) => {
// 定義全部的操做
const actions = [
{
key: 'act1',
rc: <Button>act1</Button>,
},
{
key: 'act2',
rc: <Button>act2</Button>,
},
];
const finalActions = displayActions
? actions.filter(item => displayActions.join(',').includes(item.key))
: actions;
// 定義全部的列
const columns = [
{
dataIndex: 'id',
},
{
dataIndex: 'columnA',
},
{
dataIndex: 'columnB',
},
{
dataIndex: 'actions',
render: () => finalActions.map(action => action.rc),
},
];
const finalColumns = displayColumns
? columns.filter(item => displayColumns.join(',').includes(item.dataIndex))
: columns;
return <AntdTable dataSource={dataSource} columns={finalColumns} />;
};
export default Table;
複製代碼
至此,任何的權限調整,都被限定在了與 UI 實現無關的地方。將來,若是服務端支持,還能夠將每一個角色所對應的權限經過 API 的方式獲取,從而加大靈活程度,能夠在不用改代碼的狀況下增長角色、調整權限。
有時候,咱們能夠適當轉變一下思路,採用一些「模式」來優雅地解決問題