共计 2733 个字符,预计需要花费 7 分钟才能阅读完成。
按钮权限管制
按钮权限管制的交互方式无非两种:“ 不可见 ” 和 “ 可见不可点 ”。
不可见
不可见的交互方式绝对简略,管制 DOM
的显示暗藏即可。
在 Vue
中能够通过下述形式实现:
v-if
管制其是否显示v-show
管制其是否显示,但不够保险,毕竟v-show
只是把款式改成display: none
,在实在的 DOM 渲染还是存在
在 React
中能够通过下述形式实现:
JSX
中条件判断
const Demo = () => {
return <div>
{boolean && <Button>submit</Button>}
</div>
}
- 应用高阶组件
HOC
,抽离判断逻辑
const Demo = () => {return <div>code...</div>}
/** 高阶组件 */
const HOC = <T>(Com: Com: React.ComponentType<T>) => {if (whiteList.includes(code)) return <Com {...this.props} />
return null;
}
可见不可点
页面中有很多性能点,如果有些性能点用户不能操作而不显示DOM
,可能会导致页面布局错乱,或者影响页面的好看,有些产品在管制性能点权限期间望元素“可见不可点”。
在 Vue
中能够通过下述形式实现:
- 自定义指令
Vue.directive
。应用addEventListener
给元素减少一个捕捉事件,捕捉事件会优先于@click
触发,而后在捕捉事件办法体中应用stopImmediatePropagation
阻止事件冒泡和其它雷同事件的触发,因而达到管制元素不可点击的目标
如果多个事件监听器被附加到雷同元素的雷同事件类型上,当此事件触发时,它们会按其被增加的程序被调用。如果在其中一个事件监听器中执行
stopImmediatePropagation()
,那么剩下的事件监听器都不会被调用。MSDN – stopImmediatePropagation
// 注册自定义指令脚本
/** 权限拦挡 */
const interception = (event) => {event && event.stopImmediatePropagation();
}
/** 白名单 */
const whiteList = [];
/** 注册指令 */
Vue.directive('permission', {bind(el, binding) {
/** 不在白名单中 */
if (!whiteList.includes(binding.value)) {
el.style.pointerEvents = 'none';
el.setAttribute('disabled', 'disabled');
el.addEventListener('click', interception, true);
}
},
unbind(el) {el.removeEventListener('click', interception);
}
});
这里应用 pointer-events
只是一个辅助性能,并不一定意味着元素上的事件监听器永远不会触发,如果后辈元素有指定 pointer-events
并容许成为事件指标的话,是能够触发父元素事件,而且单纯依附 CSS
属性来管制不点击,还是有危险,因而这里仅作辅助作用。
CSS3
的pointer-events
属性指定在什么状况下 (如果有) 某个特定的图形元素能够成为鼠标事件的target
。更多用法参考:MSDN – pointer-events
在 React
中能够通过下述形式实现:
import {Button} from 'antd';
import axios from 'axios';
import React, {Component} from 'react';
/** 按钮权限管制高阶组件 */
const RbacHOC = (Com: any) => {
return class WrappedComponent extends Component {divRef = React.createRef<HTMLDivElement>();
componentDidMount() {this.fetchWilteList();
}
componentWillUnmount() {this.divRef.current?.removeEventListener('click', this.intercept);
}
/** 获取黑白名单 */
fetchWilteList = async () => {
try {const { code, data} = await axios.get(`${url}`).then((res: any) => res.data);
if (code === 200 && !data) {this.register();
}
} catch (error) {this.register();
}
};
/** 注册捕捉事件,拦挡事件 */
register = () => {this.divRef.current?.addEventListener('click', this.intercept, true);
};
/** 拦挡函数 */
intercept = (event: Event) => {event.stopImmediatePropagation();
message.info('你没有权限应用该性能!!!');
};
render() {const { props} = this;
return (<div style={{ display: 'inline-block'}} ref={this.divRef}>
<Com {...props} />
</div>
);
}
};
};
export default RbacHOC;
页面组件中应用:
import React from 'react';
const Demo = () => {return <>coding...</>}
export default RbacHOC(inject('store')(observer(Demo)));
// export default inject('store')(observer(RbacHOC(Demo));
// 不能这么写,因为 store 扭转后 WrappedComponent 组件不会从新渲染,继而传给 Demo 组件的 props 不变,Demo 也不会从新渲染
如果不想每次点击触发时都去调用接口拿黑白名单,能够将寄存黑白名单数据的 store
传到高阶组件中
import React from 'react';
const Demo = () => {return <>coding...</>}
export default inject('xxxstore')(RbacHOC(inject('store')(observer(Demo))));
参考
基于 Element 按钮权限实现计划
正文完