react 按钮权限小demo

1,410 阅读2分钟

最近需求要给页面按钮加上权限

根据业务需求结合网上相关文章,有了以下权限代码。整体思路是,用户登录后,拿到当前用户的按钮权限集合。再根据按钮权限codeKey去判断

一、定义权限按钮包裹组件,withRouter为了方便使用router

定义AuthWrap组件,让其返回一个组件,像这种高阶组件是参数为组件,返回值为新组件的函数。高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。HOC 自身不是 React API 的一部分,它是一种基于 React 的组合特性而形成的设计模式。

/** 按钮权限设计 */

import React, { FC, ReactElement } from 'react';
import { withRouter, RouteComponentProps } from 'react-router-dom';
import { Tooltip } from 'antd';
import './index.less';
import { getLocalUserPermissionsButton } from '@/utils/userToken';

/** 按钮置灰样式
.ant-btn-disabled {
    color: rgba(0, 0, 0, 0.25) !important;
    border-color: #DFE1E6 !important;
    background: #f5f5f5 !important;
    text-shadow: none !important;
    box-shadow: none !important;
    pointer-events: none; // 注意此行 解决点击穿透
}
**/

// 非路由组件可以通过withRouter高阶组件访问 History 对象的属性和进行匹配。withRouter将在渲染时向包装组件传递更新的 match、location 和 history 属性。
type AuthProps = {
  authCode: string; // 权限codeKey
  isShowTooltip?: boolean; // 无权限时,是否展示提示,默认true
  children: any;
};
// 1.获取用户按钮权限集合,用户登录时,请求权限接口,拿到数据存入本地
const authBtnList = getLocalUserPermissionsButton();

// todo 渲染禁止按钮 无权限时,处理包裹的组件,移出click事件。为什么不加 disable属性?,会影响Tooltip的移入移出效果,配合css属性pointer-events: none;
const renderAuthBanButton: (children: any) => any = children => {
  return React.Children.map(children, child => {
    if (['boolean', 'undefined', 'string', 'number'].includes(typeof child) || child === null) {
      return child;
    }
    if (child.props.children) {
      return React.cloneElement(
        child,
        {
          onClick: e => {
            e.preventDefault();
            return false;
          },
          className: 'ant-btn-disabled'
        },
        renderAuthBanButton(child.props.children)
      );
    }
    return React.cloneElement(child, {
      onClick: e => {
        e.preventDefault();
        return false;
      },
      className: 'ant-btn-disabled'
    });
  });
};

const AuthWrap: FC<AuthProps & RouteComponentProps> = props => {
  const { authCode, isShowTooltip = true, children } = props;
  let hasAuth = false;
  if (authCode === undefined) {
    return children;
  } else {
    // todo 2.自定义按钮权限逻辑校验
    hasAuth = authBtnList.includes(authCode);
  }
  if (hasAuth) {
    return children;
  }
  // TODO 无权限时,处理包裹的组件,移出click事件。
  const authBanButton = renderAuthBanButton(children)
  return <>{isShowTooltip ? <Tooltip title="无操作权限">{authBanButton}</Tooltip> : null}</>;
};

export default withRouter(AuthWrap);

二、页面使用

import AuthWrap from '@/components/AuthWrap';

# 直接包裹 里面可以有多级
<AuthWrap authCode={'role_create2'}>
    <Button
      type="primary"
      className="action-btn-primary"
      onClick={() => {
        props.history.push(`/role/create`);
      }}>
      新建角色
    </Button>
</AuthWrap>

三、效果

Snipaste_2022-05-13_11-37-20.png

Hi ~ My code code code ...小记录