前置条件
- react,这里应用 umiJs 脚手架
- 应用 redux 数据流,这里应用 dvaJS 数据流
- 创立页面「TestPage」,作为例子页面
- 创立按钮组件「MyInput」,作为例子按钮
局部代码目录
Demo/
node_modules/
dist/
src/
components/
MyInput/
index.js // 公共组件,input
HOCAuth/
index.js // 外围权限校验组件
pages/
test/
index.js // 咱们的测试页面
model.js // test 页面的状态
home/
index.js // home 页面
model.js // home 页面的状态
models/
global.js // 最顶层的全局公共状态
services/ // api 等等
utils/
app.js // 入口函数
router.js // 路由配置
package.json
... 等等
思路
如何校验权限?
咱们将须要校验的(按钮或页面等)指标组件,通过一个公共组件包裹(即 hoc 组件),在这个 hoc 组件中判断指标组件的权限编码是否存在于权限表里,「若存在」则以后有权限拜访,渲染。「不存在」则返回 null
。
那么,咱们首先要贮存一份权限表,供所有组件应用。再为每个组件设置对于的权限编码。
这里咱们对页面的权限编码配置规定为 ‘ 数字 - 数字 ’,如:’1-2’、’1-3’ 等等。页面级组件应用 ’-‘ 连贯。
按钮级的权限编码为:’1-1_1’、’1-1_2’ 等等。按钮级组件应用 ’_’ 连贯。
如咱们以后 test
页面编码为 ‘1-1’,且该上面也有两个按钮级组件,那么该组件编码别离为 ‘1-1_1’、’1-1_2’。
例子:
const auth = {
'1-1': true,
'1-1_1': true
} // 权限表
const testPageAuthKey = '1-1' // test 页面的权限编码
const inputAuthKey = '1-1_1' // test 页面下的 input 组件权限编码
若 auth[authKey] === true 即有权限,渲染对应组件
接下来定义状态:
每个页面有独自的 model.js
(即 redux 中的 store),用于寄存该页面的状态。global.js
寄存我的项目最顶层的状态,为公共状态。
global
中贮存一份权限表 auth
,为所有按钮或页面的权限。渲染按钮或页背后,校验以后是否有权限,无权限则返回 null
。
例子
// global.js
const Model = {
namespace: 'Global',
state: {
auth: {
'1-1': true, // 示意领有 test 页面权限
'1-1_1': true, // 示意领有 test 页面下的 input 组件权限
} // 以后所有的权限
},
effects: {* fetchAuth({ payload, callback}, {call, put}) {
// 登录后调用 api 获取以后用户所领有的权限配置,更新掉 auth
const {auth} = yield call(apiFetchAuthFromServe, payload)
yield put({
type: 'save',
payload: {auth},
});
if (callback) callback();}
},
reducers: {save (state, { payload}) {
return {
...state,
...payload,
}
};
},
}
components/MyInput/index.js,input 组件
import React, {useRef, useMemo, memo} from 'react';
import HOCAuth from '../HOCAuth';
const Input = props => {
const {
onChange,
value,
defaultValue,
} = props;
const input = useRef(null);
const cur = useMemo(() => {if (value) return value;
if (defaultValue) return defaultValue;
}, [defaultValue, value]);
function onInputChange (e) {if (onChange) onChange(e.target.value);
}
return (<input type="text" ref={ input} defaultValue={cur} onChange={onInputChange}/>
);
};
export default memo(HOCAuth(Input)); // 这里应用 HOCAUth 包裹 Input
再看看应用:
// test/index.js test 页面
import React from 'react';
import {connect} from 'dva';
import HOCAuth from '@/components/HOCAuth'
import MyInput from '@/components/MyInput'
const Test = props => {console.log(props)
return (
<div>
<MyInput defaultValue={'default'} authKey={'1-1_1'} /> // 传递 authKey,示意该组件对应的权限编码
</div>
);
};
function mapStateToProps ({Global, Test}) {
return {
auth: Global.auth, // 订阅 global.js 中的 auth
authKey: Test.authKey, // 以后 test 页面的权限编码,从 model 中获取
Test, // test/model.js
};
}
export default connect(mapStateToProps)(HOCAuth(Test))
// 这是页面级的权限校验,应用 HOCAuth 包裹 Test
// test/model.js
const Model = {
namespace: 'Test',
state: {authKey: '1-1', // 以后 test 页面的权限编码},
... 略
}
接下来是咱们的外围组件 HOCAuth,components/HOCAuth/index.js
import React from 'react';
const HOCAuth = BaseComponent => (props) => {const { auth, authKey, ...others} = props;
if (!auth || !authKey) return null;
return (auth[authKey] ?
<BaseComponent {...others}/> : null // 过滤掉 auth 与 authKey
);
};
export default HOCAuth;
// 简略不?