Button access control
There are nothing more than two interactive methods for button permission control: "invisible" and "visible .
Invisible
The invisible interaction is relatively simple, just control the display and hide of DOM
It Vue
in the following ways:
v-if
control whether it is displayedv-show
controls whether it is displayed, but it is not safe enough. After all,v-show
just changes the style todisplay: none
, which still exists in the real DOM rendering
It React
in the following ways:
- Condition judgment in
JSX
const Demo = () => {
return <div>
{boolean && <Button>submit</Button>}
</div>
}
- Use high-end components
HOC
to extract the judgment logic
const Demo = () => {
return <div>code...</div>
}
/** 高阶组件 */
const HOC = <T>(Com: Com: React.ComponentType<T>) => {
if (whiteList.includes(code)) return <Com {...this.props} />
return null;
}
Visible
There are many function points on the page. If some function points cannot be operated by the user without displaying DOM
, it may cause the page layout to be disordered or affect the appearance of the page. Some products expect the elements to be "visible but not clickable" when controlling the permission of function points.
can be implemented in Vue
in the following way:
- Custom instruction
Vue.directive
. UseaddEventListener
to add a capture event to the element. The capture event will be@click
stopImmediatePropagation
in the capture event method body to prevent event bubbling and other triggers of the same event, thus achieving the purpose of controlling the element to be unclickable
If multiple event listeners are attached to the same event type of the same element, when this event is triggered, they will be called in the order in which they were added. stopImmediatePropagation()
in one of the event listeners, none of the remaining event listeners will be called. 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);
}
});
The use of pointer-events
here is just an auxiliary function. It does not necessarily mean that the event listener on the element will never be triggered. If the descendant element has the specified pointer-events
and is allowed to be the event target, it can trigger the parent element event and rely solely on the CSS
attribute. Controlling not clicking is still risky, so here is only an auxiliary function.
CSS3
ofpointer-events
attribute specifies under what circumstances (if any) a particular graphic elements can be a mouse eventtarget
. For more usage reference: MSDN-pointer-events
can be implemented in React
in the following way:
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;
Used in page components:
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也不会重新渲染
If you don’t want to call the interface to get the black and white list every time you click the trigger, you can transfer the store
that stores the black and white list data to the high-end component
import React from 'react';
const Demo = () => {
return <>coding...</>
}
export default inject('xxxstore')(RbacHOC(inject('store')(observer(Demo))));
refer to
Based on the element button permission implementation scheme
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。