1

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 displayed
  • v-show controls whether it is displayed, but it is not safe enough. After all, v-show just changes the style to display: 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 . Use addEventListener 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 of pointer-events attribute specifies under what circumstances (if any) a particular graphic elements can be a mouse event target . 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


记得要微笑
1.9k 声望4.5k 粉丝

知不足而奋进,望远山而前行,卯足劲,不减热爱。